From a50cc794019378fbb75972959a6e74047157dcb8 Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 27 May 2021 23:15:27 +0200 Subject: [PATCH 001/103] step0 : start model/openoffice, logic/openoffice/style --- .../org/jabref/gui/openoffice/CitationEntryViewModel.java | 2 +- .../jabref/gui/openoffice/ManageCitationsDialogViewModel.java | 2 +- src/main/java/org/jabref/gui/openoffice/OOBibBase.java | 4 ++-- src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java | 4 ++-- .../java/org/jabref/gui/openoffice/StyleSelectDialogView.java | 4 ++-- .../org/jabref/gui/openoffice/StyleSelectDialogViewModel.java | 4 ++-- .../org/jabref/gui/openoffice/StyleSelectItemViewModel.java | 2 +- src/main/java/org/jabref/logic/layout/LayoutEntry.java | 2 +- .../org/jabref/logic/openoffice/UndefinedBibtexEntry.java | 1 + .../org/jabref/logic/openoffice/{ => style}/OOBibStyle.java | 2 +- .../jabref/logic/openoffice/{ => style}/OOPreFormatter.java | 2 +- .../org/jabref/logic/openoffice/{ => style}/StyleLoader.java | 3 ++- .../org/jabref/{logic => model}/openoffice/CitationEntry.java | 2 +- src/main/java/org/jabref/preferences/JabRefPreferences.java | 2 +- .../jabref/logic/openoffice/{ => style}/OOBibStyleTest.java | 2 +- .../logic/openoffice/{ => style}/OOPreFormatterTest.java | 2 +- .../jabref/logic/openoffice/{ => style}/StyleLoaderTest.java | 3 ++- .../jabref/{logic => model}/openoffice/CitationEntryTest.java | 2 +- .../org/jabref/logic/openoffice/{ => style}/test.jstyle | 0 .../openoffice/{ => style}/testWithDefaultAtFirstLIne.jstyle | 0 20 files changed, 24 insertions(+), 21 deletions(-) rename src/main/java/org/jabref/logic/openoffice/{ => style}/OOBibStyle.java (99%) rename src/main/java/org/jabref/logic/openoffice/{ => style}/OOPreFormatter.java (99%) rename src/main/java/org/jabref/logic/openoffice/{ => style}/StyleLoader.java (98%) rename src/main/java/org/jabref/{logic => model}/openoffice/CitationEntry.java (97%) rename src/test/java/org/jabref/logic/openoffice/{ => style}/OOBibStyleTest.java (99%) rename src/test/java/org/jabref/logic/openoffice/{ => style}/OOPreFormatterTest.java (98%) rename src/test/java/org/jabref/logic/openoffice/{ => style}/StyleLoaderTest.java (98%) rename src/test/java/org/jabref/{logic => model}/openoffice/CitationEntryTest.java (98%) rename src/test/resources/org/jabref/logic/openoffice/{ => style}/test.jstyle (100%) rename src/test/resources/org/jabref/logic/openoffice/{ => style}/testWithDefaultAtFirstLIne.jstyle (100%) diff --git a/src/main/java/org/jabref/gui/openoffice/CitationEntryViewModel.java b/src/main/java/org/jabref/gui/openoffice/CitationEntryViewModel.java index 028990a6bc8..c29f24c8424 100644 --- a/src/main/java/org/jabref/gui/openoffice/CitationEntryViewModel.java +++ b/src/main/java/org/jabref/gui/openoffice/CitationEntryViewModel.java @@ -3,7 +3,7 @@ import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; -import org.jabref.logic.openoffice.CitationEntry; +import org.jabref.model.openoffice.CitationEntry; public class CitationEntryViewModel { diff --git a/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java b/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java index 55d532caa62..40cee65036f 100644 --- a/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java +++ b/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java @@ -10,7 +10,7 @@ import org.jabref.gui.DialogService; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.openoffice.CitationEntry; +import org.jabref.model.openoffice.CitationEntry; import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase.java index 076c2ce2360..26bbde95eb3 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBase.java @@ -28,8 +28,8 @@ import org.jabref.logic.bibtex.comparator.FieldComparatorStack; import org.jabref.logic.l10n.Localization; import org.jabref.logic.layout.Layout; -import org.jabref.logic.openoffice.OOBibStyle; -import org.jabref.logic.openoffice.OOPreFormatter; +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.logic.openoffice.style.OOPreFormatter; import org.jabref.logic.openoffice.OOUtil; import org.jabref.logic.openoffice.UndefinedBibtexEntry; import org.jabref.logic.openoffice.UndefinedParagraphFormatException; diff --git a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java index 635d9469a31..481eadf867c 100644 --- a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java +++ b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java @@ -44,11 +44,11 @@ import org.jabref.logic.citationkeypattern.CitationKeyPatternPreferences; import org.jabref.logic.help.HelpFile; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.openoffice.OOBibStyle; import org.jabref.logic.openoffice.OpenOfficeFileSearch; import org.jabref.logic.openoffice.OpenOfficePreferences; -import org.jabref.logic.openoffice.StyleLoader; import org.jabref.logic.openoffice.UndefinedParagraphFormatException; +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.logic.openoffice.style.StyleLoader; import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; diff --git a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java index 60a5bb84de5..0465dfd0a41 100644 --- a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java +++ b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java @@ -20,8 +20,8 @@ import org.jabref.gui.util.ViewModelTableRowFactory; import org.jabref.logic.l10n.Localization; import org.jabref.logic.layout.TextBasedPreviewLayout; -import org.jabref.logic.openoffice.OOBibStyle; -import org.jabref.logic.openoffice.StyleLoader; +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.logic.openoffice.style.StyleLoader; import org.jabref.logic.util.TestEntry; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.types.StandardEntryType; diff --git a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogViewModel.java b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogViewModel.java index 80c7b97c8de..d2ae14549a6 100644 --- a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogViewModel.java +++ b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogViewModel.java @@ -22,9 +22,9 @@ import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.util.FileDialogConfiguration; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.openoffice.OOBibStyle; +import org.jabref.logic.openoffice.style.OOBibStyle; import org.jabref.logic.openoffice.OpenOfficePreferences; -import org.jabref.logic.openoffice.StyleLoader; +import org.jabref.logic.openoffice.style.StyleLoader; import org.jabref.logic.util.StandardFileType; import org.jabref.model.database.BibDatabaseContext; import org.jabref.preferences.PreferencesService; diff --git a/src/main/java/org/jabref/gui/openoffice/StyleSelectItemViewModel.java b/src/main/java/org/jabref/gui/openoffice/StyleSelectItemViewModel.java index 72890122d4f..af7390aeb65 100644 --- a/src/main/java/org/jabref/gui/openoffice/StyleSelectItemViewModel.java +++ b/src/main/java/org/jabref/gui/openoffice/StyleSelectItemViewModel.java @@ -9,7 +9,7 @@ import javafx.scene.Node; import org.jabref.gui.icon.IconTheme; -import org.jabref.logic.openoffice.OOBibStyle; +import org.jabref.logic.openoffice.style.OOBibStyle; public class StyleSelectItemViewModel { diff --git a/src/main/java/org/jabref/logic/layout/LayoutEntry.java b/src/main/java/org/jabref/logic/layout/LayoutEntry.java index cef0e5dcb0a..8b3c98edb8d 100644 --- a/src/main/java/org/jabref/logic/layout/LayoutEntry.java +++ b/src/main/java/org/jabref/logic/layout/LayoutEntry.java @@ -80,7 +80,7 @@ import org.jabref.logic.layout.format.WrapContent; import org.jabref.logic.layout.format.WrapFileLinks; import org.jabref.logic.layout.format.XMLChars; -import org.jabref.logic.openoffice.OOPreFormatter; +import org.jabref.logic.openoffice.style.OOPreFormatter; import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; diff --git a/src/main/java/org/jabref/logic/openoffice/UndefinedBibtexEntry.java b/src/main/java/org/jabref/logic/openoffice/UndefinedBibtexEntry.java index 6533d61326e..8a1a7cf5e8f 100644 --- a/src/main/java/org/jabref/logic/openoffice/UndefinedBibtexEntry.java +++ b/src/main/java/org/jabref/logic/openoffice/UndefinedBibtexEntry.java @@ -1,5 +1,6 @@ package org.jabref.logic.openoffice; +import org.jabref.logic.openoffice.style.OOBibStyle; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; diff --git a/src/main/java/org/jabref/logic/openoffice/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java similarity index 99% rename from src/main/java/org/jabref/logic/openoffice/OOBibStyle.java rename to src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index 63120d0776e..561099afe96 100644 --- a/src/main/java/org/jabref/logic/openoffice/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -1,4 +1,4 @@ -package org.jabref.logic.openoffice; +package org.jabref.logic.openoffice.style; import java.io.File; import java.io.FileInputStream; diff --git a/src/main/java/org/jabref/logic/openoffice/OOPreFormatter.java b/src/main/java/org/jabref/logic/openoffice/style/OOPreFormatter.java similarity index 99% rename from src/main/java/org/jabref/logic/openoffice/OOPreFormatter.java rename to src/main/java/org/jabref/logic/openoffice/style/OOPreFormatter.java index 131b8ea374a..dc02daf6ee9 100644 --- a/src/main/java/org/jabref/logic/openoffice/OOPreFormatter.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOPreFormatter.java @@ -1,4 +1,4 @@ -package org.jabref.logic.openoffice; +package org.jabref.logic.openoffice.style; import java.util.Map; import java.util.Objects; diff --git a/src/main/java/org/jabref/logic/openoffice/StyleLoader.java b/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java similarity index 98% rename from src/main/java/org/jabref/logic/openoffice/StyleLoader.java rename to src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java index 4d3b30537db..6d7651a24de 100644 --- a/src/main/java/org/jabref/logic/openoffice/StyleLoader.java +++ b/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java @@ -1,4 +1,4 @@ -package org.jabref.logic.openoffice; +package org.jabref.logic.openoffice.style; import java.io.File; import java.io.FileNotFoundException; @@ -10,6 +10,7 @@ import java.util.Objects; import org.jabref.logic.layout.LayoutFormatterPreferences; +import org.jabref.logic.openoffice.OpenOfficePreferences; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/jabref/logic/openoffice/CitationEntry.java b/src/main/java/org/jabref/model/openoffice/CitationEntry.java similarity index 97% rename from src/main/java/org/jabref/logic/openoffice/CitationEntry.java rename to src/main/java/org/jabref/model/openoffice/CitationEntry.java index 33f3c34662a..219e71eb0d1 100644 --- a/src/main/java/org/jabref/logic/openoffice/CitationEntry.java +++ b/src/main/java/org/jabref/model/openoffice/CitationEntry.java @@ -1,4 +1,4 @@ -package org.jabref.logic.openoffice; +package org.jabref.model.openoffice; import java.util.Objects; import java.util.Optional; diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java index 11bf4fa31b3..ba5df0fa216 100644 --- a/src/main/java/org/jabref/preferences/JabRefPreferences.java +++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java @@ -87,7 +87,7 @@ import org.jabref.logic.layout.format.NameFormatterPreferences; import org.jabref.logic.net.ProxyPreferences; import org.jabref.logic.openoffice.OpenOfficePreferences; -import org.jabref.logic.openoffice.StyleLoader; +import org.jabref.logic.openoffice.style.StyleLoader; import org.jabref.logic.preferences.DOIPreferences; import org.jabref.logic.preferences.OwnerPreferences; import org.jabref.logic.preferences.TimestampPreferences; diff --git a/src/test/java/org/jabref/logic/openoffice/OOBibStyleTest.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java similarity index 99% rename from src/test/java/org/jabref/logic/openoffice/OOBibStyleTest.java rename to src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java index 093a5eb6348..786e678324c 100644 --- a/src/test/java/org/jabref/logic/openoffice/OOBibStyleTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java @@ -1,4 +1,4 @@ -package org.jabref.logic.openoffice; +package org.jabref.logic.openoffice.style; import java.io.File; import java.io.IOException; diff --git a/src/test/java/org/jabref/logic/openoffice/OOPreFormatterTest.java b/src/test/java/org/jabref/logic/openoffice/style/OOPreFormatterTest.java similarity index 98% rename from src/test/java/org/jabref/logic/openoffice/OOPreFormatterTest.java rename to src/test/java/org/jabref/logic/openoffice/style/OOPreFormatterTest.java index 8b76fbeacd0..0478089a8dc 100644 --- a/src/test/java/org/jabref/logic/openoffice/OOPreFormatterTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOPreFormatterTest.java @@ -1,4 +1,4 @@ -package org.jabref.logic.openoffice; +package org.jabref.logic.openoffice.style; import org.junit.jupiter.api.Test; diff --git a/src/test/java/org/jabref/logic/openoffice/StyleLoaderTest.java b/src/test/java/org/jabref/logic/openoffice/style/StyleLoaderTest.java similarity index 98% rename from src/test/java/org/jabref/logic/openoffice/StyleLoaderTest.java rename to src/test/java/org/jabref/logic/openoffice/style/StyleLoaderTest.java index be5e3768a01..9b5a58f4de5 100644 --- a/src/test/java/org/jabref/logic/openoffice/StyleLoaderTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/StyleLoaderTest.java @@ -1,4 +1,4 @@ -package org.jabref.logic.openoffice; +package org.jabref.logic.openoffice.style; import java.net.URISyntaxException; import java.nio.charset.Charset; @@ -9,6 +9,7 @@ import java.util.List; import org.jabref.logic.layout.LayoutFormatterPreferences; +import org.jabref.logic.openoffice.OpenOfficePreferences; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/src/test/java/org/jabref/logic/openoffice/CitationEntryTest.java b/src/test/java/org/jabref/model/openoffice/CitationEntryTest.java similarity index 98% rename from src/test/java/org/jabref/logic/openoffice/CitationEntryTest.java rename to src/test/java/org/jabref/model/openoffice/CitationEntryTest.java index b1cd1d100a7..fd7ec48b9b3 100644 --- a/src/test/java/org/jabref/logic/openoffice/CitationEntryTest.java +++ b/src/test/java/org/jabref/model/openoffice/CitationEntryTest.java @@ -1,4 +1,4 @@ -package org.jabref.logic.openoffice; +package org.jabref.model.openoffice; import java.util.Optional; diff --git a/src/test/resources/org/jabref/logic/openoffice/test.jstyle b/src/test/resources/org/jabref/logic/openoffice/style/test.jstyle similarity index 100% rename from src/test/resources/org/jabref/logic/openoffice/test.jstyle rename to src/test/resources/org/jabref/logic/openoffice/style/test.jstyle diff --git a/src/test/resources/org/jabref/logic/openoffice/testWithDefaultAtFirstLIne.jstyle b/src/test/resources/org/jabref/logic/openoffice/style/testWithDefaultAtFirstLIne.jstyle similarity index 100% rename from src/test/resources/org/jabref/logic/openoffice/testWithDefaultAtFirstLIne.jstyle rename to src/test/resources/org/jabref/logic/openoffice/style/testWithDefaultAtFirstLIne.jstyle From d93bd56ef99c19da6fac760baeeeb6229046e110 Mon Sep 17 00:00:00 2001 From: Antal K Date: Fri, 28 May 2021 00:12:17 +0200 Subject: [PATCH 002/103] correction: import order --- src/main/java/org/jabref/gui/openoffice/OOBibBase.java | 4 ++-- .../org/jabref/gui/openoffice/StyleSelectDialogViewModel.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase.java index 26bbde95eb3..6a464507c09 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBase.java @@ -28,11 +28,11 @@ import org.jabref.logic.bibtex.comparator.FieldComparatorStack; import org.jabref.logic.l10n.Localization; import org.jabref.logic.layout.Layout; -import org.jabref.logic.openoffice.style.OOBibStyle; -import org.jabref.logic.openoffice.style.OOPreFormatter; import org.jabref.logic.openoffice.OOUtil; import org.jabref.logic.openoffice.UndefinedBibtexEntry; import org.jabref.logic.openoffice.UndefinedParagraphFormatException; +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.logic.openoffice.style.OOPreFormatter; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; diff --git a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogViewModel.java b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogViewModel.java index d2ae14549a6..abb37e87bd7 100644 --- a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogViewModel.java +++ b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogViewModel.java @@ -22,8 +22,8 @@ import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.util.FileDialogConfiguration; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.openoffice.style.OOBibStyle; import org.jabref.logic.openoffice.OpenOfficePreferences; +import org.jabref.logic.openoffice.style.OOBibStyle; import org.jabref.logic.openoffice.style.StyleLoader; import org.jabref.logic.util.StandardFileType; import org.jabref.model.database.BibDatabaseContext; From c9b72e998a8edd19e10f1060fa28d10beee4e78c Mon Sep 17 00:00:00 2001 From: Antal K Date: Fri, 28 May 2021 00:20:40 +0200 Subject: [PATCH 003/103] add general utilities --- .../model/openoffice/util/OOListUtil.java | 31 +++++ .../jabref/model/openoffice/util/OOPair.java | 11 ++ .../model/openoffice/util/OOResult.java | 128 ++++++++++++++++++ .../model/openoffice/util/OOVoidResult.java | 52 +++++++ 4 files changed, 222 insertions(+) create mode 100644 src/main/java/org/jabref/model/openoffice/util/OOListUtil.java create mode 100644 src/main/java/org/jabref/model/openoffice/util/OOPair.java create mode 100644 src/main/java/org/jabref/model/openoffice/util/OOResult.java create mode 100644 src/main/java/org/jabref/model/openoffice/util/OOVoidResult.java diff --git a/src/main/java/org/jabref/model/openoffice/util/OOListUtil.java b/src/main/java/org/jabref/model/openoffice/util/OOListUtil.java new file mode 100644 index 00000000000..1fe617ed99a --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/util/OOListUtil.java @@ -0,0 +1,31 @@ +package org.jabref.model.openoffice.util; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class OOListUtil { + + public static List map(List list, Function fun) { + return list.stream().map(e -> fun.apply(e)).collect(Collectors.toList()); + } + + /** Integers 0..(n-1) */ + public static List makeIndices(int n) { + return Stream.iterate(0, i -> i + 1).limit(n).collect(Collectors.toList()); + } + + /** Return indices so that list.get(indices.get(i)) is sorted. */ + public static List order(List list, Comparator comparator) { + List ii = makeIndices(list.size()); + Collections.sort(ii, new Comparator() { + @Override public int compare(final Integer o1, final Integer o2) { + return comparator.compare((U) list.get(o1), (U) list.get(o2)); + } + }); + return ii; + } +} diff --git a/src/main/java/org/jabref/model/openoffice/util/OOPair.java b/src/main/java/org/jabref/model/openoffice/util/OOPair.java new file mode 100644 index 00000000000..9d1596d19ef --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/util/OOPair.java @@ -0,0 +1,11 @@ +package org.jabref.model.openoffice.util; + +public class OOPair { + public final A a; + public final B b; + public OOPair(A a, B b) { + this.a = a; + this.b = b; + } +} + diff --git a/src/main/java/org/jabref/model/openoffice/util/OOResult.java b/src/main/java/org/jabref/model/openoffice/util/OOResult.java new file mode 100644 index 00000000000..1bc8cddcc13 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/util/OOResult.java @@ -0,0 +1,128 @@ +package org.jabref.model.openoffice.util; + +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; + +/* + * error cannot be null + * result cannot be null + * + * Void is not allowed for R, use OOVoidResult instead. + * + * Out of `isPresent()` and `isError()` exactly one is true. + */ +public class OOResult { + private final Optional result; + private final Optional error; + + /** + * Exactly one of the arguments should be Optional.empty() + * + * @param result + * @param error + */ + private OOResult(Optional result, Optional error) { + this.result = result; + this.error = error; + } + + /** + * @param result Null is not allowed. + */ + public static OOResult ok(R result) { + return new OOResult(Optional.of(result), Optional.empty()); + } + + /** + * @param error Null is not allowed. + */ + public static OOResult error(E error) { + return new OOResult(Optional.empty(), Optional.of(error)); + } + + /* + * Test state + */ + + public boolean isPresent() { + return result.isPresent(); + } + + public boolean isEmpty() { + return !isPresent(); + } + + public boolean isError() { + return error.isPresent(); + } + + public boolean isOK() { + return !isError(); + } + + /* + * getters + */ + + public R get() { + if (isError()) { + throw new RuntimeException("Cannot get from error"); + } + return result.get(); + } + + public E getError() { + return error.get(); + } + + /* + * Conditionals + */ + + public OOResult ifPresent(Consumer fun) { + if (isPresent()) { + fun.accept(get()); + } + return this; + } + + public OOResult ifError(Consumer fun) { + if (isError()) { + fun.accept(getError()); + } + return this; + } + + public OOResult map(Function fun) { + if (isError()) { + return error(getError()); + } else { + return ok(fun.apply(get())); + } + } + + public OOResult mapError(Function fun) { + if (isError()) { + return error(fun.apply(getError())); + } else { + return ok(get()); + } + } + + /** Throw away the error part. */ + public Optional getOptional() { + return result; + } + + /** Throw away the result part. */ + public OOVoidResult asVoidResult() { + if (isError()) { + return OOVoidResult.error(getError()); + } else { + return OOVoidResult.ok(); + } + } + +} + diff --git a/src/main/java/org/jabref/model/openoffice/util/OOVoidResult.java b/src/main/java/org/jabref/model/openoffice/util/OOVoidResult.java new file mode 100644 index 00000000000..a0bb0ebebe2 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/util/OOVoidResult.java @@ -0,0 +1,52 @@ +package org.jabref.model.openoffice.util; + +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; + +/* + * error cannot be null + */ +public class OOVoidResult { + private final Optional error; + + private OOVoidResult(Optional error) { + this.error = error; + } + + public static OOVoidResult ok() { + return new OOVoidResult(Optional.empty()); + } + + public static OOVoidResult error(E error) { + return new OOVoidResult(Optional.of(error)); + } + + public boolean isError() { + return error.isPresent(); + } + + public boolean isOK() { + return !isError(); + } + + public E getError() { + return error.get(); + } + + public OOVoidResult ifError(Consumer fun) { + if (isError()) { + fun.accept(getError()); + } + return this; + } + + public OOVoidResult mapError(Function fun) { + if (isError()) { + return error(fun.apply(getError())); + } else { + return ok(); + } + } +} + From 381a5493c8ed730bdf021a50a63b37b52b530f72 Mon Sep 17 00:00:00 2001 From: Antal K Date: Fri, 28 May 2021 00:42:03 +0200 Subject: [PATCH 004/103] add UNO utilities, move CreationException, NoDocumentException --- .../gui/openoffice/CreationException.java | 13 -- .../gui/openoffice/NoDocumentException.java | 13 -- .../org/jabref/gui/openoffice/OOBibBase.java | 2 + .../gui/openoffice/OpenOfficePanel.java | 2 + .../openoffice/uno/CreationException.java | 15 ++ .../openoffice/uno/NoDocumentException.java | 12 ++ .../model/openoffice/uno/UnoBookmark.java | 98 ++++++++++ .../jabref/model/openoffice/uno/UnoCast.java | 24 +++ .../model/openoffice/uno/UnoCrossRef.java | 75 ++++++++ .../model/openoffice/uno/UnoCursor.java | 45 +++++ .../model/openoffice/uno/UnoNameAccess.java | 27 +++ .../jabref/model/openoffice/uno/UnoNamed.java | 68 +++++++ .../model/openoffice/uno/UnoProperties.java | 95 ++++++++++ .../model/openoffice/uno/UnoRedlines.java | 54 ++++++ .../openoffice/uno/UnoReferenceMark.java | 133 ++++++++++++++ .../openoffice/uno/UnoScreenRefresh.java | 33 ++++ .../model/openoffice/uno/UnoSelection.java | 115 ++++++++++++ .../jabref/model/openoffice/uno/UnoStyle.java | 79 ++++++++ .../model/openoffice/uno/UnoTextDocument.java | 92 ++++++++++ .../model/openoffice/uno/UnoTextRange.java | 76 ++++++++ .../model/openoffice/uno/UnoTextSection.java | 90 +++++++++ .../jabref/model/openoffice/uno/UnoUndo.java | 45 +++++ .../uno/UnoUserDefinedProperty.java | 173 ++++++++++++++++++ 23 files changed, 1353 insertions(+), 26 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/openoffice/CreationException.java delete mode 100644 src/main/java/org/jabref/gui/openoffice/NoDocumentException.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/CreationException.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/NoDocumentException.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoBookmark.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoCast.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoCrossRef.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoNameAccess.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoNamed.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoRedlines.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoReferenceMark.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoScreenRefresh.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoSelection.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoTextDocument.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoTextSection.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java create mode 100644 src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java diff --git a/src/main/java/org/jabref/gui/openoffice/CreationException.java b/src/main/java/org/jabref/gui/openoffice/CreationException.java deleted file mode 100644 index 62c1fb0dafa..00000000000 --- a/src/main/java/org/jabref/gui/openoffice/CreationException.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.jabref.gui.openoffice; - -/** - * Exception used to indicate that the plugin attempted to set a character format that is - * not defined in the current OpenOffice document. - */ -class CreationException extends Exception { - - public CreationException(String message) { - super(message); - } - -} diff --git a/src/main/java/org/jabref/gui/openoffice/NoDocumentException.java b/src/main/java/org/jabref/gui/openoffice/NoDocumentException.java deleted file mode 100644 index 05d5f6d06ac..00000000000 --- a/src/main/java/org/jabref/gui/openoffice/NoDocumentException.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.jabref.gui.openoffice; - -/** - * Exception used to indicate that the plugin attempted to set a character format that is - * not defined in the current OpenOffice document. - */ -class NoDocumentException extends Exception { - - public NoDocumentException(String message) { - super(message); - } - -} diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase.java index 6a464507c09..540c5f9216b 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBase.java @@ -36,6 +36,8 @@ import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; import com.sun.star.awt.Point; import com.sun.star.beans.IllegalTypeException; diff --git a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java index 481eadf867c..367855a4b37 100644 --- a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java +++ b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java @@ -52,6 +52,8 @@ import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; import org.jabref.preferences.PreferencesService; import com.sun.star.beans.IllegalTypeException; diff --git a/src/main/java/org/jabref/model/openoffice/uno/CreationException.java b/src/main/java/org/jabref/model/openoffice/uno/CreationException.java new file mode 100644 index 00000000000..091d5469e2d --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/CreationException.java @@ -0,0 +1,15 @@ +package org.jabref.model.openoffice.uno; + +/** + * Exception used to indicate failure in either + * + * XMultiServiceFactory.createInstance() + * XMultiComponentFactory.createInstanceWithContext() + */ +public class CreationException extends Exception { + + public CreationException(String message) { + super(message); + } + +} diff --git a/src/main/java/org/jabref/model/openoffice/uno/NoDocumentException.java b/src/main/java/org/jabref/model/openoffice/uno/NoDocumentException.java new file mode 100644 index 00000000000..20783e3a580 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/NoDocumentException.java @@ -0,0 +1,12 @@ +package org.jabref.model.openoffice.uno; + +public class NoDocumentException extends Exception { + + public NoDocumentException(String message) { + super(message); + } + + public NoDocumentException() { + super("Not connected to a document"); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoBookmark.java b/src/main/java/org/jabref/model/openoffice/uno/UnoBookmark.java new file mode 100644 index 00000000000..b97618a3231 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoBookmark.java @@ -0,0 +1,98 @@ +package org.jabref.model.openoffice.uno; + +import java.util.Optional; + +import com.sun.star.container.NoSuchElementException; +import com.sun.star.container.XNameAccess; +import com.sun.star.container.XNamed; +import com.sun.star.lang.DisposedException; +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XBookmarksSupplier; +import com.sun.star.text.XTextContent; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; + +public class UnoBookmark { + + private UnoBookmark() { } + + /** + * Provides access to bookmarks by name. + */ + public static XNameAccess getNameAccess(XTextDocument doc) + throws + NoDocumentException { + + XBookmarksSupplier supplier = UnoCast.unoQI(XBookmarksSupplier.class, doc); + try { + return supplier.getBookmarks(); + } catch (DisposedException ex) { + throw new NoDocumentException("UnoBookmark.getNameAccess failed with" + ex); + } + } + + /** + * Get the XTextRange corresponding to the named bookmark. + * + * @param name The name of the bookmark to find. + * @return The XTextRange for the bookmark, or Optional.empty(). + */ + public static Optional getAnchor(XTextDocument doc, String name) + throws + WrappedTargetException, + NoDocumentException { + + XNameAccess nameAccess = getNameAccess(doc); + return (UnoNameAccess.getTextContentByName(nameAccess, name) + .map(e -> e.getAnchor())); + } + + /** + * Insert a bookmark with the given name at the cursor provided, + * or with another name if the one we asked for is already in use. + * + * 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) + throws + IllegalArgumentException, + CreationException { + return UnoNamed.insertNamedTextContent(doc, + "com.sun.star.text.Bookmark", + name, + range, + absorb); + } + + /** + * Remove the named bookmark if it exists. + */ + public static void remove(XTextDocument doc, String name) + throws + NoDocumentException, + NoSuchElementException, + WrappedTargetException { + + XNameAccess marks = UnoBookmark.getNameAccess(doc); + + if (marks.hasByName(name)) { + Optional mark = UnoNameAccess.getTextContentByName(marks, name); + if (mark.isEmpty()) { + return; + } + doc.getText().removeTextContent(mark.get()); + } + } +} diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoCast.java b/src/main/java/org/jabref/model/openoffice/uno/UnoCast.java new file mode 100644 index 00000000000..df5be51db36 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoCast.java @@ -0,0 +1,24 @@ +package org.jabref.model.openoffice.uno; + +import java.util.Optional; + +import com.sun.star.uno.UnoRuntime; + +public class UnoCast { + + private UnoCast() { } + + /** + * unoQI : short for UnoRuntime.queryInterface + * + * @return A reference to the requested UNO interface type if available, + * otherwise null + */ + public static T unoQI(Class zInterface, Object object) { + return UnoRuntime.queryInterface(zInterface, object); + } + + public static Optional optUnoQI(Class zInterface, Object object) { + return Optional.ofNullable(UnoRuntime.queryInterface(zInterface, object)); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoCrossRef.java b/src/main/java/org/jabref/model/openoffice/uno/UnoCrossRef.java new file mode 100644 index 00000000000..0e8b84e8d22 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoCrossRef.java @@ -0,0 +1,75 @@ +package org.jabref.model.openoffice.uno; + +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.beans.XPropertySet; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.text.ReferenceFieldPart; +import com.sun.star.text.ReferenceFieldSource; +import com.sun.star.text.XTextContent; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import com.sun.star.util.XRefreshable; + +public class UnoCrossRef { + + private UnoCrossRef() { } + + /** + * Update TextFields, etc. We use it to refresh cross-references in the document. + */ + public static void refresh(XTextDocument doc) { + // Refresh the document + XRefreshable xRefresh = UnoCast.unoQI(XRefreshable.class, doc); + xRefresh.refresh(); + } + + /** + * Insert a clickable cross-reference to a reference mark, + * with a label containing the target's page number. + * + * May need a documentConnection.refresh() after, to update + * the text shown. + */ + public static void insertReferenceToPageNumberOfReferenceMark(XTextDocument doc, + String referenceMarkName, + XTextRange cursor) + throws + CreationException, + UnknownPropertyException, + PropertyVetoException, + WrappedTargetException { + + // based on: https://wiki.openoffice.org/wiki/Documentation/DevGuide/Text/Reference_Marks + XMultiServiceFactory msf = UnoCast.unoQI(XMultiServiceFactory.class, doc); + // Create a 'GetReference' text field to refer to the reference mark we just inserted, + // and get it's XPropertySet interface + XPropertySet xFieldProps; + try { + String name = "com.sun.star.text.textfield.GetReference"; + xFieldProps = (XPropertySet) UnoCast.unoQI(XPropertySet.class, + msf.createInstance(name)); + } catch (Exception e) { + throw new CreationException(e.getMessage()); + } + + // Set the SourceName of the GetReference text field to the referenceMarkName + xFieldProps.setPropertyValue("SourceName", referenceMarkName); + + // specify that the source is a reference mark (could also be a footnote, + // bookmark or sequence field) + xFieldProps.setPropertyValue("ReferenceFieldSource", + new Short(ReferenceFieldSource.REFERENCE_MARK)); + + // We want the reference displayed as page number + xFieldProps.setPropertyValue("ReferenceFieldPart", + new Short(ReferenceFieldPart.PAGE)); + + // Get the XTextContent interface of the GetReference text field + XTextContent xRefContent = (XTextContent) UnoCast.unoQI(XTextContent.class, xFieldProps); + + // Insert the text field + cursor.getText().insertTextContent(cursor.getEnd(), xRefContent, false); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java b/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java new file mode 100644 index 00000000000..b7115feb8e1 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java @@ -0,0 +1,45 @@ +package org.jabref.model.openoffice.uno; + +import java.util.Optional; + +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.text.XTextViewCursor; +import com.sun.star.text.XTextViewCursorSupplier; + +public class UnoCursor { + + private UnoCursor() { } + + /** + * Get the cursor positioned by the user. + */ + public static Optional getViewCursor(XTextDocument doc) { + return (UnoTextDocument.getCurrentController(doc) + .flatMap(e -> UnoCast.optUnoQI(XTextViewCursorSupplier.class, e)) + .map(e -> e.getViewCursor())); + } + + /** + * Create a text cursor for a textContent. + * + * @return Optional.empty if mark is null, otherwise cursor. + * + */ + public static Optional getTextCursorOfTextContentAnchor(XTextContent mark) { + if (mark == null) { + return Optional.empty(); + } + XTextRange markAnchor = mark.getAnchor(); + if (markAnchor == null) { + return Optional.empty(); + } + return Optional.of(markAnchor.getText().createTextCursorByRange(markAnchor)); + } + + public static XTextCursor createTextCursorByRange(XTextRange r) { + return r.getText().createTextCursorByRange(r); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoNameAccess.java b/src/main/java/org/jabref/model/openoffice/uno/UnoNameAccess.java new file mode 100644 index 00000000000..3d172d11f14 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoNameAccess.java @@ -0,0 +1,27 @@ +package org.jabref.model.openoffice.uno; + +import java.util.Optional; + +import com.sun.star.container.NoSuchElementException; +import com.sun.star.container.XNameAccess; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextContent; + +public class UnoNameAccess { + + private UnoNameAccess() { } + + /** + * @return null if name not found, or if the result does not + * support the XTextContent interface. + */ + public static Optional getTextContentByName(XNameAccess nameAccess, String name) + throws + WrappedTargetException { + try { + return UnoCast.optUnoQI(XTextContent.class, nameAccess.getByName(name)); + } catch (NoSuchElementException ex) { + return Optional.empty(); + } + } +} diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoNamed.java b/src/main/java/org/jabref/model/openoffice/uno/UnoNamed.java new file mode 100644 index 00000000000..d99b6702153 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoNamed.java @@ -0,0 +1,68 @@ +package org.jabref.model.openoffice.uno; + +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 { + + private UnoNamed() { } + + /** + * Insert a new instance of a service at the provided cursor + * position. + * + * @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) + throws + CreationException { + + XMultiServiceFactory msf = UnoCast.unoQI(XMultiServiceFactory.class, doc); + + Object xObject; + try { + xObject = msf.createInstance(service); + } catch (Exception e) { + throw new CreationException(e.getMessage()); + } + + XNamed xNamed = UnoCast.unoQI(XNamed.class, xObject); + xNamed.setName(name); + + // get XTextContent interface + XTextContent xTextContent = UnoCast.unoQI(XTextContent.class, xObject); + range.getText().insertTextContent(range, xTextContent, absorb); + return xNamed; + } + +} diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java b/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java new file mode 100644 index 00000000000..07a6de1374d --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java @@ -0,0 +1,95 @@ +package org.jabref.model.openoffice.uno; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import com.sun.star.beans.Property; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.beans.XPropertyContainer; +import com.sun.star.beans.XPropertySet; +import com.sun.star.beans.XPropertySetInfo; +import com.sun.star.lang.WrappedTargetException; + +/** + * Utilities for properties. + */ +public class UnoProperties { + + private UnoProperties() { } + + /* + * asPropertySet + */ + + public static Optional asPropertySet(XPropertyContainer propertyContainer) { + return UnoCast.optUnoQI(XPropertySet.class, propertyContainer); + } + + /* + * getPropertySetInfo + */ + + public static Optional getPropertySetInfo(XPropertySet propertySet) { + return (Optional.ofNullable(propertySet) + .flatMap(e -> Optional.ofNullable(e.getPropertySetInfo()))); + } + + public static Optional getPropertySetInfo(XPropertyContainer propertyContainer) { + return Optional.ofNullable(propertyContainer).flatMap(UnoProperties::getPropertySetInfo); + } + + /* + * getPropertyNames + */ + + public static List getPropertyNames(Property[] properties) { + Objects.requireNonNull(properties); + return (Arrays.stream(properties) + .map(p -> p.Name) + .collect(Collectors.toList())); + } + + public static List getPropertyNames(XPropertySetInfo propertySetInfo) { + return getPropertyNames(propertySetInfo.getProperties()); + } + + public static List getPropertyNames(XPropertySet propertySet) { + return getPropertyNames(propertySet.getPropertySetInfo()); + } + + public static List getPropertyNames(XPropertyContainer propertyContainer) { + return (asPropertySet(propertyContainer) + .map(UnoProperties::getPropertyNames) + .orElse(new ArrayList<>())); + } + + /* + * getPropertyValue + */ + + public static Optional getValueAsObject(XPropertySet propertySet, String property) + throws + WrappedTargetException { + Objects.requireNonNull(propertySet); + Objects.requireNonNull(property); + try { + return Optional.ofNullable(propertySet.getPropertyValue(property)); + } catch (UnknownPropertyException e) { + return Optional.empty(); + } + } + + public static Optional getValueAsObject(XPropertyContainer propertyContainer, String property) + throws + WrappedTargetException { + Optional propertySet = asPropertySet(propertyContainer); + if (propertySet.isEmpty()) { + return Optional.empty(); + } + return UnoProperties.getValueAsObject(propertySet.get(), property); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoRedlines.java b/src/main/java/org/jabref/model/openoffice/uno/UnoRedlines.java new file mode 100644 index 00000000000..a5f5ce7c6d1 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoRedlines.java @@ -0,0 +1,54 @@ +package org.jabref.model.openoffice.uno; + +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.beans.XPropertySet; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.container.XEnumeration; +import com.sun.star.container.XEnumerationAccess; +import com.sun.star.document.XRedlinesSupplier; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextDocument; + +/** + * Change tracking and Redlines + */ +public class UnoRedlines { + + public static boolean getRecordChanges(XTextDocument doc) + throws + UnknownPropertyException, + WrappedTargetException { + + // https://wiki.openoffice.org/wiki/Documentation/DevGuide/Text/Settings + // "Properties of com.sun.star.text.TextDocument" + + XPropertySet propertySet = (UnoCast.optUnoQI(XPropertySet.class, doc) + .orElseThrow(RuntimeException::new)); + + return (boolean) propertySet.getPropertyValue("RecordChanges"); + } + + private static XRedlinesSupplier getRedlinesSupplier(XTextDocument doc) { + return UnoCast.unoQI(XRedlinesSupplier.class, doc); + } + + public static int countRedlines(XTextDocument doc) { + XRedlinesSupplier supplier = getRedlinesSupplier(doc); + XEnumerationAccess enumerationAccess = supplier.getRedlines(); + XEnumeration enumeration = enumerationAccess.createEnumeration(); + if (enumeration == null) { + return 0; + } else { + int count = 0; + while (enumeration.hasMoreElements()) { + try { + enumeration.nextElement(); + count++; + } catch (NoSuchElementException | WrappedTargetException ex) { + break; + } + } + return count; + } + } +} diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoReferenceMark.java b/src/main/java/org/jabref/model/openoffice/uno/UnoReferenceMark.java new file mode 100644 index 00000000000..8185c1ffbe3 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoReferenceMark.java @@ -0,0 +1,133 @@ +package org.jabref.model.openoffice.uno; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import com.sun.star.container.NoSuchElementException; +import com.sun.star.container.XNameAccess; +import com.sun.star.container.XNamed; +import com.sun.star.lang.DisposedException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XReferenceMarksSupplier; +import com.sun.star.text.XTextContent; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; + +public class UnoReferenceMark { + + private UnoReferenceMark() { } + + /** + * @throws NoDocumentException If cannot get reference marks + * + * Note: also used by `isDocumentConnectionMissing` to test if + * we have a working connection. + * + */ + public static XNameAccess getNameAccess(XTextDocument doc) + throws + NoDocumentException { + + XReferenceMarksSupplier supplier = UnoCast.unoQI(XReferenceMarksSupplier.class, doc); + + try { + return supplier.getReferenceMarks(); + } catch (DisposedException ex) { + throw new NoDocumentException("UnoReferenceMarks.getNameAccess failed with" + ex); + } + } + + /** + * Names of all reference marks. + * + * Empty list for nothing. + */ + public static List getListOfNames(XTextDocument doc) + throws NoDocumentException { + + XNameAccess nameAccess = UnoReferenceMark.getNameAccess(doc); + String[] names = nameAccess.getElementNames(); + if (names == null) { + return new ArrayList<>(); + } + return Arrays.asList(names); + } + + /** + * Remove the named reference mark. + * + * Removes both the text and the mark itself. + */ + public static void remove(XTextDocument doc, String name) + throws + WrappedTargetException, + NoDocumentException, + NoSuchElementException { + + XNameAccess xReferenceMarks = UnoReferenceMark.getNameAccess(doc); + + if (xReferenceMarks.hasByName(name)) { + Optional mark = UnoNameAccess.getTextContentByName(xReferenceMarks, name); + if (mark.isEmpty()) { + return; + } + doc.getText().removeTextContent(mark.get()); + } + } + + /** + * @return reference mark as XTextContent, Optional.empty if not found. + */ + public static Optional getAsTextContent(XTextDocument doc, String name) + throws + NoDocumentException, + WrappedTargetException { + + XNameAccess nameAccess = UnoReferenceMark.getNameAccess(doc); + return UnoNameAccess.getTextContentByName(nameAccess, name); + } + + /** + * XTextRange for the named reference mark, Optional.empty if not found. + */ + public static Optional getAnchor(XTextDocument doc, String name) + throws + NoDocumentException, + WrappedTargetException { + return (UnoReferenceMark.getAsTextContent(doc, name) + .map(e -> e.getAnchor())); + } + + /** + * 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. + * + * 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) + throws + CreationException { + return UnoNamed.insertNamedTextContent(doc, + "com.sun.star.text.ReferenceMark", + name, + range, + absorb); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoScreenRefresh.java b/src/main/java/org/jabref/model/openoffice/uno/UnoScreenRefresh.java new file mode 100644 index 00000000000..e5c27fcbb5c --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoScreenRefresh.java @@ -0,0 +1,33 @@ +package org.jabref.model.openoffice.uno; + +import com.sun.star.text.XTextDocument; + +/** + * Disable/enable screen refresh. + */ +public class UnoScreenRefresh { + + private UnoScreenRefresh() { } + + /** + * Disable screen refresh. + * + * Must be paired with unlockControllers() + * + * https://www.openoffice.org/api/docs/common/ref/com/sun/star/frame/XModel.html + * + * While there is at least one lock remaining, some + * notifications for display updates are not broadcasted. + */ + public static void lockControllers(XTextDocument doc) { + doc.lockControllers(); + } + + public static void unlockControllers(XTextDocument doc) { + doc.unlockControllers(); + } + + public static boolean hasControllersLocked(XTextDocument doc) { + return doc.hasControllersLocked(); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoSelection.java b/src/main/java/org/jabref/model/openoffice/uno/UnoSelection.java new file mode 100644 index 00000000000..0ef750b9983 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoSelection.java @@ -0,0 +1,115 @@ +package org.jabref.model.openoffice.uno; + +import java.util.Objects; +import java.util.Optional; + +import com.sun.star.frame.XController; +import com.sun.star.lang.XServiceInfo; +import com.sun.star.text.XTextDocument; +import com.sun.star.view.XSelectionSupplier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Selection in the document. + */ +public class UnoSelection { + + private static final Logger LOGGER = LoggerFactory.getLogger(UnoSelection.class); + + private UnoSelection() { } + + private static Optional getSelectionSupplier(XTextDocument doc) { + if (doc == null) { + LOGGER.warn("UnoSelection.getSelectionSupplier: doc is null"); + return Optional.empty(); + } + Optional controller = UnoTextDocument.getCurrentController(doc); + if (controller.isEmpty()) { + LOGGER.warn("UnoSelection.getSelectionSupplier: getCurrentController(doc) returned empty"); + return Optional.empty(); + } + XSelectionSupplier supplier = UnoCast.unoQI(XSelectionSupplier.class, controller.get()); + if (supplier == null) { + LOGGER.warn("UnoSelection.getSelectionSupplier: unoQI(XSelectionSupplier) returned null"); + return Optional.empty(); + } + return Optional.of(supplier); + } + + /** + * @return may be Optional.empty(), or some type supporting XServiceInfo + * + * + * So far it seems the first thing we have to do + * with a selection is to decide what do we have. + * + * One way to do that is accessing its XServiceInfo interface. + * + * Experiments using printServiceInfo with cursor in various + * positions in the document: + * + * With cursor within the frame, in text: + * *** xserviceinfo.getImplementationName: "SwXTextRanges" + * "com.sun.star.text.TextRanges" + * + * With cursor somewhere else in text: + * *** xserviceinfo.getImplementationName: "SwXTextRanges" + * "com.sun.star.text.TextRanges" + * + * With cursor in comment (also known as "annotation"): + * *** XSelectionSupplier is OK + * *** Object initialSelection is null + * *** xserviceinfo is null + * + * With frame selected: + * *** xserviceinfo.getImplementationName: "SwXTextFrame" + * "com.sun.star.text.BaseFrame" + * "com.sun.star.text.TextContent" + * "com.sun.star.document.LinkTarget" + * "com.sun.star.text.TextFrame" + * "com.sun.star.text.Text" + * + * With cursor selecting an inserted image: + * *** XSelectionSupplier is OK + * *** Object initialSelection is OK + * *** xserviceinfo is OK + * *** xserviceinfo.getImplementationName: "SwXTextGraphicObject" + * "com.sun.star.text.BaseFrame" + * "com.sun.star.text.TextContent" + * "com.sun.star.document.LinkTarget" + * "com.sun.star.text.TextGraphicObject" + */ + public static Optional getSelectionAsXServiceInfo(XTextDocument doc) { + Objects.requireNonNull(doc); + Optional supplier = getSelectionSupplier(doc); + if (supplier.isEmpty()) { + LOGGER.warn("getSelectionSupplier returned empty"); + return Optional.empty(); + } + Object selection = supplier.get().getSelection(); + if (selection == null) { + return Optional.empty(); + } + XServiceInfo result = UnoCast.unoQI(XServiceInfo.class, selection); + if (result == null) { + LOGGER.warn("unoQI(XServiceInfo) returned null"); + return Optional.empty(); + } + return Optional.of(result); + } + + /** + * Select the object represented by {@code newSelection} if it is + * known and selectable in this {@code XSelectionSupplier} object. + * + * Presumably result from {@code XSelectionSupplier.getSelection()} is + * usually OK. It also accepted + * {@code XTextRange newSelection = doc.getText().getStart();} + * + */ + public static void select(XTextDocument doc, Object newSelection) { + Objects.requireNonNull(doc); + getSelectionSupplier(doc).ifPresent(e -> e.select(newSelection)); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java b/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java new file mode 100644 index 00000000000..86222872597 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java @@ -0,0 +1,79 @@ +package org.jabref.model.openoffice.uno; + +import java.util.Optional; + +import com.sun.star.container.NoSuchElementException; +import com.sun.star.container.XNameAccess; +import com.sun.star.container.XNameContainer; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.style.XStyle; +import com.sun.star.style.XStyleFamiliesSupplier; +import com.sun.star.text.XTextDocument; + +/** + * Styles in the document. + */ +public class UnoStyle { + + public static final String CHARACTER_STYLES = "CharacterStyles"; + public static final String PARAGRAPH_STYLES = "ParagraphStyles"; + + private UnoStyle() { } + + private static Optional getStyleFromFamily(XTextDocument doc, + String familyName, + String styleName) + throws + WrappedTargetException { + + XStyleFamiliesSupplier fss = UnoCast.unoQI(XStyleFamiliesSupplier.class, doc); + XNameAccess fs = UnoCast.unoQI(XNameAccess.class, fss.getStyleFamilies()); + XNameContainer xFamily; + try { + xFamily = UnoCast.unoQI(XNameContainer.class, fs.getByName(familyName)); + } catch (NoSuchElementException ex) { + String msg = String.format("Style family name '%s' is not recognized", familyName); + throw new RuntimeException(msg, ex); + } + + try { + Object s = xFamily.getByName(styleName); + XStyle xs = (XStyle) UnoCast.unoQI(XStyle.class, s); + return Optional.ofNullable(xs); + } catch (NoSuchElementException ex) { + return Optional.empty(); + } + } + + public static Optional getParagraphStyle(XTextDocument doc, String styleName) + throws + WrappedTargetException { + return getStyleFromFamily(doc, PARAGRAPH_STYLES, styleName); + } + + public static Optional getCharacterStyle(XTextDocument doc, String styleName) + throws + WrappedTargetException { + return getStyleFromFamily(doc, CHARACTER_STYLES, styleName); + } + + public static Optional getInternalNameOfStyle(XTextDocument doc, String familyName, + String name) + throws + WrappedTargetException { + return (getStyleFromFamily(doc, familyName, name) + .map(e -> e.getName())); + } + + public static Optional getInternalNameOfParagraphStyle(XTextDocument doc, String name) + throws + WrappedTargetException { + return getInternalNameOfStyle(doc, PARAGRAPH_STYLES, name); + } + + public static Optional getInternalNameOfCharacterStyle(XTextDocument doc, String name) + throws + WrappedTargetException { + return getInternalNameOfStyle(doc, CHARACTER_STYLES, name); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoTextDocument.java b/src/main/java/org/jabref/model/openoffice/uno/UnoTextDocument.java new file mode 100644 index 00000000000..188a092465a --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoTextDocument.java @@ -0,0 +1,92 @@ +package org.jabref.model.openoffice.uno; + +import java.util.Optional; + +import com.sun.star.beans.XPropertySet; +import com.sun.star.document.XDocumentProperties; +import com.sun.star.document.XDocumentPropertiesSupplier; +import com.sun.star.frame.XController; +import com.sun.star.frame.XFrame; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextDocument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class UnoTextDocument { + + private static final Logger LOGGER = LoggerFactory.getLogger(UnoTextDocument.class); + + private UnoTextDocument() { } + + /** + * @return True if we cannot reach the current document. + */ + public static boolean isDocumentConnectionMissing(XTextDocument doc) { + + boolean missing = false; + if (doc == null) { + missing = true; + } + + // Attempt to check document is really available + if (!missing) { + try { + UnoReferenceMark.getNameAccess(doc); + } catch (NoDocumentException ex) { + missing = true; + } catch (com.sun.star.lang.DisposedException ex) { + missing = true; + } + } + return missing; + } + + public static Optional getCurrentController(XTextDocument doc) { + if (doc == null) { + return Optional.empty(); + } + XController controller = doc.getCurrentController(); + if (controller == null) { + LOGGER.warn("doc.getCurrentController() returned null"); + return Optional.empty(); + } + return Optional.of(controller); + } + + /** + * @param doc The XTextDocument we want the frame title for. Null allowed. + * @return The title or Optional.empty() + */ + public static Optional getFrameTitle(XTextDocument doc) { + + Optional frame = getCurrentController(doc).map(e -> e.getFrame()); + if (frame.isEmpty()) { + return Optional.empty(); + } + + Optional propertySet = UnoCast.optUnoQI(XPropertySet.class, frame.get()); + if (propertySet.isEmpty()) { + return Optional.empty(); + } + + try { + Optional frameTitleObj = + UnoProperties.getValueAsObject(propertySet.get(), "Title"); + if (frameTitleObj.isEmpty()) { + return Optional.empty(); + } + String frameTitleString = String.valueOf(frameTitleObj.get()); + return Optional.ofNullable(frameTitleString); + } catch (WrappedTargetException e) { + LOGGER.warn("Could not get document title", e); + return Optional.empty(); + } + } + + static Optional getDocumentProperties(XTextDocument doc) { + return (Optional.ofNullable(doc) + .map(e -> UnoCast.unoQI(XDocumentPropertiesSupplier.class, e)) + .map(e -> e.getDocumentProperties())); + } +} + diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java b/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java new file mode 100644 index 00000000000..1559c55d490 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java @@ -0,0 +1,76 @@ +package org.jabref.model.openoffice.uno; + +import java.util.Optional; + +import com.sun.star.text.XFootnote; +import com.sun.star.text.XTextRange; +import com.sun.star.text.XTextRangeCompare; + +public class UnoTextRange { + + private UnoTextRange() { } + + /** + * If original is in a footnote, return a range containing + * the corresponding footnote marker. + * + * Returns Optional.empty if not in a footnote. + */ + public static Optional getFootnoteMarkRange(XTextRange original) { + XFootnote footer = UnoCast.unoQI(XFootnote.class, original.getText()); + if (footer != null) { + // If we are inside a footnote, + // find the linking footnote marker: + // The footnote's anchor gives the correct position in the text: + return Optional.ofNullable(footer.getAnchor()); + } + return Optional.empty(); + } + + /** + * Test if two XTextRange values are comparable (i.e. they share + * the same getText()). + */ + public static boolean comparables(XTextRange a, XTextRange b) { + return a.getText() == b.getText(); + } + + /** + * @return follows java conventions + * + * 1 if (a > b); (-1) if (a < b) + */ + public static int compareStarts(XTextRange a, XTextRange b) { + if (!comparables(a, b)) { + throw new RuntimeException("compareStarts: got incomparable regions"); + } + final XTextRangeCompare compare = UnoCast.unoQI(XTextRangeCompare.class, a.getText()); + return (-1) * compare.compareRegionStarts(a, b); + } + + /** + * @return follows java conventions + * + * 1 if (a > b); (-1) if (a < b) + */ + public static int compareEnds(XTextRange a, XTextRange b) { + if (!comparables(a, b)) { + throw new RuntimeException("compareEnds: got incomparable regions"); + } + final XTextRangeCompare compare = UnoCast.unoQI(XTextRangeCompare.class, a.getText()); + return (-1) * compare.compareRegionEnds(a, b); + } + + public static int compareStartsThenEnds(XTextRange a, XTextRange b) { + if (!comparables(a, b)) { + throw new RuntimeException("compareStartsThenEnds: got incomparable regions"); + } + final XTextRangeCompare compare = UnoCast.unoQI(XTextRangeCompare.class, a.getText()); + int res = (-1) * compare.compareRegionStarts(a, b); + if (res != 0) { + return res; + } + return (-1) * compare.compareRegionEnds(a, b); + } + +} diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoTextSection.java b/src/main/java/org/jabref/model/openoffice/uno/UnoTextSection.java new file mode 100644 index 00000000000..107e7a0e018 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoTextSection.java @@ -0,0 +1,90 @@ +package org.jabref.model.openoffice.uno; + +import java.util.Optional; + +import com.sun.star.container.NoSuchElementException; +import com.sun.star.container.XNameAccess; +import com.sun.star.container.XNamed; +import com.sun.star.lang.DisposedException; +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import com.sun.star.text.XTextSection; +import com.sun.star.text.XTextSectionsSupplier; +import com.sun.star.uno.Any; + +public class UnoTextSection { + + /** + * @return An XNameAccess to find sections by name. + */ + public static XNameAccess getNameAccess(XTextDocument doc) + throws + NoDocumentException { + + XTextSectionsSupplier supplier = UnoCast.unoQI(XTextSectionsSupplier.class, doc); + try { + return supplier.getTextSections(); + } catch (DisposedException ex) { + throw new NoDocumentException("UnoTextSection.getNameAccess failed with" + ex); + } + } + + /** + * Get an XTextSection by name. + */ + public static Optional getByName(XTextDocument doc, String name) + throws + WrappedTargetException, + NoDocumentException { + XNameAccess nameAccess = getNameAccess(doc); + try { + return Optional.ofNullable((XTextSection) + ((Any) nameAccess.getByName(name)) + .getObject()); + } catch (NoSuchElementException ex) { + return Optional.empty(); + } + } + + /** + * Get the XTextRange covering to the named section. + * + * @param name The name of the section to find. + * @return The XTextRange for the section, or Optional.empty(). + */ + public static Optional getAnchor(XTextDocument doc, String name) + throws + WrappedTargetException, + NoDocumentException { + + XNameAccess nameAccess = getNameAccess(doc); + return (UnoNameAccess.getTextContentByName(nameAccess, name) + .map(e -> e.getAnchor())); + } + + /** + * 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. + */ + public static XNamed create(XTextDocument doc, String name, XTextRange range, boolean absorb) + throws + IllegalArgumentException, + CreationException { + + return UnoNamed.insertNamedTextContent(doc, + "com.sun.star.text.TextSection", + name, + range, + absorb); + } +} + diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java b/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java new file mode 100644 index 00000000000..7f41515dd1c --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java @@ -0,0 +1,45 @@ +package org.jabref.model.openoffice.uno; + +import java.util.Optional; + +import com.sun.star.document.XUndoManager; +import com.sun.star.document.XUndoManagerSupplier; +import com.sun.star.text.XTextDocument; +import com.sun.star.util.InvalidStateException; + +/** + * Undo : group document changes into larger Undo actions. + */ +public class UnoUndo { + + private UnoUndo() { } + + public static Optional getXUndoManager(XTextDocument doc) { + // https://www.openoffice.org/api/docs/common/ref/com/sun/star/document/XUndoManager.html + return (UnoCast.optUnoQI(XUndoManagerSupplier.class, doc) + .map(e -> e.getUndoManager())); + } + + /** + * Each call to enterUndoContext must be paired by a call to + * leaveUndoContext, otherwise, the document's undo stack is + * left in an inconsistent state. + */ + public static void enterUndoContext(XTextDocument doc, String title) { + Optional um = getXUndoManager(doc); + if (um.isPresent()) { + um.get().enterUndoContext(title); + } + } + + public static void leaveUndoContext(XTextDocument doc) { + Optional um = getXUndoManager(doc); + if (um.isPresent()) { + try { + um.get().leaveUndoContext(); + } catch (InvalidStateException ex) { + throw new RuntimeException("leaveUndoContext reported InvalidStateException"); + } + } + } +} diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java b/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java new file mode 100644 index 00000000000..dd09ae4745a --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java @@ -0,0 +1,173 @@ +package org.jabref.model.openoffice.uno; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.beans.XPropertyContainer; +import com.sun.star.beans.XPropertySet; +import com.sun.star.beans.XPropertySetInfo; +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextDocument; +import com.sun.star.uno.Any; +import com.sun.star.uno.Type; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Document level user-defined properties. + * + * LibreOffice GUI: [File]/[Properties]/[Custom Properties] + */ +public class UnoUserDefinedProperty { + + private static final Logger LOGGER = LoggerFactory.getLogger(UnoUserDefinedProperty.class); + + private UnoUserDefinedProperty() { } + + public static Optional getPropertyContainer(XTextDocument doc) { + return UnoTextDocument.getDocumentProperties(doc).map(e -> e.getUserDefinedProperties()); + } + + public static List getListOfNames(XTextDocument doc) { + return (UnoUserDefinedProperty.getPropertyContainer(doc) + .map(UnoProperties::getPropertyNames) + .orElse(new ArrayList<>())); + } + + /** + * @param property Name of a custom document property in the + * current document. + * + * @return The value of the property or Optional.empty() + * + * These properties are used to store extra data about + * individual citation. In particular, the `pageInfo` part. + * + */ + public static Optional getStringValue(XTextDocument doc, String property) + throws + WrappedTargetException { + Optional propertySet = (UnoUserDefinedProperty.getPropertyContainer(doc) + .flatMap(UnoProperties::asPropertySet)); + if (propertySet.isEmpty()) { + throw new RuntimeException("getting UserDefinedProperties as XPropertySet failed"); + } + try { + String v = propertySet.get().getPropertyValue(property).toString(); + return Optional.ofNullable(v); + } catch (UnknownPropertyException ex) { + return Optional.empty(); + } + } + + /** + * @param property Name of a custom document property in the + * current document. Created if does not exist yet. + * + * @param value The value to be stored. + */ + public static void createStringProperty(XTextDocument doc, String property, String value) + throws + NotRemoveableException, + PropertyExistException, + IllegalTypeException, + IllegalArgumentException, + PropertyVetoException, + WrappedTargetException { + + Objects.requireNonNull(property); + Objects.requireNonNull(value); + + Optional container = UnoUserDefinedProperty.getPropertyContainer(doc); + + if (container.isEmpty()) { + throw new RuntimeException("UnoUserDefinedProperty.getPropertyContainer failed"); + } + + Optional propertySet = container.flatMap(UnoProperties::asPropertySet); + if (propertySet.isEmpty()) { + throw new RuntimeException("asPropertySet failed"); + } + + XPropertySetInfo propertySetInfo = propertySet.get().getPropertySetInfo(); + + if (propertySetInfo.hasPropertyByName(property)) { + try { + propertySet.get().setPropertyValue(property, value); + return; + } catch (UnknownPropertyException ex) { + // fall through to addProperty + } + } + + container.get().addProperty(property, + com.sun.star.beans.PropertyAttribute.REMOVEABLE, + new Any(Type.STRING, value)); + } + + /** + * @param property Name of a custom document property in the + * current document. + * + * Logs warning if does not exist. + */ + public static void remove(XTextDocument doc, String property) + throws + NotRemoveableException, + PropertyExistException, + IllegalTypeException, + IllegalArgumentException { + + Objects.requireNonNull(property); + + Optional container = UnoUserDefinedProperty.getPropertyContainer(doc); + + if (container.isEmpty()) { + throw new RuntimeException("getUserDefinedPropertiesAsXPropertyContainer failed"); + } + + try { + container.get().removeProperty(property); + } catch (UnknownPropertyException ex) { + LOGGER.warn(String.format("UnoUserDefinedProperty.remove(%s)" + + " This property was not there to remove", + property)); + } + } + + /** + * @param property Name of a custom document property in the + * current document. + * + * Keep silent if property did not exist. + */ + public static void removeIfExists(XTextDocument doc, String property) + throws + NotRemoveableException, + PropertyExistException, + IllegalTypeException, + IllegalArgumentException { + + Objects.requireNonNull(property); + + Optional container = UnoUserDefinedProperty.getPropertyContainer(doc); + + if (container.isEmpty()) { + throw new RuntimeException("getUserDefinedPropertiesAsXPropertyContainer failed"); + } + + try { + container.get().removeProperty(property); + } catch (UnknownPropertyException ex) { + // did not exist + } + } +} From f94c1f6b2c8b9970ade3f2d75d064c6459fcb7a4 Mon Sep 17 00:00:00 2001 From: Antal K Date: Fri, 28 May 2021 11:15:34 +0200 Subject: [PATCH 005/103] Xlint:unchecked model/openoffice/util --- src/main/java/org/jabref/model/openoffice/util/OOResult.java | 4 ++-- .../java/org/jabref/model/openoffice/util/OOVoidResult.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/util/OOResult.java b/src/main/java/org/jabref/model/openoffice/util/OOResult.java index 1bc8cddcc13..2be478f6d8a 100644 --- a/src/main/java/org/jabref/model/openoffice/util/OOResult.java +++ b/src/main/java/org/jabref/model/openoffice/util/OOResult.java @@ -31,14 +31,14 @@ private OOResult(Optional result, Optional error) { * @param result Null is not allowed. */ public static OOResult ok(R result) { - return new OOResult(Optional.of(result), Optional.empty()); + return new OOResult<>(Optional.of(result), Optional.empty()); } /** * @param error Null is not allowed. */ public static OOResult error(E error) { - return new OOResult(Optional.empty(), Optional.of(error)); + return new OOResult<>(Optional.empty(), Optional.of(error)); } /* diff --git a/src/main/java/org/jabref/model/openoffice/util/OOVoidResult.java b/src/main/java/org/jabref/model/openoffice/util/OOVoidResult.java index a0bb0ebebe2..5de68f8697c 100644 --- a/src/main/java/org/jabref/model/openoffice/util/OOVoidResult.java +++ b/src/main/java/org/jabref/model/openoffice/util/OOVoidResult.java @@ -15,11 +15,11 @@ private OOVoidResult(Optional error) { } public static OOVoidResult ok() { - return new OOVoidResult(Optional.empty()); + return new OOVoidResult<>(Optional.empty()); } public static OOVoidResult error(E error) { - return new OOVoidResult(Optional.of(error)); + return new OOVoidResult<>(Optional.of(error)); } public boolean isError() { From f9a817603c7ac24eb0ad4f3b8ab624bd9f018d77 Mon Sep 17 00:00:00 2001 From: Antal K Date: Fri, 28 May 2021 09:38:30 +0200 Subject: [PATCH 006/103] add ootext --- .../model/openoffice/ootext/OOFormat.java | 73 ++ .../model/openoffice/ootext/OOText.java | 62 ++ .../model/openoffice/ootext/OOTextIntoOO.java | 817 ++++++++++++++++++ 3 files changed, 952 insertions(+) create mode 100644 src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java create mode 100644 src/main/java/org/jabref/model/openoffice/ootext/OOText.java create mode 100644 src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java new file mode 100644 index 00000000000..472ca519161 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java @@ -0,0 +1,73 @@ +package org.jabref.model.openoffice.ootext; + +public class OOFormat { + + /** + * Mark {@code s} as using a character locale known to OO. + * + * @param locale language[-country[-territory]] + * + * https://www.openoffice.org/api/docs/common/ref/com/sun/star/lang/Locale.html + * + * The country part is optional. + * + * The territory part is not only optional, the allowed "codes are + * vendor and browser-specific", so probably best to avoid them if possible. + * + */ + public static OOText setLocale(OOText s, String locale) { + return OOText.fromString(String.format("", locale) + s.asString() + ""); + } + + /** + * Mark {@code s} as using the character locale "zxx", which means + * "no language", "no linguistic content". + * + * Used around citation marks, probably to turn off spellchecking. + * + */ + public static OOText setLocaleNone(OOText s) { + return OOFormat.setLocale(s, "zxx"); + } + + /** + * Mark {@code s} using a character style {@code charStyle} + * + * @param charStyle Name of a character style known to OO. May be + * empty for "Standard", which in turn means do not override any properties. + * + */ + public static OOText setCharStyle(OOText s, String charStyle) { + return OOText.fromString(String.format("", charStyle) + + s.asString() + + ""); + } + + /** + * Mark {@code s} as part of a paragraph with style {@code paraStyle} + */ + public static OOText paragraph(OOText s, String paraStyle) { + if (paraStyle == null || "".equals(paraStyle)) { + return paragraph(s); + } + String startTag = String.format("

", paraStyle); + return OOText.fromString(startTag + s.asString() + "

"); + } + + /** + * Mark {@code s} as part of a paragraph. + */ + public static OOText paragraph(OOText s) { + return OOText.fromString("

" + s.asString() + "

"); + } + + /** + * Format an OO cross-reference showing the target's page number + * as label to a reference mark. + */ + public static OOText formatReferenceToPageNumberOfReferenceMark(String referencMarkName) { + String s = String.format("", + referencMarkName); + return OOText.fromString(s); + } + } diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOText.java b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java new file mode 100644 index 00000000000..a568a7c6e8a --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java @@ -0,0 +1,62 @@ +package org.jabref.model.openoffice.ootext; + +import java.util.Objects; + +/** + * Text with HTML-like markup as understood by OOTextIntoOO.write + * + * Some of the tags can be added using OOFormat methods. Others come + * from the layout engine, either by interpreting LaTeX markup or from + * settings in the jstyle file. + */ +public class OOText { + + private final String data; + + private OOText(String data) { + Objects.requireNonNull(data); + this.data = data; + } + + /* null input is passed through */ + public static OOText fromString(String s) { + if (s == null) { + return null; + } + return new OOText(s); + } + + /* null input is passed through */ + public static String toString(OOText s) { + if (s == null) { + return null; + } + return s.data; + } + + public String asString() { + return data; + } + + /* Object.equals */ + @Override + public boolean equals(Object o) { + + if (o == this) { + return true; + } + + if (!(o instanceof OOText)) { + return false; + } + + OOText c = (OOText) o; + + return data.equals(c.data); + } + + @Override + public int hashCode() { + return data.hashCode(); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java new file mode 100644 index 00000000000..f062bed7c40 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java @@ -0,0 +1,817 @@ +package org.jabref.model.openoffice.ootext; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.jabref.architecture.AllowedToUseAwt; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.UnoCast; +import org.jabref.model.openoffice.uno.UnoCrossRef; +import org.jabref.model.openoffice.util.OOPair; + +import com.sun.star.awt.FontSlant; +import com.sun.star.awt.FontStrikeout; +import com.sun.star.awt.FontUnderline; +import com.sun.star.awt.FontWeight; +import com.sun.star.beans.Property; +import com.sun.star.beans.PropertyAttribute; +import com.sun.star.beans.PropertyState; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.beans.XMultiPropertySet; +import com.sun.star.beans.XMultiPropertyStates; +import com.sun.star.beans.XPropertySet; +import com.sun.star.beans.XPropertySetInfo; +import com.sun.star.beans.XPropertyState; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.Locale; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.style.CaseMap; +import com.sun.star.text.ControlCharacter; +import com.sun.star.text.XParagraphCursor; +import com.sun.star.text.XText; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Interpret OOText into an OpenOffice or LibreOffice writer + * document. + */ +@AllowedToUseAwt("Requires AWT for changing document properties") +public class OOTextIntoOO { + + private static final Logger LOGGER = LoggerFactory.getLogger(OOTextIntoOO.class); + + /** + * "ParaStyleName" is an OpenOffice Property name. + */ + private static final String PARA_STYLE_NAME = "ParaStyleName"; + + /* + * Character property names used in multiple locations below. + */ + private static final String CHAR_ESCAPEMENT_HEIGHT = "CharEscapementHeight"; + private static final String CHAR_ESCAPEMENT = "CharEscapement"; + private static final String CHAR_STYLE_NAME = "CharStyleName"; + private static final String CHAR_UNDERLINE = "CharUnderline"; + private static final String CHAR_STRIKEOUT = "CharStrikeout"; + + /* + * SUPERSCRIPT_VALUE and SUPERSCRIPT_HEIGHT are percents of the normal character height + */ + private static final short CHAR_ESCAPEMENT_VALUE_DEFAULT = (short) 0; + private static final short SUPERSCRIPT_VALUE = (short) 33; + private static final short SUBSCRIPT_VALUE = (short) -10; + private static final byte CHAR_ESCAPEMENT_HEIGHT_DEFAULT = (byte) 100; + private static final byte SUPERSCRIPT_HEIGHT = (byte) 58; + private static final byte SUBSCRIPT_HEIGHT = (byte) 58; + + private static final String TAG_NAME_REGEXP = + "(?:b|i|em|tt|smallcaps|sup|sub|u|s|p|span|oo:referenceToPageNumberOfReferenceMark)"; + + private static final String ATTRIBUTE_NAME_REGEXP = + "(?:oo:ParaStyleName|oo:CharStyleName|lang|style|target)"; + + private static final String ATTRIBUTE_VALUE_REGEXP = "\"([^\"]*)\""; + + private static final Pattern HTML_TAG = + Pattern.compile("<(/" + TAG_NAME_REGEXP + ")>" + + "|" + + "<(" + TAG_NAME_REGEXP + ")" + + "((?:\\s+(" + ATTRIBUTE_NAME_REGEXP + ")=" + ATTRIBUTE_VALUE_REGEXP + ")*)" + + ">"); + + private static final Pattern ATTRIBUTE_PATTERN = + Pattern.compile("\\s+(" + ATTRIBUTE_NAME_REGEXP + ")=" + ATTRIBUTE_VALUE_REGEXP); + + private OOTextIntoOO() { + // Hide the public constructor + } + + /** + * Insert a text with formatting indicated by HTML-like tags, into + * a text at the position given by a cursor. + * + * Limitation: understands no entities. It does not receive any either, unless + * the user provides it. + * + * To limit the damage {@code TAG_NAME_REGEXP} and {@code ATTRIBUTE_NAME_REGEXP} + * explicitly lists the names we care about. + * + * Notable changes w.r.t insertOOFormattedTextAtCurrentLocation: + * + * - new tags: + * + * - <span lang="zxx"> + * - earlier was applied from code + * + * - <span oo:CharStyleName="CharStylename"> + * - earlier was applied from code, for "CitationCharacterFormat" + * + * - <p> start new paragraph + * - earlier was applied from code + * + * - <p oo:ParaStyleName="ParStyleName"> : start new paragraph and apply ParStyleName + * - earlier was applied from code + * + * - <tt> + * - earlier: known, but ignored + * - now: equivalent to <span oo:CharStyleName="Example"> + * - <oo:referenceToPageNumberOfReferenceMark> (self-closing) + * + * - closing tags try to properly restore state (in particular, the "not directly set" state) + * instead of dictating an "off" state. This makes a difference when the value inherited from + * another level (for example the paragraph) is not the "off" state. + * + * An example: a style with + * ReferenceParagraphFormat="JR_bibentry" + * Assume JR_bibentry in LibreOffice is a paragraph style that prescribes "bold" font. + * LAYOUT only prescribes bold around year. + * Which parts of the bibliography entries should come out as bold? + * + * - The user can format citation marks (it is enough to format their start) and the + * properties not (everywhere) dictated by the style are preserved (where they are not). + * + * @param position The cursor giving the insert location. Not modified. + * @param ootext The marked-up text to insert. + */ + public static void write(XTextDocument doc, XTextCursor position, OOText ootext) + throws + UnknownPropertyException, + PropertyVetoException, + WrappedTargetException, + IllegalArgumentException, + NoSuchElementException, + CreationException { + + final boolean debugThisFun = false; + + Objects.requireNonNull(doc); + Objects.requireNonNull(ootext); + Objects.requireNonNull(position); + + String lText = OOText.toString(ootext); + + if (debugThisFun) { + System.out.println(lText); + } + + XText text = position.getText(); + XTextCursor cursor = text.createTextCursorByRange(position); + cursor.collapseToEnd(); + + MyPropertyStack formatStack = new MyPropertyStack(cursor); + Stack expectEnd = new Stack<>(); + + // We need to extract formatting. Use a simple regexp search iteration: + int piv = 0; + Matcher m = HTML_TAG.matcher(lText); + while (m.find()) { + + String currentSubstring = lText.substring(piv, m.start()); + if (!currentSubstring.isEmpty()) { + cursor.setString(currentSubstring); + } + formatStack.apply(cursor); + cursor.collapseToEnd(); + + String fullTag = m.group(); + String endTagName = m.group(1); + String startTagName = m.group(2); + String attributeListPart = m.group(3); + boolean isStartTag = (endTagName == null) || "".equals(endTagName); + String tagName = isStartTag ? startTagName : endTagName; + Objects.requireNonNull(tagName); + + // Attibutes parsed into (name,value) pairs. + List> attributes = parseAttributes(attributeListPart); + + // Handle tags: + switch (tagName) { + case "b": + formatStack.pushLayer(setCharWeight(FontWeight.BOLD)); + expectEnd.push("/" + tagName); + break; + case "i": + case "em": + formatStack.pushLayer(setCharPosture(FontSlant.ITALIC)); + expectEnd.push("/" + tagName); + break; + case "smallcaps": + formatStack.pushLayer(setCharCaseMap(CaseMap.SMALLCAPS)); + expectEnd.push("/" + tagName); + break; + case "sup": + formatStack.pushLayer(setSuperScript(formatStack)); + expectEnd.push("/" + tagName); + break; + case "sub": + formatStack.pushLayer(setSubScript(formatStack)); + expectEnd.push("/" + tagName); + break; + case "u": + formatStack.pushLayer(setCharUnderline(FontUnderline.SINGLE)); + expectEnd.push("/" + tagName); + break; + case "s": + formatStack.pushLayer(setCharStrikeout(FontStrikeout.SINGLE)); + expectEnd.push("/" + tagName); + break; + case "/p": + // nop + break; + case "p": + insertParagraphBreak(text, cursor); + cursor.collapseToEnd(); + for (OOPair pair : attributes) { + String key = pair.a; + String value = pair.b; + switch (key) { + case "oo:ParaStyleName": + //

+ if (value != null && !value.equals("")) { + if (setParagraphStyle(cursor, value)) { + if (debugThisFun) { + // Presumably tested already: + LOGGER.warn(String.format("oo:ParaStyleName=\"%s\" failed", value)); + } + } + } else { + if (debugThisFun) { + LOGGER.warn(String.format("oo:ParaStyleName inherited")); + } + } + break; + default: + LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); + break; + } + } + break; + case "oo:referenceToPageNumberOfReferenceMark": + for (OOPair pair : attributes) { + String key = pair.a; + String value = pair.b; + switch (key) { + case "target": + UnoCrossRef.insertReferenceToPageNumberOfReferenceMark(doc, value, cursor); + break; + default: + LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); + break; + } + } + break; + case "tt": + // Note: "Example" names a character style in LibreOffice. + formatStack.pushLayer(setCharStyleName("Example")); + expectEnd.push("/" + tagName); + break; + case "span": + List> settings = new ArrayList<>(); + for (OOPair pair : attributes) { + String key = pair.a; + String value = pair.b; + switch (key) { + case "oo:CharStyleName": + // + settings.addAll(setCharStyleName(value)); + break; + case "lang": + // + // + settings.addAll(setCharLocale(value)); + break; + case "style": + // HTML-style small-caps + if (value.equals("font-variant: small-caps")) { + settings.addAll(setCharCaseMap(CaseMap.SMALLCAPS)); + break; + } + LOGGER.warn(String.format("Unexpected value %s for attribute '%s' for <%s>", + value, key, tagName)); + break; + default: + LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); + break; + } + } + formatStack.pushLayer(settings); + expectEnd.push("/" + tagName); + break; + case "/b": + case "/i": + case "/em": + case "/tt": + case "/smallcaps": + case "/sup": + case "/sub": + case "/u": + case "/s": + case "/span": + formatStack.popLayer(); + String expected = expectEnd.pop(); + if (!tagName.equals(expected)) { + LOGGER.warn(String.format("expected '<%s>', found '<%s>' after '%s'", + expected, + tagName, + currentSubstring)); + } + break; + } + + piv = m.end(); + } + + if (piv < lText.length()) { + cursor.setString(lText.substring(piv)); + } + formatStack.apply(cursor); + cursor.collapseToEnd(); + + if (!expectEnd.empty()) { + String rest = ""; + for (String s : expectEnd) { + rest = String.format("<%s>", s) + rest; + } + LOGGER.warn(String.format("OOTextIntoOO.write:" + + " expectEnd stack is not empty at the end: %s%n", + rest)); + } + } + + /** + * Purpose: in some cases we do not want to inherit direct + * formatting from the context. + * + * In particular, when filling the bibliography title and body. + */ + public static void removeDirectFormatting(XTextCursor cursor) { + + XMultiPropertyStates mpss = UnoCast.unoQI(XMultiPropertyStates.class, cursor); + + XPropertySet propertySet = UnoCast.unoQI(XPropertySet.class, cursor); + XPropertyState xPropertyState = UnoCast.unoQI(XPropertyState.class, cursor); + + try { + // Special handling + propertySet.setPropertyValue(CHAR_STYLE_NAME, "Standard"); + xPropertyState.setPropertyToDefault("CharCaseMap"); + } catch (UnknownPropertyException | + PropertyVetoException | + IllegalArgumentException | + WrappedTargetException ex) { + LOGGER.warn("exception caught", ex); + } + + mpss.setAllPropertiesToDefault(); + + /* + * Now that we have called setAllPropertiesToDefault, check which properties + * are not set to default and try to correct what we can and seem necessary. + * + * Note: tested with LibreOffice : 6.4.6.2 + */ + + // Only report those we do not yet know about + final Set knownToFail = Set.of("ListAutoFormat", + "ListId", + "NumberingIsNumber", + "NumberingLevel", + "NumberingRules", + "NumberingStartValue", + "ParaChapterNumberingLevel", + "ParaIsNumberingRestart", + "ParaStyleName"); + + // query again, just in case it matters + propertySet = UnoCast.unoQI(XPropertySet.class, cursor); + XPropertySetInfo propertySetInfo = propertySet.getPropertySetInfo(); + + // check the result + for (Property p : propertySetInfo.getProperties()) { + if ((p.Attributes & PropertyAttribute.READONLY) != 0) { + continue; + } + try { + if (isPropertyDefault(cursor, p.Name)) { + continue; + } + } catch (UnknownPropertyException ex) { + throw new RuntimeException("Unexpected UnknownPropertyException"); + } + if (knownToFail.contains(p.Name)) { + continue; + } + LOGGER.warn(String.format("OOTextIntoOO.removeDirectFormatting failed on '%s'", p.Name)); + } + } + + static class MyPropertyStack { + + /* + * We only try to control these. Should include all character + * properties we set, and maybe their interdependencies. + * + * For a list of properties see: + * https://www.openoffice.org/api/docs/common/ref/com/sun/star/style/CharacterProperties.html + * + * For interdependencies between properties: + * https://wiki.openoffice.org/wiki/Documentation/DevGuide/Text/Formatting + * (at the end, under "Interdependencies between Properties") + * + */ + static final Set CONTROLLED_PROPERTIES = Set.of( + + /* Used for SuperScript, SubScript. + * + * These three are interdependent: changing one may change others. + */ + "CharEscapement", "CharEscapementHeight", "CharAutoEscapement", + + /* used for Bold */ + "CharWeight", + + /* Used for Italic */ + "CharPosture", + + /* Used for strikeout. These two are interdependent. */ + "CharStrikeout", "CharCrossedOut", + + /* Used for underline. These three are interdependent, but apparently + * we can leave out the last two. + */ + "CharUnderline", // "CharUnderlineColor", "CharUnderlineHasColor", + + /* Used for lang="zxx", to silence spellchecker. */ + "CharLocale", + + /* Used for CitationCharacterFormat. */ + "CharStyleName", + + /* Used for and */ + "CharCaseMap"); + + /** + * The number of properties actually controlled. + */ + final int goodSize; + + /** + * From property name to index in goodNames. + */ + final Map goodNameToIndex; + + /** + * From index to property name. + */ + final String[] goodNames; + + /** + * Maintain a stack of layers, each containing a description + * of the desired state of properties. Each description is an + * ArrayList of property values, Optional.empty() encoding + * "not directly set". + */ + final Stack>> layers; + + MyPropertyStack(XTextCursor cursor) + throws UnknownPropertyException { + + XPropertySet propertySet = UnoCast.unoQI(XPropertySet.class, cursor); + XPropertySetInfo propertySetInfo = propertySet.getPropertySetInfo(); + + /* + * On creation, initialize the property name -- index mapping. + */ + this.goodNameToIndex = new HashMap<>(); + int nextIndex = 0; + for (Property p : propertySetInfo.getProperties()) { + if ((p.Attributes & PropertyAttribute.READONLY) != 0) { + continue; + } + if (!CONTROLLED_PROPERTIES.contains(p.Name)) { + continue; + } + this.goodNameToIndex.put(p.Name, nextIndex); + nextIndex++; + } + + this.goodSize = nextIndex; + + this.goodNames = new String[goodSize]; + for (Map.Entry entry : goodNameToIndex.entrySet()) { + goodNames[ entry.getValue() ] = entry.getKey(); + } + + // XMultiPropertySet.setPropertyValues() + // requires alphabetically sorted property names. + // We adjust here: + Arrays.sort(goodNames); + for (int i = 0; i < goodSize; i++) { + this.goodNameToIndex.put(goodNames[i], i); + } + + /* + * Get the initial state of the properties and add add the first layer. + */ + XMultiPropertyStates mpss = UnoCast.unoQI(XMultiPropertyStates.class, cursor); + PropertyState[] propertyStates = mpss.getPropertyStates(goodNames); + + XMultiPropertySet mps = UnoCast.unoQI(XMultiPropertySet.class, cursor); + Object[] initialValues = mps.getPropertyValues(goodNames); + + ArrayList> initialValuesOpt = new ArrayList<>(goodSize); + + for (int i = 0; i < goodSize; i++) { + if (propertyStates[i] == PropertyState.DIRECT_VALUE) { + initialValuesOpt.add(Optional.of(initialValues[i])); + } else { + initialValuesOpt.add(Optional.empty()); + } + } + + this.layers = new Stack<>(); + this.layers.push(initialValuesOpt); + } + + /** + * Given a list of property name, property value pairs, + * construct and push a new layer describing the intended + * state after these have been applied. + * + * Opening tags usually call this. + */ + void pushLayer(List> settings) { + ArrayList> oldLayer = layers.peek(); + ArrayList> newLayer = new ArrayList<>(oldLayer); + for (OOPair pair : settings) { + String name = pair.a; + Integer i = goodNameToIndex.get(name); + if (i == null) { + LOGGER.warn(String.format("pushLayer: '%s' is not in goodNameToIndex", name)); + continue; + } + Object newValue = pair.b; + newLayer.set(i, Optional.ofNullable(newValue)); + } + layers.push(newLayer); + } + + /** + * Closing tags just pop a layer. + */ + void popLayer() { + if (layers.size() <= 1) { + LOGGER.warn("popLayer: underflow"); + return; + } + layers.pop(); + } + + /** + * Apply the current desired formatting state to a cursor. + * The idea is to minimize the number of calls to OpenOffice. + */ + void apply(XTextCursor cursor) { + XMultiPropertySet mps = UnoCast.unoQI(XMultiPropertySet.class, cursor); + XMultiPropertyStates mpss = UnoCast.unoQI(XMultiPropertyStates.class, cursor); + ArrayList> topLayer = layers.peek(); + try { + // select values to be set + ArrayList names = new ArrayList<>(goodSize); + ArrayList values = new ArrayList<>(goodSize); + // and those to be cleared + ArrayList delNames = new ArrayList<>(goodSize); + for (int i = 0; i < goodSize; i++) { + if (topLayer.get(i).isPresent()) { + names.add(goodNames[i]); + values.add(topLayer.get(i).get()); + } else { + delNames.add(goodNames[i]); + } + } + // namesArray must be alphabetically sorted. + String[] namesArray = names.toArray(new String[names.size()]); + String[] delNamesArray = delNames.toArray(new String[names.size()]); + mpss.setPropertiesToDefault(delNamesArray); + mps.setPropertyValues(namesArray, values.toArray()); + } catch (UnknownPropertyException ex) { + LOGGER.warn("UnknownPropertyException in MyPropertyStack.apply"); + } catch (PropertyVetoException ex) { + LOGGER.warn("PropertyVetoException in MyPropertyStack.apply"); + } catch (IllegalArgumentException ex) { + LOGGER.warn("IllegalArgumentException in MyPropertyStack.apply"); + } catch (WrappedTargetException ex) { + LOGGER.warn("WrappedTargetException in MyPropertyStack.apply"); + } + } + + // Relative CharEscapement needs to know current values. + Optional getPropertyValue(String name) { + if (goodNameToIndex.containsKey(name)) { + int i = goodNameToIndex.get(name); + ArrayList> topLayer = layers.peek(); + Optional value = topLayer.get(i); + return value; + } + return Optional.empty(); + } + } + + /** + * Parse HTML-like attributes to a list of (name,value) pairs. + */ + private static List> parseAttributes(String s) { + List> res = new ArrayList<>(); + if (s == null) { + return res; + } + Matcher m = ATTRIBUTE_PATTERN.matcher(s); + while (m.find()) { + String key = m.group(1); + String value = m.group(2); + res.add(new OOPair(key, value)); + } + return res; + } + + /* + * We rely on property values being either DIRECT_VALUE or + * DEFAULT_VALUE (not AMBIGUOUS_VALUE). If the cursor covers a homogeneous region, + * or is collapsed, then this is true. + */ + private static boolean isPropertyDefault(XTextCursor cursor, String propertyName) + throws + UnknownPropertyException { + XPropertyState xPropertyState = UnoCast.unoQI(XPropertyState.class, cursor); + PropertyState state = xPropertyState.getPropertyState(propertyName); + if (state == PropertyState.AMBIGUOUS_VALUE) { + throw new RuntimeException("PropertyState.AMBIGUOUS_VALUE" + + " (expected properties for a homogeneous cursor)"); + } + return state == PropertyState.DEFAULT_VALUE; + } + + /* + * Various property change requests. Their results are passed to MyPropertyStack.pushLayer() + */ + + private static List> setCharWeight(float value) { + List> settings = new ArrayList<>(); + settings.add(new OOPair<>("CharWeight", (Float) value)); + return settings; + } + + private static List> setCharPosture(FontSlant value) { + List> settings = new ArrayList<>(); + settings.add(new OOPair<>("CharPosture", (Object) value)); + return settings; + } + + private static List> setCharCaseMap(short value) { + List> settings = new ArrayList<>(); + settings.add(new OOPair<>("CharCaseMap", (Short) value)); + return settings; + } + + // com.sun.star.awt.FontUnderline + private static List> setCharUnderline(short value) { + List> settings = new ArrayList<>(); + settings.add(new OOPair<>(CHAR_UNDERLINE, (Short) value)); + return settings; + } + + // com.sun.star.awt.FontStrikeout + private static List> setCharStrikeout(short value) { + List> settings = new ArrayList<>(); + settings.add(new OOPair<>(CHAR_STRIKEOUT, (Short) value)); + return settings; + } + + // CharStyleName + private static List> setCharStyleName(String value) { + List> settings = new ArrayList<>(); + if (value != null && value != "") { + settings.add(new OOPair<>(CHAR_STYLE_NAME, value)); + } else { + LOGGER.warn("setCharStyleName: received null or empty value"); + } + return settings; + } + + // Locale + private static List> setCharLocale(Locale value) { + List> settings = new ArrayList<>(); + settings.add(new OOPair<>("CharLocale", (Object) value)); + return settings; + } + + /** + * Locale from string encoding: language, language-country or language-country-variant + */ + private static List> setCharLocale(String value) { + if (value == null || "".equals(value)) { + throw new RuntimeException("setCharLocale \"\" or null"); + } + String[] parts = value.split("-"); + String language = (parts.length > 0) ? parts[0] : ""; + String country = (parts.length > 1) ? parts[1] : ""; + String variant = (parts.length > 2) ? parts[2] : ""; + return setCharLocale(new Locale(language, country, variant)); + } + + /* + * SuperScript and SubScript. + * + * @param relative If true, calculate the new values relative to + * the current values. This allows subscript-in-superscript. + */ + private static List> setCharEscapement(Optional value, + Optional height, + boolean relative, + MyPropertyStack formatStack) { + List> settings = new ArrayList<>(); + Optional oldValue = (formatStack + .getPropertyValue(CHAR_ESCAPEMENT) + .map(e -> (short) e)); + + Optional oldHeight = (formatStack + .getPropertyValue(CHAR_ESCAPEMENT_HEIGHT) + .map(e -> (byte) e)); + + if (relative && (value.isPresent() || height.isPresent())) { + double oldHeightFloat = oldHeight.orElse(CHAR_ESCAPEMENT_HEIGHT_DEFAULT) * 0.01; + double oldValueFloat = oldValue.orElse(CHAR_ESCAPEMENT_VALUE_DEFAULT); + double heightFloat = height.orElse(CHAR_ESCAPEMENT_HEIGHT_DEFAULT); + double valueFloat = value.orElse(CHAR_ESCAPEMENT_VALUE_DEFAULT); + byte newHeight = (byte) Math.round(heightFloat * oldHeightFloat); + short newValue = (short) Math.round(valueFloat * oldHeightFloat + oldValueFloat); + if (value.isPresent()) { + settings.add(new OOPair<>(CHAR_ESCAPEMENT, (Short) newValue)); + } + if (height.isPresent()) { + settings.add(new OOPair<>(CHAR_ESCAPEMENT_HEIGHT, (Byte) newHeight)); + } + } else { + if (value.isPresent()) { + settings.add(new OOPair<>(CHAR_ESCAPEMENT, (Short) value.get())); + } + if (height.isPresent()) { + settings.add(new OOPair<>(CHAR_ESCAPEMENT_HEIGHT, (Byte) height.get())); + } + } + return settings; + } + + private static List> setSubScript(MyPropertyStack formatStack) { + return setCharEscapement(Optional.of(SUBSCRIPT_VALUE), + Optional.of(SUBSCRIPT_HEIGHT), + true, + formatStack); + } + + private static List> setSuperScript(MyPropertyStack formatStack) { + return setCharEscapement(Optional.of(SUPERSCRIPT_VALUE), + Optional.of(SUPERSCRIPT_HEIGHT), + true, + formatStack); + } + + /* + * @return true on failure + */ + public static boolean setParagraphStyle(XTextCursor cursor, String paragraphStyle) { + final boolean FAIL = true; + final boolean PASS = false; + + XParagraphCursor paragraphCursor = UnoCast.unoQI(XParagraphCursor.class, cursor); + XPropertySet propertySet = UnoCast.unoQI(XPropertySet.class, paragraphCursor); + try { + propertySet.setPropertyValue(PARA_STYLE_NAME, paragraphStyle); + return PASS; + } catch (UnknownPropertyException + | PropertyVetoException + | IllegalArgumentException + | WrappedTargetException ex) { + return FAIL; + } + } + + private static void insertParagraphBreak(XText text, XTextCursor cursor) + throws IllegalArgumentException { + text.insertControlCharacter(cursor, ControlCharacter.PARAGRAPH_BREAK, true); + } + +} From 6d013f12ccd1dd6b22ac833c98368d714cea551e Mon Sep 17 00:00:00 2001 From: Antal K Date: Fri, 28 May 2021 11:11:26 +0200 Subject: [PATCH 007/103] add rangesort --- .../rangesort/FunctionalTextViewCursor.java | 159 +++++++++++++++ .../openoffice/rangesort/RangeKeyedMap.java | 90 +++++++++ .../rangesort/RangeKeyedMapList.java | 49 +++++ .../openoffice/rangesort/RangeOverlap.java | 16 ++ .../rangesort/RangeOverlapFinder.java | 61 ++++++ .../rangesort/RangeOverlapKind.java | 14 ++ .../openoffice/rangesort/RangeSortEntry.java | 42 ++++ .../openoffice/rangesort/RangeSortVisual.java | 182 ++++++++++++++++++ .../openoffice/rangesort/RangeSortable.java | 24 +++ 9 files changed, 637 insertions(+) create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMap.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMapList.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlap.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapFinder.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapKind.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java b/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java new file mode 100644 index 00000000000..3f780274b0f --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java @@ -0,0 +1,159 @@ +package org.jabref.model.openoffice.rangesort; + +import java.util.Arrays; +import java.util.Objects; + +import org.jabref.model.openoffice.uno.UnoCursor; +import org.jabref.model.openoffice.uno.UnoSelection; +import org.jabref.model.openoffice.util.OOResult; + +import com.sun.star.lang.XServiceInfo; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import com.sun.star.text.XTextViewCursor; + +/* + * A problem with XTextViewCursor: if it is not in text, then we get a + * crippled version that does not support viewCursor.getStart() or + * viewCursor.gotoRange(range,false), and will throw an exception + * instead. + * + * Here we manipulate the cursor via XSelectionSupplier.getSelection and + * XSelectionSupplier.select to move it to the text. + * + * Seems to work when the user selected a frame or image. + * In these cases restoring the selection works, too. + * + * When the cursor is in a comment (referred to as "annotation" in OO + * API) then initialSelection is null, and select() fails to + * get a functional viewCursor. + * + * If FunctionalTextViewCursor.get() reports error, we have to ask the + * user to move the cursor into the text part of the document. + * + * Usage: + * + * OOResult fcursor = FunctionalTextViewCursor.get(doc, msg); + * if (fcursor.isError()) { + * ... + * } else { + * XTextViewCursor viewCursor = fcursor.get().getViewCursor(); + * ... + * fc.restore(); + * } + * + */ +public class FunctionalTextViewCursor { + + /* + * The initial position of the cursor or null. + */ + private XTextRange initialPosition; + + /* + * The initial selection in the document or null. + */ + private XServiceInfo initialSelection; + + /* + * The view cursor, potentially moved from its original location. + */ + private XTextViewCursor viewCursor; + + private FunctionalTextViewCursor(XTextRange initialPosition, + XServiceInfo initialSelection, + XTextViewCursor viewCursor) { + this.initialPosition = initialPosition; + this.initialSelection = initialSelection; + this.viewCursor = viewCursor; + } + + /* + * Get a functional XTextViewCursor or an error message. + * + * The cursor position may differ from the location + * provided by the user. + * + * On failure the constructor restores the selection. On success, + * the caller may want to call instance.restore() after finished + * using the cursor. + */ + public static OOResult get(XTextDocument doc) { + + Objects.requireNonNull(doc); + + XTextRange initialPosition = null; + XServiceInfo initialSelection = UnoSelection.getSelectionAsXServiceInfo(doc).orElse(null); + XTextViewCursor viewCursor = UnoCursor.getViewCursor(doc).orElse(null); + if (viewCursor != null) { + try { + initialPosition = UnoCursor.createTextCursorByRange(viewCursor); + viewCursor.getStart(); + return OOResult.ok(new FunctionalTextViewCursor(initialPosition, + initialSelection, + viewCursor)); + } catch (com.sun.star.uno.RuntimeException ex) { + // bad cursor + viewCursor = null; + initialPosition = null; + } + } + + if (initialSelection == null) { + String errorMessage = ("Selection is not available:" + + " cannot provide a functional view cursor"); + return OOResult.error(errorMessage); + } else if (!Arrays.stream(initialSelection.getSupportedServiceNames()) + .anyMatch("com.sun.star.text.TextRanges"::equals)) { + // initialSelection does not support TextRanges. + // We need to change it (and the viewCursor with it). + XTextRange newSelection = doc.getText().getStart(); + UnoSelection.select(doc, newSelection); + viewCursor = UnoCursor.getViewCursor(doc).orElse(null); + } + + if (viewCursor == null) { + restore(doc, initialPosition, initialSelection); + String errorMessage = "Could not get the view cursor"; + return OOResult.error(errorMessage); + } + + try { + viewCursor.getStart(); + } catch (com.sun.star.uno.RuntimeException ex) { + restore(doc, initialPosition, initialSelection); + String errorMessage = "The view cursor failed the functionality test"; + return OOResult.error(errorMessage); + } + + return OOResult.ok(new FunctionalTextViewCursor(initialPosition, initialSelection, viewCursor)); + } + + public XTextViewCursor getViewCursor() { + return viewCursor; + } + + private static void restore(XTextDocument doc, + XTextRange initialPosition, + XServiceInfo initialSelection) { + + if (initialPosition != null) { + XTextViewCursor viewCursor = UnoCursor.getViewCursor(doc).orElse(null); + if (viewCursor != null) { + viewCursor.gotoRange(initialPosition, false); + return; + } + } + if (initialSelection != null) { + UnoSelection.select(doc, initialSelection); + } + } + + /* + * Restore initial state of viewCursor (possibly by restoring + * selection) if possible. + */ + public void restore(XTextDocument doc) { + FunctionalTextViewCursor.restore(doc, initialPosition, initialSelection); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMap.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMap.java new file mode 100644 index 00000000000..094705f5fa8 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMap.java @@ -0,0 +1,90 @@ +package org.jabref.model.openoffice.rangesort; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.TreeMap; + +import com.sun.star.text.XText; +import com.sun.star.text.XTextRange; +import com.sun.star.text.XTextRangeCompare; +import com.sun.star.uno.UnoRuntime; + +/** + * Purpose: in order to check overlaps of XTextRange values, sort + * them, and allow recovering some corresponding information + * (of type V) + * + * Since XTextRange values are only comparable if they share the same + * range.getText(), we group them by these. + * + * Within such groups (partitions) we may define comparison, here + * based on (range.getStart(),range.getEnd()), where equality means identical + * ranges. + * + * For finding overlapping ranges this class proved insufficient, + * beacause it does not allow multiple values to be associated with a + * single XTextRange. The class RangeKeyedMapList solves this. + * + */ +public class RangeKeyedMap { + + private final Map> partitions; + + public RangeKeyedMap() { + this.partitions = new HashMap<>(); + } + + public boolean containsKey(XTextRange range) { + Objects.requireNonNull(range); + XText partitionKey = range.getText(); + if (!partitions.containsKey(partitionKey)) { + return false; + } + return partitions.get(partitionKey).containsKey(range); + } + + public V get(XTextRange range) { + TreeMap partition = partitions.get(range.getText()); + if (partition == null) { + return null; + } + return partition.get(range); + } + + /* + * Same as UnoTextRange.compareStartsThenEnds in logic. + */ + private static int comparator(XTextRange a, XTextRange b) { + if (a.getText() != b.getText()) { + throw new RuntimeException("comparator: got incomparable regions"); + } + + final XTextRangeCompare compare = + UnoRuntime.queryInterface(XTextRangeCompare.class, a.getText()); + + int cmpStart = (-1) * compare.compareRegionStarts(a, b); + if (cmpStart != 0) { + return cmpStart; + } + return (-1) * compare.compareRegionEnds(a, b); + } + + public V put(XTextRange range, V value) { + TreeMap partition = partitions.get(range.getText()); + if (partition == null) { + partition = new TreeMap<>(RangeKeyedMap::comparator); + partitions.put(range.getText(), partition); + } + return partition.put(range, value); + } + + /** + * @return A list of the partitions. + */ + public List> partitionValues() { + return new ArrayList<>(partitions.values()); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMapList.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMapList.java new file mode 100644 index 00000000000..9e6edd69738 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMapList.java @@ -0,0 +1,49 @@ +package org.jabref.model.openoffice.rangesort; + +import java.util.ArrayList; +import java.util.List; +import java.util.TreeMap; + +import com.sun.star.text.XTextRange; + +/* + * Partition by XTextRange.getText() and sort within the partitions a + * set of XTextRange values, while keeping their associated data + * recoverable. Allows identical XTextRange values, their data is + * collected in a list. + */ +public class RangeKeyedMapList { + + private RangeKeyedMap> partitions; + + public RangeKeyedMapList() { + this.partitions = new RangeKeyedMap<>(); + } + + public boolean containsKey(XTextRange range) { + return partitions.containsKey(range); + } + + public List get(XTextRange range) { + return partitions.get(range); + } + + public void add(XTextRange range, V value) { + List values = partitions.get(range); + if (values == null) { + values = new ArrayList<>(); + values.add(value); + partitions.put(range, values); + } else { + values.add(value); + } + } + + /** + * @return A list of the partitions. + */ + public List>> partitionValues() { + return this.partitions.partitionValues(); + } + +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlap.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlap.java new file mode 100644 index 00000000000..3edd059d7ff --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlap.java @@ -0,0 +1,16 @@ +package org.jabref.model.openoffice.rangesort; + +import java.util.List; + +/** + * Used in reporting range overlaps. + */ +public class RangeOverlap { + public final RangeOverlapKind kind; + public final List valuesForOverlappingRanges; + + public RangeOverlap(RangeOverlapKind kind, List valuesForOverlappingRanges) { + this.kind = kind; + this.valuesForOverlappingRanges = valuesForOverlappingRanges; + } +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapFinder.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapFinder.java new file mode 100644 index 00000000000..c5b74a0b42d --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapFinder.java @@ -0,0 +1,61 @@ +package org.jabref.model.openoffice.rangesort; + +import java.util.ArrayList; +import java.util.List; +import java.util.TreeMap; + +import org.jabref.model.openoffice.uno.UnoTextRange; + +import com.sun.star.text.XTextRange; + +public class RangeOverlapFinder { + /** + * Report identical, overlapping or touching ranges. + * + * For overlapping and touching, only report consecutive ranges + * and only with a single sample of otherwise identical ranges. + * + * @param atMost Limit the number of records returned to atMost. + * Zero or negative {@code atMost} means no limit. + * + * @param includeTouching Should the result contain ranges + * sharing only a boundary? + */ + public static List> findOverlappingRanges(RangeKeyedMapList input, + int atMost, + boolean includeTouching) { + List> result = new ArrayList<>(); + for (TreeMap> partition : input.partitionValues()) { + List orderedRanges = new ArrayList<>(partition.keySet()); + for (int i = 0; i < orderedRanges.size(); i++) { + XTextRange aRange = orderedRanges.get(i); + List aValues = partition.get(aRange); + if (aValues.size() > 1) { + result.add(new RangeOverlap(RangeOverlapKind.EQUAL_RANGE, aValues)); + if (atMost > 0 && result.size() >= atMost) { + return result; + } + } + if ((i + 1) < orderedRanges.size()) { + XTextRange bRange = orderedRanges.get(i + 1); + int cmp = UnoTextRange.compareStarts(aRange.getEnd(), bRange.getStart()); + if (cmp > 0 || (includeTouching && (cmp == 0))) { + // found overlap or touch + List bValues = partition.get(bRange); + List valuesForOverlappingRanges = new ArrayList<>(); + valuesForOverlappingRanges.add(aValues.get(0)); + valuesForOverlappingRanges.add(bValues.get(0)); + result.add(new RangeOverlap((cmp == 0) + ? RangeOverlapKind.TOUCH + : RangeOverlapKind.OVERLAP, + valuesForOverlappingRanges)); + } + if (atMost > 0 && result.size() >= atMost) { + return result; + } + } + } + } + return result; + } +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapKind.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapKind.java new file mode 100644 index 00000000000..2bb7f8f4af7 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapKind.java @@ -0,0 +1,14 @@ +package org.jabref.model.openoffice.rangesort; + +public enum RangeOverlapKind { + + /** The ranges share a boundary */ + TOUCH, + + /** They share some characters */ + OVERLAP, + + /** They cover the same XTextRange */ + EQUAL_RANGE +} + diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java new file mode 100644 index 00000000000..4ed651e5396 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java @@ -0,0 +1,42 @@ +package org.jabref.model.openoffice.rangesort; + +import com.sun.star.text.XTextRange; + +/** + * A simple implementation of {@code RangeSortable} + */ +public class RangeSortEntry implements RangeSortable { + + private XTextRange range; + private int indexInPosition; + private T content; + + public RangeSortEntry(XTextRange range, int indexInPosition, T content) { + this.range = range; + this.indexInPosition = indexInPosition; + this.content = content; + } + + @Override + public XTextRange getRange() { + return range; + } + + @Override + public int getIndexInPosition() { + return indexInPosition; + } + + @Override + public T getContent() { + return content; + } + + public void setRange(XTextRange r) { + range = r; + } + + public void setIndexInPosition(int i) { + indexInPosition = i; + } +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java new file mode 100644 index 00000000000..67b1fa0471d --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java @@ -0,0 +1,182 @@ +package org.jabref.model.openoffice.rangesort; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; + +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoScreenRefresh; + +import com.sun.star.awt.Point; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import com.sun.star.text.XTextViewCursor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Sort XTextRange values visually (top-down,left-to-right). + * + * Requires functional XTextViewCursor. + * + * Problem: for multicolumn layout and when viewing pages side-by-side + * in LO, the (top-down,left-to-right) order interpreted + * as-on-the-screen: an XTextRange at the top of the second + * column or second page is sorted before one at the bottom + * of the first column of the first page. + */ +public class RangeSortVisual { + + private static final Logger LOGGER = LoggerFactory.getLogger(RangeSortVisual.class); + + /** + * Sort the input {@code inputs} visually. + * + * Requires a functional {@code XTextViewCursor}. + * + * @return The input, sorted by the elements XTextRange and + * getIndexInPosition. + */ + public static List> visualSort(List> inputs, + XTextDocument doc, + FunctionalTextViewCursor fcursor) + throws + WrappedTargetException, + NoDocumentException { + + final int inputSize = inputs.size(); + + if (UnoScreenRefresh.hasControllersLocked(doc)) { + LOGGER.warn("visualSort:" + + " with ControllersLocked, viewCursor.gotoRange" + + " is probably useless"); + } + + XTextViewCursor viewCursor = fcursor.getViewCursor(); + + // find coordinates + List positions = new ArrayList<>(inputSize); + + for (RangeSortable v : inputs) { + positions.add(findPositionOfTextRange(v.getRange(), + viewCursor)); + } + + fcursor.restore(doc); + + if (positions.size() != inputSize) { + throw new RuntimeException("visualSort: positions.size() != inputSize"); + } + + // order by position + Set>> set = new TreeSet<>(); + for (int i = 0; i < inputSize; i++) { + set.add(new ComparableMark<>(positions.get(i), + inputs.get(i).getIndexInPosition(), + inputs.get(i))); + } + + if (set.size() != inputSize) { + throw new RuntimeException("visualSort: set.size() != inputSize"); + } + + // collect ordered result + List> result = new ArrayList<>(set.size()); + for (ComparableMark> mark : set) { + result.add(mark.getContent()); + } + + if (result.size() != inputSize) { + throw new RuntimeException("visualSort: result.size() != inputSize"); + } + + return result; + } + + /** + * Given a location, return its position: coordinates relative to + * the top left position of the first page of the document. + * + * Note: for text layouts with two or more columns, this gives the + * wrong order: top-down/left-to-right does not match + * reading order. + * + * Note: The "relative to the top left position of the first page" + * is meant "as it appears on the screen". + * + * In particular: when viewing pages side-by-side, the top + * half of the right page is higher than the lower half of + * the left page. Again, top-down/left-to-right does not + * match reading order. + * + * @param range Location. + * @param cursor To get the position, we need az XTextViewCursor. + * It will be moved to the range. + */ + private static Point findPositionOfTextRange(XTextRange range, XTextViewCursor cursor) { + cursor.gotoRange(range, false); + return cursor.getPosition(); + } + + /** + * A reference mark name paired with its visual position. + * + * Comparison is based on (Y,X,indexInPosition): vertical compared + * first, horizontal second, indexInPosition third. + * + * Used for sorting reference marks by their visual positions. + */ + private static class ComparableMark implements Comparable> { + + private final Point position; + private final int indexInPosition; + private final T content; + + public ComparableMark(Point position, int indexInPosition, T content) { + this.position = position; + this.indexInPosition = indexInPosition; + this.content = content; + } + + @Override + public int compareTo(ComparableMark other) { + + if (position.Y != other.position.Y) { + return position.Y - other.position.Y; + } + if (position.X != other.position.X) { + return position.X - other.position.X; + } + return indexInPosition - other.indexInPosition; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o instanceof ComparableMark) { + ComparableMark other = (ComparableMark) o; + return ((this.position.X == other.position.X) + && (this.position.Y == other.position.Y) + && (this.indexInPosition == other.indexInPosition) + && Objects.equals(this.content, other.content)); + } + return false; + } + + public T getContent() { + return content; + } + + @Override + public int hashCode() { + return Objects.hash(position, indexInPosition, content); + } + } + +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java new file mode 100644 index 00000000000..39a16b4ecb2 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java @@ -0,0 +1,24 @@ +package org.jabref.model.openoffice.rangesort; + +import com.sun.star.text.XTextRange; + +/** + * This is what {@code visualSort} needs in its input. + */ +public interface RangeSortable { + + /** The XTextRange + * + * For citation marks in footnotes this may be the range of the + * footnote mark. + */ + public XTextRange getRange(); + + /** + * For citation marks in footnotes this may provide order within + * the footnote. + */ + public int getIndexInPosition(); + + public T getContent(); +} From 04345791b7193eb6f1437b1fe11cb399cffccbb0 Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 10:26:08 +0200 Subject: [PATCH 008/103] add compareStartsUnsafe, compareStartsThenEndsUnsafe --- .../model/openoffice/uno/UnoTextRange.java | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java b/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java index 1559c55d490..b44ed6ce38b 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java @@ -40,12 +40,16 @@ public static boolean comparables(XTextRange a, XTextRange b) { * * 1 if (a > b); (-1) if (a < b) */ + public static int compareStartsUnsafe(XTextRangeCompare compare, XTextRange a, XTextRange b) { + return (-1) * compare.compareRegionStarts(a, b); + } + public static int compareStarts(XTextRange a, XTextRange b) { if (!comparables(a, b)) { throw new RuntimeException("compareStarts: got incomparable regions"); } final XTextRangeCompare compare = UnoCast.unoQI(XTextRangeCompare.class, a.getText()); - return (-1) * compare.compareRegionStarts(a, b); + return compareStartsUnsafe(compare, a, b); } /** @@ -61,16 +65,22 @@ public static int compareEnds(XTextRange a, XTextRange b) { return (-1) * compare.compareRegionEnds(a, b); } + /* + * Assumes a and b belong to the same XText as compare. + */ + public static int compareStartsThenEndsUnsafe(XTextRangeCompare compare, XTextRange a, XTextRange b) { + int res = compare.compareRegionStarts(a, b); + if (res != 0) { + return (-1) * res; + } + return (-1) * compare.compareRegionEnds(a, b); + } + public static int compareStartsThenEnds(XTextRange a, XTextRange b) { if (!comparables(a, b)) { throw new RuntimeException("compareStartsThenEnds: got incomparable regions"); } final XTextRangeCompare compare = UnoCast.unoQI(XTextRangeCompare.class, a.getText()); - int res = (-1) * compare.compareRegionStarts(a, b); - if (res != 0) { - return res; - } - return (-1) * compare.compareRegionEnds(a, b); + return compareStartsThenEndsUnsafe(compare, a, b); } - } From 3c45a8a162de5e30707e14c89b86520f5d46e43e Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 10:26:37 +0200 Subject: [PATCH 009/103] add Tuple3 --- .../org/jabref/model/openoffice/util/OOTuple3.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/main/java/org/jabref/model/openoffice/util/OOTuple3.java diff --git a/src/main/java/org/jabref/model/openoffice/util/OOTuple3.java b/src/main/java/org/jabref/model/openoffice/util/OOTuple3.java new file mode 100644 index 00000000000..ca324ebc4ad --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/util/OOTuple3.java @@ -0,0 +1,13 @@ +package org.jabref.model.openoffice.util; + +public class OOTuple3 { + public final A a; + public final B b; + public final C c; + public OOTuple3(A a, B b, C c) { + this.a = a; + this.b = b; + this.c = c; + } +} + From 32f7a43e43a0565c26ea719cabee20ebac6b838a Mon Sep 17 00:00:00 2001 From: Antal K Date: Fri, 28 May 2021 09:38:30 +0200 Subject: [PATCH 010/103] add ootext --- .../model/openoffice/ootext/OOFormat.java | 73 ++ .../model/openoffice/ootext/OOText.java | 62 ++ .../model/openoffice/ootext/OOTextIntoOO.java | 817 ++++++++++++++++++ 3 files changed, 952 insertions(+) create mode 100644 src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java create mode 100644 src/main/java/org/jabref/model/openoffice/ootext/OOText.java create mode 100644 src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java new file mode 100644 index 00000000000..472ca519161 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java @@ -0,0 +1,73 @@ +package org.jabref.model.openoffice.ootext; + +public class OOFormat { + + /** + * Mark {@code s} as using a character locale known to OO. + * + * @param locale language[-country[-territory]] + * + * https://www.openoffice.org/api/docs/common/ref/com/sun/star/lang/Locale.html + * + * The country part is optional. + * + * The territory part is not only optional, the allowed "codes are + * vendor and browser-specific", so probably best to avoid them if possible. + * + */ + public static OOText setLocale(OOText s, String locale) { + return OOText.fromString(String.format("", locale) + s.asString() + ""); + } + + /** + * Mark {@code s} as using the character locale "zxx", which means + * "no language", "no linguistic content". + * + * Used around citation marks, probably to turn off spellchecking. + * + */ + public static OOText setLocaleNone(OOText s) { + return OOFormat.setLocale(s, "zxx"); + } + + /** + * Mark {@code s} using a character style {@code charStyle} + * + * @param charStyle Name of a character style known to OO. May be + * empty for "Standard", which in turn means do not override any properties. + * + */ + public static OOText setCharStyle(OOText s, String charStyle) { + return OOText.fromString(String.format("", charStyle) + + s.asString() + + ""); + } + + /** + * Mark {@code s} as part of a paragraph with style {@code paraStyle} + */ + public static OOText paragraph(OOText s, String paraStyle) { + if (paraStyle == null || "".equals(paraStyle)) { + return paragraph(s); + } + String startTag = String.format("

", paraStyle); + return OOText.fromString(startTag + s.asString() + "

"); + } + + /** + * Mark {@code s} as part of a paragraph. + */ + public static OOText paragraph(OOText s) { + return OOText.fromString("

" + s.asString() + "

"); + } + + /** + * Format an OO cross-reference showing the target's page number + * as label to a reference mark. + */ + public static OOText formatReferenceToPageNumberOfReferenceMark(String referencMarkName) { + String s = String.format("", + referencMarkName); + return OOText.fromString(s); + } + } diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOText.java b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java new file mode 100644 index 00000000000..a568a7c6e8a --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java @@ -0,0 +1,62 @@ +package org.jabref.model.openoffice.ootext; + +import java.util.Objects; + +/** + * Text with HTML-like markup as understood by OOTextIntoOO.write + * + * Some of the tags can be added using OOFormat methods. Others come + * from the layout engine, either by interpreting LaTeX markup or from + * settings in the jstyle file. + */ +public class OOText { + + private final String data; + + private OOText(String data) { + Objects.requireNonNull(data); + this.data = data; + } + + /* null input is passed through */ + public static OOText fromString(String s) { + if (s == null) { + return null; + } + return new OOText(s); + } + + /* null input is passed through */ + public static String toString(OOText s) { + if (s == null) { + return null; + } + return s.data; + } + + public String asString() { + return data; + } + + /* Object.equals */ + @Override + public boolean equals(Object o) { + + if (o == this) { + return true; + } + + if (!(o instanceof OOText)) { + return false; + } + + OOText c = (OOText) o; + + return data.equals(c.data); + } + + @Override + public int hashCode() { + return data.hashCode(); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java new file mode 100644 index 00000000000..f062bed7c40 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java @@ -0,0 +1,817 @@ +package org.jabref.model.openoffice.ootext; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.jabref.architecture.AllowedToUseAwt; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.UnoCast; +import org.jabref.model.openoffice.uno.UnoCrossRef; +import org.jabref.model.openoffice.util.OOPair; + +import com.sun.star.awt.FontSlant; +import com.sun.star.awt.FontStrikeout; +import com.sun.star.awt.FontUnderline; +import com.sun.star.awt.FontWeight; +import com.sun.star.beans.Property; +import com.sun.star.beans.PropertyAttribute; +import com.sun.star.beans.PropertyState; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.beans.XMultiPropertySet; +import com.sun.star.beans.XMultiPropertyStates; +import com.sun.star.beans.XPropertySet; +import com.sun.star.beans.XPropertySetInfo; +import com.sun.star.beans.XPropertyState; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.Locale; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.style.CaseMap; +import com.sun.star.text.ControlCharacter; +import com.sun.star.text.XParagraphCursor; +import com.sun.star.text.XText; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Interpret OOText into an OpenOffice or LibreOffice writer + * document. + */ +@AllowedToUseAwt("Requires AWT for changing document properties") +public class OOTextIntoOO { + + private static final Logger LOGGER = LoggerFactory.getLogger(OOTextIntoOO.class); + + /** + * "ParaStyleName" is an OpenOffice Property name. + */ + private static final String PARA_STYLE_NAME = "ParaStyleName"; + + /* + * Character property names used in multiple locations below. + */ + private static final String CHAR_ESCAPEMENT_HEIGHT = "CharEscapementHeight"; + private static final String CHAR_ESCAPEMENT = "CharEscapement"; + private static final String CHAR_STYLE_NAME = "CharStyleName"; + private static final String CHAR_UNDERLINE = "CharUnderline"; + private static final String CHAR_STRIKEOUT = "CharStrikeout"; + + /* + * SUPERSCRIPT_VALUE and SUPERSCRIPT_HEIGHT are percents of the normal character height + */ + private static final short CHAR_ESCAPEMENT_VALUE_DEFAULT = (short) 0; + private static final short SUPERSCRIPT_VALUE = (short) 33; + private static final short SUBSCRIPT_VALUE = (short) -10; + private static final byte CHAR_ESCAPEMENT_HEIGHT_DEFAULT = (byte) 100; + private static final byte SUPERSCRIPT_HEIGHT = (byte) 58; + private static final byte SUBSCRIPT_HEIGHT = (byte) 58; + + private static final String TAG_NAME_REGEXP = + "(?:b|i|em|tt|smallcaps|sup|sub|u|s|p|span|oo:referenceToPageNumberOfReferenceMark)"; + + private static final String ATTRIBUTE_NAME_REGEXP = + "(?:oo:ParaStyleName|oo:CharStyleName|lang|style|target)"; + + private static final String ATTRIBUTE_VALUE_REGEXP = "\"([^\"]*)\""; + + private static final Pattern HTML_TAG = + Pattern.compile("<(/" + TAG_NAME_REGEXP + ")>" + + "|" + + "<(" + TAG_NAME_REGEXP + ")" + + "((?:\\s+(" + ATTRIBUTE_NAME_REGEXP + ")=" + ATTRIBUTE_VALUE_REGEXP + ")*)" + + ">"); + + private static final Pattern ATTRIBUTE_PATTERN = + Pattern.compile("\\s+(" + ATTRIBUTE_NAME_REGEXP + ")=" + ATTRIBUTE_VALUE_REGEXP); + + private OOTextIntoOO() { + // Hide the public constructor + } + + /** + * Insert a text with formatting indicated by HTML-like tags, into + * a text at the position given by a cursor. + * + * Limitation: understands no entities. It does not receive any either, unless + * the user provides it. + * + * To limit the damage {@code TAG_NAME_REGEXP} and {@code ATTRIBUTE_NAME_REGEXP} + * explicitly lists the names we care about. + * + * Notable changes w.r.t insertOOFormattedTextAtCurrentLocation: + * + * - new tags: + * + * - <span lang="zxx"> + * - earlier was applied from code + * + * - <span oo:CharStyleName="CharStylename"> + * - earlier was applied from code, for "CitationCharacterFormat" + * + * - <p> start new paragraph + * - earlier was applied from code + * + * - <p oo:ParaStyleName="ParStyleName"> : start new paragraph and apply ParStyleName + * - earlier was applied from code + * + * - <tt> + * - earlier: known, but ignored + * - now: equivalent to <span oo:CharStyleName="Example"> + * - <oo:referenceToPageNumberOfReferenceMark> (self-closing) + * + * - closing tags try to properly restore state (in particular, the "not directly set" state) + * instead of dictating an "off" state. This makes a difference when the value inherited from + * another level (for example the paragraph) is not the "off" state. + * + * An example: a style with + * ReferenceParagraphFormat="JR_bibentry" + * Assume JR_bibentry in LibreOffice is a paragraph style that prescribes "bold" font. + * LAYOUT only prescribes bold around year. + * Which parts of the bibliography entries should come out as bold? + * + * - The user can format citation marks (it is enough to format their start) and the + * properties not (everywhere) dictated by the style are preserved (where they are not). + * + * @param position The cursor giving the insert location. Not modified. + * @param ootext The marked-up text to insert. + */ + public static void write(XTextDocument doc, XTextCursor position, OOText ootext) + throws + UnknownPropertyException, + PropertyVetoException, + WrappedTargetException, + IllegalArgumentException, + NoSuchElementException, + CreationException { + + final boolean debugThisFun = false; + + Objects.requireNonNull(doc); + Objects.requireNonNull(ootext); + Objects.requireNonNull(position); + + String lText = OOText.toString(ootext); + + if (debugThisFun) { + System.out.println(lText); + } + + XText text = position.getText(); + XTextCursor cursor = text.createTextCursorByRange(position); + cursor.collapseToEnd(); + + MyPropertyStack formatStack = new MyPropertyStack(cursor); + Stack expectEnd = new Stack<>(); + + // We need to extract formatting. Use a simple regexp search iteration: + int piv = 0; + Matcher m = HTML_TAG.matcher(lText); + while (m.find()) { + + String currentSubstring = lText.substring(piv, m.start()); + if (!currentSubstring.isEmpty()) { + cursor.setString(currentSubstring); + } + formatStack.apply(cursor); + cursor.collapseToEnd(); + + String fullTag = m.group(); + String endTagName = m.group(1); + String startTagName = m.group(2); + String attributeListPart = m.group(3); + boolean isStartTag = (endTagName == null) || "".equals(endTagName); + String tagName = isStartTag ? startTagName : endTagName; + Objects.requireNonNull(tagName); + + // Attibutes parsed into (name,value) pairs. + List> attributes = parseAttributes(attributeListPart); + + // Handle tags: + switch (tagName) { + case "b": + formatStack.pushLayer(setCharWeight(FontWeight.BOLD)); + expectEnd.push("/" + tagName); + break; + case "i": + case "em": + formatStack.pushLayer(setCharPosture(FontSlant.ITALIC)); + expectEnd.push("/" + tagName); + break; + case "smallcaps": + formatStack.pushLayer(setCharCaseMap(CaseMap.SMALLCAPS)); + expectEnd.push("/" + tagName); + break; + case "sup": + formatStack.pushLayer(setSuperScript(formatStack)); + expectEnd.push("/" + tagName); + break; + case "sub": + formatStack.pushLayer(setSubScript(formatStack)); + expectEnd.push("/" + tagName); + break; + case "u": + formatStack.pushLayer(setCharUnderline(FontUnderline.SINGLE)); + expectEnd.push("/" + tagName); + break; + case "s": + formatStack.pushLayer(setCharStrikeout(FontStrikeout.SINGLE)); + expectEnd.push("/" + tagName); + break; + case "/p": + // nop + break; + case "p": + insertParagraphBreak(text, cursor); + cursor.collapseToEnd(); + for (OOPair pair : attributes) { + String key = pair.a; + String value = pair.b; + switch (key) { + case "oo:ParaStyleName": + //

+ if (value != null && !value.equals("")) { + if (setParagraphStyle(cursor, value)) { + if (debugThisFun) { + // Presumably tested already: + LOGGER.warn(String.format("oo:ParaStyleName=\"%s\" failed", value)); + } + } + } else { + if (debugThisFun) { + LOGGER.warn(String.format("oo:ParaStyleName inherited")); + } + } + break; + default: + LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); + break; + } + } + break; + case "oo:referenceToPageNumberOfReferenceMark": + for (OOPair pair : attributes) { + String key = pair.a; + String value = pair.b; + switch (key) { + case "target": + UnoCrossRef.insertReferenceToPageNumberOfReferenceMark(doc, value, cursor); + break; + default: + LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); + break; + } + } + break; + case "tt": + // Note: "Example" names a character style in LibreOffice. + formatStack.pushLayer(setCharStyleName("Example")); + expectEnd.push("/" + tagName); + break; + case "span": + List> settings = new ArrayList<>(); + for (OOPair pair : attributes) { + String key = pair.a; + String value = pair.b; + switch (key) { + case "oo:CharStyleName": + // + settings.addAll(setCharStyleName(value)); + break; + case "lang": + // + // + settings.addAll(setCharLocale(value)); + break; + case "style": + // HTML-style small-caps + if (value.equals("font-variant: small-caps")) { + settings.addAll(setCharCaseMap(CaseMap.SMALLCAPS)); + break; + } + LOGGER.warn(String.format("Unexpected value %s for attribute '%s' for <%s>", + value, key, tagName)); + break; + default: + LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); + break; + } + } + formatStack.pushLayer(settings); + expectEnd.push("/" + tagName); + break; + case "/b": + case "/i": + case "/em": + case "/tt": + case "/smallcaps": + case "/sup": + case "/sub": + case "/u": + case "/s": + case "/span": + formatStack.popLayer(); + String expected = expectEnd.pop(); + if (!tagName.equals(expected)) { + LOGGER.warn(String.format("expected '<%s>', found '<%s>' after '%s'", + expected, + tagName, + currentSubstring)); + } + break; + } + + piv = m.end(); + } + + if (piv < lText.length()) { + cursor.setString(lText.substring(piv)); + } + formatStack.apply(cursor); + cursor.collapseToEnd(); + + if (!expectEnd.empty()) { + String rest = ""; + for (String s : expectEnd) { + rest = String.format("<%s>", s) + rest; + } + LOGGER.warn(String.format("OOTextIntoOO.write:" + + " expectEnd stack is not empty at the end: %s%n", + rest)); + } + } + + /** + * Purpose: in some cases we do not want to inherit direct + * formatting from the context. + * + * In particular, when filling the bibliography title and body. + */ + public static void removeDirectFormatting(XTextCursor cursor) { + + XMultiPropertyStates mpss = UnoCast.unoQI(XMultiPropertyStates.class, cursor); + + XPropertySet propertySet = UnoCast.unoQI(XPropertySet.class, cursor); + XPropertyState xPropertyState = UnoCast.unoQI(XPropertyState.class, cursor); + + try { + // Special handling + propertySet.setPropertyValue(CHAR_STYLE_NAME, "Standard"); + xPropertyState.setPropertyToDefault("CharCaseMap"); + } catch (UnknownPropertyException | + PropertyVetoException | + IllegalArgumentException | + WrappedTargetException ex) { + LOGGER.warn("exception caught", ex); + } + + mpss.setAllPropertiesToDefault(); + + /* + * Now that we have called setAllPropertiesToDefault, check which properties + * are not set to default and try to correct what we can and seem necessary. + * + * Note: tested with LibreOffice : 6.4.6.2 + */ + + // Only report those we do not yet know about + final Set knownToFail = Set.of("ListAutoFormat", + "ListId", + "NumberingIsNumber", + "NumberingLevel", + "NumberingRules", + "NumberingStartValue", + "ParaChapterNumberingLevel", + "ParaIsNumberingRestart", + "ParaStyleName"); + + // query again, just in case it matters + propertySet = UnoCast.unoQI(XPropertySet.class, cursor); + XPropertySetInfo propertySetInfo = propertySet.getPropertySetInfo(); + + // check the result + for (Property p : propertySetInfo.getProperties()) { + if ((p.Attributes & PropertyAttribute.READONLY) != 0) { + continue; + } + try { + if (isPropertyDefault(cursor, p.Name)) { + continue; + } + } catch (UnknownPropertyException ex) { + throw new RuntimeException("Unexpected UnknownPropertyException"); + } + if (knownToFail.contains(p.Name)) { + continue; + } + LOGGER.warn(String.format("OOTextIntoOO.removeDirectFormatting failed on '%s'", p.Name)); + } + } + + static class MyPropertyStack { + + /* + * We only try to control these. Should include all character + * properties we set, and maybe their interdependencies. + * + * For a list of properties see: + * https://www.openoffice.org/api/docs/common/ref/com/sun/star/style/CharacterProperties.html + * + * For interdependencies between properties: + * https://wiki.openoffice.org/wiki/Documentation/DevGuide/Text/Formatting + * (at the end, under "Interdependencies between Properties") + * + */ + static final Set CONTROLLED_PROPERTIES = Set.of( + + /* Used for SuperScript, SubScript. + * + * These three are interdependent: changing one may change others. + */ + "CharEscapement", "CharEscapementHeight", "CharAutoEscapement", + + /* used for Bold */ + "CharWeight", + + /* Used for Italic */ + "CharPosture", + + /* Used for strikeout. These two are interdependent. */ + "CharStrikeout", "CharCrossedOut", + + /* Used for underline. These three are interdependent, but apparently + * we can leave out the last two. + */ + "CharUnderline", // "CharUnderlineColor", "CharUnderlineHasColor", + + /* Used for lang="zxx", to silence spellchecker. */ + "CharLocale", + + /* Used for CitationCharacterFormat. */ + "CharStyleName", + + /* Used for and */ + "CharCaseMap"); + + /** + * The number of properties actually controlled. + */ + final int goodSize; + + /** + * From property name to index in goodNames. + */ + final Map goodNameToIndex; + + /** + * From index to property name. + */ + final String[] goodNames; + + /** + * Maintain a stack of layers, each containing a description + * of the desired state of properties. Each description is an + * ArrayList of property values, Optional.empty() encoding + * "not directly set". + */ + final Stack>> layers; + + MyPropertyStack(XTextCursor cursor) + throws UnknownPropertyException { + + XPropertySet propertySet = UnoCast.unoQI(XPropertySet.class, cursor); + XPropertySetInfo propertySetInfo = propertySet.getPropertySetInfo(); + + /* + * On creation, initialize the property name -- index mapping. + */ + this.goodNameToIndex = new HashMap<>(); + int nextIndex = 0; + for (Property p : propertySetInfo.getProperties()) { + if ((p.Attributes & PropertyAttribute.READONLY) != 0) { + continue; + } + if (!CONTROLLED_PROPERTIES.contains(p.Name)) { + continue; + } + this.goodNameToIndex.put(p.Name, nextIndex); + nextIndex++; + } + + this.goodSize = nextIndex; + + this.goodNames = new String[goodSize]; + for (Map.Entry entry : goodNameToIndex.entrySet()) { + goodNames[ entry.getValue() ] = entry.getKey(); + } + + // XMultiPropertySet.setPropertyValues() + // requires alphabetically sorted property names. + // We adjust here: + Arrays.sort(goodNames); + for (int i = 0; i < goodSize; i++) { + this.goodNameToIndex.put(goodNames[i], i); + } + + /* + * Get the initial state of the properties and add add the first layer. + */ + XMultiPropertyStates mpss = UnoCast.unoQI(XMultiPropertyStates.class, cursor); + PropertyState[] propertyStates = mpss.getPropertyStates(goodNames); + + XMultiPropertySet mps = UnoCast.unoQI(XMultiPropertySet.class, cursor); + Object[] initialValues = mps.getPropertyValues(goodNames); + + ArrayList> initialValuesOpt = new ArrayList<>(goodSize); + + for (int i = 0; i < goodSize; i++) { + if (propertyStates[i] == PropertyState.DIRECT_VALUE) { + initialValuesOpt.add(Optional.of(initialValues[i])); + } else { + initialValuesOpt.add(Optional.empty()); + } + } + + this.layers = new Stack<>(); + this.layers.push(initialValuesOpt); + } + + /** + * Given a list of property name, property value pairs, + * construct and push a new layer describing the intended + * state after these have been applied. + * + * Opening tags usually call this. + */ + void pushLayer(List> settings) { + ArrayList> oldLayer = layers.peek(); + ArrayList> newLayer = new ArrayList<>(oldLayer); + for (OOPair pair : settings) { + String name = pair.a; + Integer i = goodNameToIndex.get(name); + if (i == null) { + LOGGER.warn(String.format("pushLayer: '%s' is not in goodNameToIndex", name)); + continue; + } + Object newValue = pair.b; + newLayer.set(i, Optional.ofNullable(newValue)); + } + layers.push(newLayer); + } + + /** + * Closing tags just pop a layer. + */ + void popLayer() { + if (layers.size() <= 1) { + LOGGER.warn("popLayer: underflow"); + return; + } + layers.pop(); + } + + /** + * Apply the current desired formatting state to a cursor. + * The idea is to minimize the number of calls to OpenOffice. + */ + void apply(XTextCursor cursor) { + XMultiPropertySet mps = UnoCast.unoQI(XMultiPropertySet.class, cursor); + XMultiPropertyStates mpss = UnoCast.unoQI(XMultiPropertyStates.class, cursor); + ArrayList> topLayer = layers.peek(); + try { + // select values to be set + ArrayList names = new ArrayList<>(goodSize); + ArrayList values = new ArrayList<>(goodSize); + // and those to be cleared + ArrayList delNames = new ArrayList<>(goodSize); + for (int i = 0; i < goodSize; i++) { + if (topLayer.get(i).isPresent()) { + names.add(goodNames[i]); + values.add(topLayer.get(i).get()); + } else { + delNames.add(goodNames[i]); + } + } + // namesArray must be alphabetically sorted. + String[] namesArray = names.toArray(new String[names.size()]); + String[] delNamesArray = delNames.toArray(new String[names.size()]); + mpss.setPropertiesToDefault(delNamesArray); + mps.setPropertyValues(namesArray, values.toArray()); + } catch (UnknownPropertyException ex) { + LOGGER.warn("UnknownPropertyException in MyPropertyStack.apply"); + } catch (PropertyVetoException ex) { + LOGGER.warn("PropertyVetoException in MyPropertyStack.apply"); + } catch (IllegalArgumentException ex) { + LOGGER.warn("IllegalArgumentException in MyPropertyStack.apply"); + } catch (WrappedTargetException ex) { + LOGGER.warn("WrappedTargetException in MyPropertyStack.apply"); + } + } + + // Relative CharEscapement needs to know current values. + Optional getPropertyValue(String name) { + if (goodNameToIndex.containsKey(name)) { + int i = goodNameToIndex.get(name); + ArrayList> topLayer = layers.peek(); + Optional value = topLayer.get(i); + return value; + } + return Optional.empty(); + } + } + + /** + * Parse HTML-like attributes to a list of (name,value) pairs. + */ + private static List> parseAttributes(String s) { + List> res = new ArrayList<>(); + if (s == null) { + return res; + } + Matcher m = ATTRIBUTE_PATTERN.matcher(s); + while (m.find()) { + String key = m.group(1); + String value = m.group(2); + res.add(new OOPair(key, value)); + } + return res; + } + + /* + * We rely on property values being either DIRECT_VALUE or + * DEFAULT_VALUE (not AMBIGUOUS_VALUE). If the cursor covers a homogeneous region, + * or is collapsed, then this is true. + */ + private static boolean isPropertyDefault(XTextCursor cursor, String propertyName) + throws + UnknownPropertyException { + XPropertyState xPropertyState = UnoCast.unoQI(XPropertyState.class, cursor); + PropertyState state = xPropertyState.getPropertyState(propertyName); + if (state == PropertyState.AMBIGUOUS_VALUE) { + throw new RuntimeException("PropertyState.AMBIGUOUS_VALUE" + + " (expected properties for a homogeneous cursor)"); + } + return state == PropertyState.DEFAULT_VALUE; + } + + /* + * Various property change requests. Their results are passed to MyPropertyStack.pushLayer() + */ + + private static List> setCharWeight(float value) { + List> settings = new ArrayList<>(); + settings.add(new OOPair<>("CharWeight", (Float) value)); + return settings; + } + + private static List> setCharPosture(FontSlant value) { + List> settings = new ArrayList<>(); + settings.add(new OOPair<>("CharPosture", (Object) value)); + return settings; + } + + private static List> setCharCaseMap(short value) { + List> settings = new ArrayList<>(); + settings.add(new OOPair<>("CharCaseMap", (Short) value)); + return settings; + } + + // com.sun.star.awt.FontUnderline + private static List> setCharUnderline(short value) { + List> settings = new ArrayList<>(); + settings.add(new OOPair<>(CHAR_UNDERLINE, (Short) value)); + return settings; + } + + // com.sun.star.awt.FontStrikeout + private static List> setCharStrikeout(short value) { + List> settings = new ArrayList<>(); + settings.add(new OOPair<>(CHAR_STRIKEOUT, (Short) value)); + return settings; + } + + // CharStyleName + private static List> setCharStyleName(String value) { + List> settings = new ArrayList<>(); + if (value != null && value != "") { + settings.add(new OOPair<>(CHAR_STYLE_NAME, value)); + } else { + LOGGER.warn("setCharStyleName: received null or empty value"); + } + return settings; + } + + // Locale + private static List> setCharLocale(Locale value) { + List> settings = new ArrayList<>(); + settings.add(new OOPair<>("CharLocale", (Object) value)); + return settings; + } + + /** + * Locale from string encoding: language, language-country or language-country-variant + */ + private static List> setCharLocale(String value) { + if (value == null || "".equals(value)) { + throw new RuntimeException("setCharLocale \"\" or null"); + } + String[] parts = value.split("-"); + String language = (parts.length > 0) ? parts[0] : ""; + String country = (parts.length > 1) ? parts[1] : ""; + String variant = (parts.length > 2) ? parts[2] : ""; + return setCharLocale(new Locale(language, country, variant)); + } + + /* + * SuperScript and SubScript. + * + * @param relative If true, calculate the new values relative to + * the current values. This allows subscript-in-superscript. + */ + private static List> setCharEscapement(Optional value, + Optional height, + boolean relative, + MyPropertyStack formatStack) { + List> settings = new ArrayList<>(); + Optional oldValue = (formatStack + .getPropertyValue(CHAR_ESCAPEMENT) + .map(e -> (short) e)); + + Optional oldHeight = (formatStack + .getPropertyValue(CHAR_ESCAPEMENT_HEIGHT) + .map(e -> (byte) e)); + + if (relative && (value.isPresent() || height.isPresent())) { + double oldHeightFloat = oldHeight.orElse(CHAR_ESCAPEMENT_HEIGHT_DEFAULT) * 0.01; + double oldValueFloat = oldValue.orElse(CHAR_ESCAPEMENT_VALUE_DEFAULT); + double heightFloat = height.orElse(CHAR_ESCAPEMENT_HEIGHT_DEFAULT); + double valueFloat = value.orElse(CHAR_ESCAPEMENT_VALUE_DEFAULT); + byte newHeight = (byte) Math.round(heightFloat * oldHeightFloat); + short newValue = (short) Math.round(valueFloat * oldHeightFloat + oldValueFloat); + if (value.isPresent()) { + settings.add(new OOPair<>(CHAR_ESCAPEMENT, (Short) newValue)); + } + if (height.isPresent()) { + settings.add(new OOPair<>(CHAR_ESCAPEMENT_HEIGHT, (Byte) newHeight)); + } + } else { + if (value.isPresent()) { + settings.add(new OOPair<>(CHAR_ESCAPEMENT, (Short) value.get())); + } + if (height.isPresent()) { + settings.add(new OOPair<>(CHAR_ESCAPEMENT_HEIGHT, (Byte) height.get())); + } + } + return settings; + } + + private static List> setSubScript(MyPropertyStack formatStack) { + return setCharEscapement(Optional.of(SUBSCRIPT_VALUE), + Optional.of(SUBSCRIPT_HEIGHT), + true, + formatStack); + } + + private static List> setSuperScript(MyPropertyStack formatStack) { + return setCharEscapement(Optional.of(SUPERSCRIPT_VALUE), + Optional.of(SUPERSCRIPT_HEIGHT), + true, + formatStack); + } + + /* + * @return true on failure + */ + public static boolean setParagraphStyle(XTextCursor cursor, String paragraphStyle) { + final boolean FAIL = true; + final boolean PASS = false; + + XParagraphCursor paragraphCursor = UnoCast.unoQI(XParagraphCursor.class, cursor); + XPropertySet propertySet = UnoCast.unoQI(XPropertySet.class, paragraphCursor); + try { + propertySet.setPropertyValue(PARA_STYLE_NAME, paragraphStyle); + return PASS; + } catch (UnknownPropertyException + | PropertyVetoException + | IllegalArgumentException + | WrappedTargetException ex) { + return FAIL; + } + } + + private static void insertParagraphBreak(XText text, XTextCursor cursor) + throws IllegalArgumentException { + text.insertControlCharacter(cursor, ControlCharacter.PARAGRAPH_BREAK, true); + } + +} From 6bae6b469f2d8d8b3ebe3d49eecb06ea19f15729 Mon Sep 17 00:00:00 2001 From: Antal K Date: Fri, 28 May 2021 11:11:26 +0200 Subject: [PATCH 011/103] add rangesort --- .../rangesort/FunctionalTextViewCursor.java | 159 +++++++++++++++ .../openoffice/rangesort/RangeKeyedMap.java | 90 +++++++++ .../rangesort/RangeKeyedMapList.java | 49 +++++ .../openoffice/rangesort/RangeOverlap.java | 16 ++ .../rangesort/RangeOverlapFinder.java | 61 ++++++ .../rangesort/RangeOverlapKind.java | 14 ++ .../openoffice/rangesort/RangeSortEntry.java | 42 ++++ .../openoffice/rangesort/RangeSortVisual.java | 182 ++++++++++++++++++ .../openoffice/rangesort/RangeSortable.java | 24 +++ 9 files changed, 637 insertions(+) create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMap.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMapList.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlap.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapFinder.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapKind.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java b/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java new file mode 100644 index 00000000000..3f780274b0f --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java @@ -0,0 +1,159 @@ +package org.jabref.model.openoffice.rangesort; + +import java.util.Arrays; +import java.util.Objects; + +import org.jabref.model.openoffice.uno.UnoCursor; +import org.jabref.model.openoffice.uno.UnoSelection; +import org.jabref.model.openoffice.util.OOResult; + +import com.sun.star.lang.XServiceInfo; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import com.sun.star.text.XTextViewCursor; + +/* + * A problem with XTextViewCursor: if it is not in text, then we get a + * crippled version that does not support viewCursor.getStart() or + * viewCursor.gotoRange(range,false), and will throw an exception + * instead. + * + * Here we manipulate the cursor via XSelectionSupplier.getSelection and + * XSelectionSupplier.select to move it to the text. + * + * Seems to work when the user selected a frame or image. + * In these cases restoring the selection works, too. + * + * When the cursor is in a comment (referred to as "annotation" in OO + * API) then initialSelection is null, and select() fails to + * get a functional viewCursor. + * + * If FunctionalTextViewCursor.get() reports error, we have to ask the + * user to move the cursor into the text part of the document. + * + * Usage: + * + * OOResult fcursor = FunctionalTextViewCursor.get(doc, msg); + * if (fcursor.isError()) { + * ... + * } else { + * XTextViewCursor viewCursor = fcursor.get().getViewCursor(); + * ... + * fc.restore(); + * } + * + */ +public class FunctionalTextViewCursor { + + /* + * The initial position of the cursor or null. + */ + private XTextRange initialPosition; + + /* + * The initial selection in the document or null. + */ + private XServiceInfo initialSelection; + + /* + * The view cursor, potentially moved from its original location. + */ + private XTextViewCursor viewCursor; + + private FunctionalTextViewCursor(XTextRange initialPosition, + XServiceInfo initialSelection, + XTextViewCursor viewCursor) { + this.initialPosition = initialPosition; + this.initialSelection = initialSelection; + this.viewCursor = viewCursor; + } + + /* + * Get a functional XTextViewCursor or an error message. + * + * The cursor position may differ from the location + * provided by the user. + * + * On failure the constructor restores the selection. On success, + * the caller may want to call instance.restore() after finished + * using the cursor. + */ + public static OOResult get(XTextDocument doc) { + + Objects.requireNonNull(doc); + + XTextRange initialPosition = null; + XServiceInfo initialSelection = UnoSelection.getSelectionAsXServiceInfo(doc).orElse(null); + XTextViewCursor viewCursor = UnoCursor.getViewCursor(doc).orElse(null); + if (viewCursor != null) { + try { + initialPosition = UnoCursor.createTextCursorByRange(viewCursor); + viewCursor.getStart(); + return OOResult.ok(new FunctionalTextViewCursor(initialPosition, + initialSelection, + viewCursor)); + } catch (com.sun.star.uno.RuntimeException ex) { + // bad cursor + viewCursor = null; + initialPosition = null; + } + } + + if (initialSelection == null) { + String errorMessage = ("Selection is not available:" + + " cannot provide a functional view cursor"); + return OOResult.error(errorMessage); + } else if (!Arrays.stream(initialSelection.getSupportedServiceNames()) + .anyMatch("com.sun.star.text.TextRanges"::equals)) { + // initialSelection does not support TextRanges. + // We need to change it (and the viewCursor with it). + XTextRange newSelection = doc.getText().getStart(); + UnoSelection.select(doc, newSelection); + viewCursor = UnoCursor.getViewCursor(doc).orElse(null); + } + + if (viewCursor == null) { + restore(doc, initialPosition, initialSelection); + String errorMessage = "Could not get the view cursor"; + return OOResult.error(errorMessage); + } + + try { + viewCursor.getStart(); + } catch (com.sun.star.uno.RuntimeException ex) { + restore(doc, initialPosition, initialSelection); + String errorMessage = "The view cursor failed the functionality test"; + return OOResult.error(errorMessage); + } + + return OOResult.ok(new FunctionalTextViewCursor(initialPosition, initialSelection, viewCursor)); + } + + public XTextViewCursor getViewCursor() { + return viewCursor; + } + + private static void restore(XTextDocument doc, + XTextRange initialPosition, + XServiceInfo initialSelection) { + + if (initialPosition != null) { + XTextViewCursor viewCursor = UnoCursor.getViewCursor(doc).orElse(null); + if (viewCursor != null) { + viewCursor.gotoRange(initialPosition, false); + return; + } + } + if (initialSelection != null) { + UnoSelection.select(doc, initialSelection); + } + } + + /* + * Restore initial state of viewCursor (possibly by restoring + * selection) if possible. + */ + public void restore(XTextDocument doc) { + FunctionalTextViewCursor.restore(doc, initialPosition, initialSelection); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMap.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMap.java new file mode 100644 index 00000000000..094705f5fa8 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMap.java @@ -0,0 +1,90 @@ +package org.jabref.model.openoffice.rangesort; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.TreeMap; + +import com.sun.star.text.XText; +import com.sun.star.text.XTextRange; +import com.sun.star.text.XTextRangeCompare; +import com.sun.star.uno.UnoRuntime; + +/** + * Purpose: in order to check overlaps of XTextRange values, sort + * them, and allow recovering some corresponding information + * (of type V) + * + * Since XTextRange values are only comparable if they share the same + * range.getText(), we group them by these. + * + * Within such groups (partitions) we may define comparison, here + * based on (range.getStart(),range.getEnd()), where equality means identical + * ranges. + * + * For finding overlapping ranges this class proved insufficient, + * beacause it does not allow multiple values to be associated with a + * single XTextRange. The class RangeKeyedMapList solves this. + * + */ +public class RangeKeyedMap { + + private final Map> partitions; + + public RangeKeyedMap() { + this.partitions = new HashMap<>(); + } + + public boolean containsKey(XTextRange range) { + Objects.requireNonNull(range); + XText partitionKey = range.getText(); + if (!partitions.containsKey(partitionKey)) { + return false; + } + return partitions.get(partitionKey).containsKey(range); + } + + public V get(XTextRange range) { + TreeMap partition = partitions.get(range.getText()); + if (partition == null) { + return null; + } + return partition.get(range); + } + + /* + * Same as UnoTextRange.compareStartsThenEnds in logic. + */ + private static int comparator(XTextRange a, XTextRange b) { + if (a.getText() != b.getText()) { + throw new RuntimeException("comparator: got incomparable regions"); + } + + final XTextRangeCompare compare = + UnoRuntime.queryInterface(XTextRangeCompare.class, a.getText()); + + int cmpStart = (-1) * compare.compareRegionStarts(a, b); + if (cmpStart != 0) { + return cmpStart; + } + return (-1) * compare.compareRegionEnds(a, b); + } + + public V put(XTextRange range, V value) { + TreeMap partition = partitions.get(range.getText()); + if (partition == null) { + partition = new TreeMap<>(RangeKeyedMap::comparator); + partitions.put(range.getText(), partition); + } + return partition.put(range, value); + } + + /** + * @return A list of the partitions. + */ + public List> partitionValues() { + return new ArrayList<>(partitions.values()); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMapList.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMapList.java new file mode 100644 index 00000000000..9e6edd69738 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMapList.java @@ -0,0 +1,49 @@ +package org.jabref.model.openoffice.rangesort; + +import java.util.ArrayList; +import java.util.List; +import java.util.TreeMap; + +import com.sun.star.text.XTextRange; + +/* + * Partition by XTextRange.getText() and sort within the partitions a + * set of XTextRange values, while keeping their associated data + * recoverable. Allows identical XTextRange values, their data is + * collected in a list. + */ +public class RangeKeyedMapList { + + private RangeKeyedMap> partitions; + + public RangeKeyedMapList() { + this.partitions = new RangeKeyedMap<>(); + } + + public boolean containsKey(XTextRange range) { + return partitions.containsKey(range); + } + + public List get(XTextRange range) { + return partitions.get(range); + } + + public void add(XTextRange range, V value) { + List values = partitions.get(range); + if (values == null) { + values = new ArrayList<>(); + values.add(value); + partitions.put(range, values); + } else { + values.add(value); + } + } + + /** + * @return A list of the partitions. + */ + public List>> partitionValues() { + return this.partitions.partitionValues(); + } + +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlap.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlap.java new file mode 100644 index 00000000000..3edd059d7ff --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlap.java @@ -0,0 +1,16 @@ +package org.jabref.model.openoffice.rangesort; + +import java.util.List; + +/** + * Used in reporting range overlaps. + */ +public class RangeOverlap { + public final RangeOverlapKind kind; + public final List valuesForOverlappingRanges; + + public RangeOverlap(RangeOverlapKind kind, List valuesForOverlappingRanges) { + this.kind = kind; + this.valuesForOverlappingRanges = valuesForOverlappingRanges; + } +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapFinder.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapFinder.java new file mode 100644 index 00000000000..c5b74a0b42d --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapFinder.java @@ -0,0 +1,61 @@ +package org.jabref.model.openoffice.rangesort; + +import java.util.ArrayList; +import java.util.List; +import java.util.TreeMap; + +import org.jabref.model.openoffice.uno.UnoTextRange; + +import com.sun.star.text.XTextRange; + +public class RangeOverlapFinder { + /** + * Report identical, overlapping or touching ranges. + * + * For overlapping and touching, only report consecutive ranges + * and only with a single sample of otherwise identical ranges. + * + * @param atMost Limit the number of records returned to atMost. + * Zero or negative {@code atMost} means no limit. + * + * @param includeTouching Should the result contain ranges + * sharing only a boundary? + */ + public static List> findOverlappingRanges(RangeKeyedMapList input, + int atMost, + boolean includeTouching) { + List> result = new ArrayList<>(); + for (TreeMap> partition : input.partitionValues()) { + List orderedRanges = new ArrayList<>(partition.keySet()); + for (int i = 0; i < orderedRanges.size(); i++) { + XTextRange aRange = orderedRanges.get(i); + List aValues = partition.get(aRange); + if (aValues.size() > 1) { + result.add(new RangeOverlap(RangeOverlapKind.EQUAL_RANGE, aValues)); + if (atMost > 0 && result.size() >= atMost) { + return result; + } + } + if ((i + 1) < orderedRanges.size()) { + XTextRange bRange = orderedRanges.get(i + 1); + int cmp = UnoTextRange.compareStarts(aRange.getEnd(), bRange.getStart()); + if (cmp > 0 || (includeTouching && (cmp == 0))) { + // found overlap or touch + List bValues = partition.get(bRange); + List valuesForOverlappingRanges = new ArrayList<>(); + valuesForOverlappingRanges.add(aValues.get(0)); + valuesForOverlappingRanges.add(bValues.get(0)); + result.add(new RangeOverlap((cmp == 0) + ? RangeOverlapKind.TOUCH + : RangeOverlapKind.OVERLAP, + valuesForOverlappingRanges)); + } + if (atMost > 0 && result.size() >= atMost) { + return result; + } + } + } + } + return result; + } +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapKind.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapKind.java new file mode 100644 index 00000000000..2bb7f8f4af7 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapKind.java @@ -0,0 +1,14 @@ +package org.jabref.model.openoffice.rangesort; + +public enum RangeOverlapKind { + + /** The ranges share a boundary */ + TOUCH, + + /** They share some characters */ + OVERLAP, + + /** They cover the same XTextRange */ + EQUAL_RANGE +} + diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java new file mode 100644 index 00000000000..4ed651e5396 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java @@ -0,0 +1,42 @@ +package org.jabref.model.openoffice.rangesort; + +import com.sun.star.text.XTextRange; + +/** + * A simple implementation of {@code RangeSortable} + */ +public class RangeSortEntry implements RangeSortable { + + private XTextRange range; + private int indexInPosition; + private T content; + + public RangeSortEntry(XTextRange range, int indexInPosition, T content) { + this.range = range; + this.indexInPosition = indexInPosition; + this.content = content; + } + + @Override + public XTextRange getRange() { + return range; + } + + @Override + public int getIndexInPosition() { + return indexInPosition; + } + + @Override + public T getContent() { + return content; + } + + public void setRange(XTextRange r) { + range = r; + } + + public void setIndexInPosition(int i) { + indexInPosition = i; + } +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java new file mode 100644 index 00000000000..67b1fa0471d --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java @@ -0,0 +1,182 @@ +package org.jabref.model.openoffice.rangesort; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; + +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoScreenRefresh; + +import com.sun.star.awt.Point; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import com.sun.star.text.XTextViewCursor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Sort XTextRange values visually (top-down,left-to-right). + * + * Requires functional XTextViewCursor. + * + * Problem: for multicolumn layout and when viewing pages side-by-side + * in LO, the (top-down,left-to-right) order interpreted + * as-on-the-screen: an XTextRange at the top of the second + * column or second page is sorted before one at the bottom + * of the first column of the first page. + */ +public class RangeSortVisual { + + private static final Logger LOGGER = LoggerFactory.getLogger(RangeSortVisual.class); + + /** + * Sort the input {@code inputs} visually. + * + * Requires a functional {@code XTextViewCursor}. + * + * @return The input, sorted by the elements XTextRange and + * getIndexInPosition. + */ + public static List> visualSort(List> inputs, + XTextDocument doc, + FunctionalTextViewCursor fcursor) + throws + WrappedTargetException, + NoDocumentException { + + final int inputSize = inputs.size(); + + if (UnoScreenRefresh.hasControllersLocked(doc)) { + LOGGER.warn("visualSort:" + + " with ControllersLocked, viewCursor.gotoRange" + + " is probably useless"); + } + + XTextViewCursor viewCursor = fcursor.getViewCursor(); + + // find coordinates + List positions = new ArrayList<>(inputSize); + + for (RangeSortable v : inputs) { + positions.add(findPositionOfTextRange(v.getRange(), + viewCursor)); + } + + fcursor.restore(doc); + + if (positions.size() != inputSize) { + throw new RuntimeException("visualSort: positions.size() != inputSize"); + } + + // order by position + Set>> set = new TreeSet<>(); + for (int i = 0; i < inputSize; i++) { + set.add(new ComparableMark<>(positions.get(i), + inputs.get(i).getIndexInPosition(), + inputs.get(i))); + } + + if (set.size() != inputSize) { + throw new RuntimeException("visualSort: set.size() != inputSize"); + } + + // collect ordered result + List> result = new ArrayList<>(set.size()); + for (ComparableMark> mark : set) { + result.add(mark.getContent()); + } + + if (result.size() != inputSize) { + throw new RuntimeException("visualSort: result.size() != inputSize"); + } + + return result; + } + + /** + * Given a location, return its position: coordinates relative to + * the top left position of the first page of the document. + * + * Note: for text layouts with two or more columns, this gives the + * wrong order: top-down/left-to-right does not match + * reading order. + * + * Note: The "relative to the top left position of the first page" + * is meant "as it appears on the screen". + * + * In particular: when viewing pages side-by-side, the top + * half of the right page is higher than the lower half of + * the left page. Again, top-down/left-to-right does not + * match reading order. + * + * @param range Location. + * @param cursor To get the position, we need az XTextViewCursor. + * It will be moved to the range. + */ + private static Point findPositionOfTextRange(XTextRange range, XTextViewCursor cursor) { + cursor.gotoRange(range, false); + return cursor.getPosition(); + } + + /** + * A reference mark name paired with its visual position. + * + * Comparison is based on (Y,X,indexInPosition): vertical compared + * first, horizontal second, indexInPosition third. + * + * Used for sorting reference marks by their visual positions. + */ + private static class ComparableMark implements Comparable> { + + private final Point position; + private final int indexInPosition; + private final T content; + + public ComparableMark(Point position, int indexInPosition, T content) { + this.position = position; + this.indexInPosition = indexInPosition; + this.content = content; + } + + @Override + public int compareTo(ComparableMark other) { + + if (position.Y != other.position.Y) { + return position.Y - other.position.Y; + } + if (position.X != other.position.X) { + return position.X - other.position.X; + } + return indexInPosition - other.indexInPosition; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o instanceof ComparableMark) { + ComparableMark other = (ComparableMark) o; + return ((this.position.X == other.position.X) + && (this.position.Y == other.position.Y) + && (this.indexInPosition == other.indexInPosition) + && Objects.equals(this.content, other.content)); + } + return false; + } + + public T getContent() { + return content; + } + + @Override + public int hashCode() { + return Objects.hash(position, indexInPosition, content); + } + } + +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java new file mode 100644 index 00000000000..39a16b4ecb2 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java @@ -0,0 +1,24 @@ +package org.jabref.model.openoffice.rangesort; + +import com.sun.star.text.XTextRange; + +/** + * This is what {@code visualSort} needs in its input. + */ +public interface RangeSortable { + + /** The XTextRange + * + * For citation marks in footnotes this may be the range of the + * footnote mark. + */ + public XTextRange getRange(); + + /** + * For citation marks in footnotes this may provide order within + * the footnote. + */ + public int getIndexInPosition(); + + public T getContent(); +} From 314902cc8720f5228d08a5c0fe21369e1150f377 Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 10:33:20 +0200 Subject: [PATCH 012/103] delNamesArray size correction --- .../java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java index f062bed7c40..298329f3a43 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java @@ -604,7 +604,7 @@ void apply(XTextCursor cursor) { } // namesArray must be alphabetically sorted. String[] namesArray = names.toArray(new String[names.size()]); - String[] delNamesArray = delNames.toArray(new String[names.size()]); + String[] delNamesArray = delNames.toArray(new String[delNames.size()]); mpss.setPropertiesToDefault(delNamesArray); mps.setPropertyValues(namesArray, values.toArray()); } catch (UnknownPropertyException ex) { From dfe18bc1149bd8b67d0791de228f385172e7d415 Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 10:34:14 +0200 Subject: [PATCH 013/103] rangeSort update --- .../openoffice/rangesort/RangeHolder.java | 7 + .../openoffice/rangesort/RangeKeyedMap.java | 90 ------------- .../rangesort/RangeKeyedMapList.java | 49 ------- .../rangesort/RangeOverlapBetween.java | 91 +++++++++++++ .../rangesort/RangeOverlapFinder.java | 61 --------- .../rangesort/RangeOverlapWithin.java | 120 ++++++++++++++++++ .../model/openoffice/rangesort/RangeSet.java | 48 +++++++ .../model/openoffice/rangesort/RangeSort.java | 90 +++++++++++++ .../openoffice/rangesort/RangeSortVisual.java | 16 ++- .../openoffice/rangesort/RangeSortable.java | 2 +- 10 files changed, 366 insertions(+), 208 deletions(-) create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeHolder.java delete mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMap.java delete mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMapList.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java delete mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapFinder.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java create mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeHolder.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeHolder.java new file mode 100644 index 00000000000..cae6f99e34e --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeHolder.java @@ -0,0 +1,7 @@ +package org.jabref.model.openoffice.rangesort; + +import com.sun.star.text.XTextRange; + +public interface RangeHolder { + XTextRange getRange(); +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMap.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMap.java deleted file mode 100644 index 094705f5fa8..00000000000 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMap.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.jabref.model.openoffice.rangesort; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.TreeMap; - -import com.sun.star.text.XText; -import com.sun.star.text.XTextRange; -import com.sun.star.text.XTextRangeCompare; -import com.sun.star.uno.UnoRuntime; - -/** - * Purpose: in order to check overlaps of XTextRange values, sort - * them, and allow recovering some corresponding information - * (of type V) - * - * Since XTextRange values are only comparable if they share the same - * range.getText(), we group them by these. - * - * Within such groups (partitions) we may define comparison, here - * based on (range.getStart(),range.getEnd()), where equality means identical - * ranges. - * - * For finding overlapping ranges this class proved insufficient, - * beacause it does not allow multiple values to be associated with a - * single XTextRange. The class RangeKeyedMapList solves this. - * - */ -public class RangeKeyedMap { - - private final Map> partitions; - - public RangeKeyedMap() { - this.partitions = new HashMap<>(); - } - - public boolean containsKey(XTextRange range) { - Objects.requireNonNull(range); - XText partitionKey = range.getText(); - if (!partitions.containsKey(partitionKey)) { - return false; - } - return partitions.get(partitionKey).containsKey(range); - } - - public V get(XTextRange range) { - TreeMap partition = partitions.get(range.getText()); - if (partition == null) { - return null; - } - return partition.get(range); - } - - /* - * Same as UnoTextRange.compareStartsThenEnds in logic. - */ - private static int comparator(XTextRange a, XTextRange b) { - if (a.getText() != b.getText()) { - throw new RuntimeException("comparator: got incomparable regions"); - } - - final XTextRangeCompare compare = - UnoRuntime.queryInterface(XTextRangeCompare.class, a.getText()); - - int cmpStart = (-1) * compare.compareRegionStarts(a, b); - if (cmpStart != 0) { - return cmpStart; - } - return (-1) * compare.compareRegionEnds(a, b); - } - - public V put(XTextRange range, V value) { - TreeMap partition = partitions.get(range.getText()); - if (partition == null) { - partition = new TreeMap<>(RangeKeyedMap::comparator); - partitions.put(range.getText(), partition); - } - return partition.put(range, value); - } - - /** - * @return A list of the partitions. - */ - public List> partitionValues() { - return new ArrayList<>(partitions.values()); - } -} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMapList.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMapList.java deleted file mode 100644 index 9e6edd69738..00000000000 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMapList.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.jabref.model.openoffice.rangesort; - -import java.util.ArrayList; -import java.util.List; -import java.util.TreeMap; - -import com.sun.star.text.XTextRange; - -/* - * Partition by XTextRange.getText() and sort within the partitions a - * set of XTextRange values, while keeping their associated data - * recoverable. Allows identical XTextRange values, their data is - * collected in a list. - */ -public class RangeKeyedMapList { - - private RangeKeyedMap> partitions; - - public RangeKeyedMapList() { - this.partitions = new RangeKeyedMap<>(); - } - - public boolean containsKey(XTextRange range) { - return partitions.containsKey(range); - } - - public List get(XTextRange range) { - return partitions.get(range); - } - - public void add(XTextRange range, V value) { - List values = partitions.get(range); - if (values == null) { - values = new ArrayList<>(); - values.add(value); - partitions.put(range, values); - } else { - values.add(value); - } - } - - /** - * @return A list of the partitions. - */ - public List>> partitionValues() { - return this.partitions.partitionValues(); - } - -} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java new file mode 100644 index 00000000000..35d2d006fab --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java @@ -0,0 +1,91 @@ +package org.jabref.model.openoffice.rangesort; + +import java.util.ArrayList; +import java.util.List; + +import org.jabref.model.openoffice.uno.UnoCast; +import org.jabref.model.openoffice.uno.UnoTextRange; +import org.jabref.model.openoffice.util.OOTuple3; + +import com.sun.star.text.XText; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import com.sun.star.text.XTextRangeCompare; + +public class RangeOverlapBetween { + + private RangeOverlapBetween() { } + + /** + * Check for any overlap between two sets of XTextRange values. + * + * Assume fewHolders is small (usually 1 elements for checking the cursor) + * Returns on first problem found. + */ + public static + List> findFirst(XTextDocument doc, + List fewHolders, + List manyHolders, + boolean includeTouching) { + + List> result = new ArrayList<>(); + + if (fewHolders.size() == 0) { + return result; + } + + List> fewTuples = + new ArrayList<>(fewHolders.size()); + + for (V aHolder : fewHolders) { + XText aText = aHolder.getRange().getText(); + fewTuples.add(new OOTuple3<>(aText, + UnoCast.unoQI(XTextRangeCompare.class, aText), + aHolder)); + } + + for (V bHolder : manyHolders) { + XTextRange bRange = bHolder.getRange(); + XText bText = bRange.getText(); + XTextRange bRangeStart = bRange.getStart(); + XTextRange bRangeEnd = bRange.getEnd(); + + for (OOTuple3 tup : fewTuples) { + XText aText = tup.a; + XTextRangeCompare cmp = tup.b; + V aHolder = tup.c; + XTextRange aRange = aHolder.getRange(); + if (aText != bText) { + continue; + } + int abEndToStart = -1 * cmp.compareRegionStarts(aRange.getEnd(), bRangeStart); + if (abEndToStart < 0 || (!includeTouching && (abEndToStart == 0))) { + continue; + } + int baEndToStart = -1 * cmp.compareRegionStarts(bRangeEnd, aRange.getStart()); + if (baEndToStart < 0 || (!includeTouching && (baEndToStart == 0))) { + continue; + } + + boolean equal = UnoTextRange.compareStartsThenEnds(aRange, bRange) == 0; + boolean touching = (abEndToStart == 0 || baEndToStart == 0); + + // In case of two equal collapsed ranges there is an + // ambiguity : TOUCH or EQUAL_RANGE ? + // We return EQUAL_RANGE + RangeOverlapKind kind = + (equal ? RangeOverlapKind.EQUAL_RANGE + : (touching ? RangeOverlapKind.TOUCH + : RangeOverlapKind.OVERLAP)); + + List valuesForOverlappingRanges = new ArrayList<>(); + valuesForOverlappingRanges.add(aHolder); + valuesForOverlappingRanges.add(bHolder); + + result.add(new RangeOverlap(kind, valuesForOverlappingRanges)); + return result; + } + } + return result; + } +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapFinder.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapFinder.java deleted file mode 100644 index c5b74a0b42d..00000000000 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapFinder.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.jabref.model.openoffice.rangesort; - -import java.util.ArrayList; -import java.util.List; -import java.util.TreeMap; - -import org.jabref.model.openoffice.uno.UnoTextRange; - -import com.sun.star.text.XTextRange; - -public class RangeOverlapFinder { - /** - * Report identical, overlapping or touching ranges. - * - * For overlapping and touching, only report consecutive ranges - * and only with a single sample of otherwise identical ranges. - * - * @param atMost Limit the number of records returned to atMost. - * Zero or negative {@code atMost} means no limit. - * - * @param includeTouching Should the result contain ranges - * sharing only a boundary? - */ - public static List> findOverlappingRanges(RangeKeyedMapList input, - int atMost, - boolean includeTouching) { - List> result = new ArrayList<>(); - for (TreeMap> partition : input.partitionValues()) { - List orderedRanges = new ArrayList<>(partition.keySet()); - for (int i = 0; i < orderedRanges.size(); i++) { - XTextRange aRange = orderedRanges.get(i); - List aValues = partition.get(aRange); - if (aValues.size() > 1) { - result.add(new RangeOverlap(RangeOverlapKind.EQUAL_RANGE, aValues)); - if (atMost > 0 && result.size() >= atMost) { - return result; - } - } - if ((i + 1) < orderedRanges.size()) { - XTextRange bRange = orderedRanges.get(i + 1); - int cmp = UnoTextRange.compareStarts(aRange.getEnd(), bRange.getStart()); - if (cmp > 0 || (includeTouching && (cmp == 0))) { - // found overlap or touch - List bValues = partition.get(bRange); - List valuesForOverlappingRanges = new ArrayList<>(); - valuesForOverlappingRanges.add(aValues.get(0)); - valuesForOverlappingRanges.add(bValues.get(0)); - result.add(new RangeOverlap((cmp == 0) - ? RangeOverlapKind.TOUCH - : RangeOverlapKind.OVERLAP, - valuesForOverlappingRanges)); - } - if (atMost > 0 && result.size() >= atMost) { - return result; - } - } - } - } - return result; - } -} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java new file mode 100644 index 00000000000..62ee6d82ca0 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java @@ -0,0 +1,120 @@ +package org.jabref.model.openoffice.rangesort; + +import java.util.ArrayList; +import java.util.List; + +import org.jabref.model.openoffice.uno.UnoCast; +import org.jabref.model.openoffice.uno.UnoTextRange; + +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import com.sun.star.text.XTextRangeCompare; + +public class RangeOverlapWithin { + + private RangeOverlapWithin() { } + + /** + * Report identical, overlapping or touching ranges between + * elements of rangeHolders. + * + * For overlapping and touching, only report consecutive ranges + * and only with a single sample of otherwise identical ranges. + * + * @param reportAtMost Limit the number of records returned to atMost. + * Zero {@code reportAtMost} means no limit. + * + * @param includeTouching Should the result contain ranges + * sharing only a boundary? + */ + public static + List> findOverlappingRanges(XTextDocument doc, + List rangeHolders, + boolean includeTouching, + int reportAtMost) { + + RangeSort.RangePartitions partitions = RangeSort.partitionAndSortRanges(rangeHolders); + + List> overlaps = findOverlappingRanges(partitions, reportAtMost, includeTouching); + + return overlaps; + } + + /** + * Report identical, overlapping or touching ranges. + * + * For overlapping and touching, only report consecutive ranges + * and only with a single sample of otherwise identical ranges. + * + * @param atMost Limit the number of records returned to atMost. + * Zero {@code atMost} means no limit. + * + * @param includeTouching Should the result contain ranges + * sharing only a boundary? + */ + public static + List> findOverlappingRanges(RangeSort.RangePartitions input, + int atMost, + boolean includeTouching) { + assert atMost >= 0; + + List> result = new ArrayList<>(); + + for (List partition : input.getPartitions()) { + if (partition.size() == 0) { + continue; + } + XTextRangeCompare cmp = UnoCast.unoQI(XTextRangeCompare.class, + partition.get(0).getRange().getText()); + + for (int i = 0; i < (partition.size() - 1); i++) { + V aHolder = partition.get(i); + V bHolder = partition.get(i + 1); + XTextRange aRange = aHolder.getRange(); + XTextRange bRange = bHolder.getRange(); + + // check equal values + int cmpResult = UnoTextRange.compareStartsThenEndsUnsafe(cmp, aRange, bRange); + if (cmpResult == 0) { + List aValues = new ArrayList<>(); + aValues.add(aHolder); + // aValues.add(bHolder); + // collect those equal + while (i < (partition.size() - 1) && + UnoTextRange.compareStartsThenEndsUnsafe( + cmp, + aRange, + partition.get(i + 1).getRange()) == 0) { + bHolder = partition.get(i + 1); + aValues.add(bHolder); + i++; + } + result.add(new RangeOverlap(RangeOverlapKind.EQUAL_RANGE, aValues)); + if (atMost > 0 && result.size() >= atMost) { + return result; + } + continue; + } + + // Not equal, and (a <= b) since sorted. + // Check if a.end >= b.start + cmpResult = UnoTextRange.compareStartsUnsafe(cmp, aRange.getEnd(), bRange.getStart()); + if (cmpResult > 0 || (includeTouching && (cmpResult == 0))) { + // found overlap or touch + List valuesForOverlappingRanges = new ArrayList<>(); + valuesForOverlappingRanges.add(aHolder); + valuesForOverlappingRanges.add(bHolder); + result.add(new RangeOverlap((cmpResult == 0) + ? RangeOverlapKind.TOUCH + : RangeOverlapKind.OVERLAP, + valuesForOverlappingRanges)); + } + if (atMost > 0 && result.size() >= atMost) { + return result; + } + } + } + return result; + } + +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java new file mode 100644 index 00000000000..f7fbe37ba25 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java @@ -0,0 +1,48 @@ +package org.jabref.model.openoffice.rangesort; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.TreeSet; + +import org.jabref.model.openoffice.uno.UnoTextRange; + +import com.sun.star.text.XText; +import com.sun.star.text.XTextRange; + +public class RangeSet { + + private final Map> partitions; + + public RangeSet() { + this.partitions = new HashMap<>(); + } + + public boolean contains(XTextRange range) { + Objects.requireNonNull(range); + XText partitionKey = range.getText(); + if (!this.partitions.containsKey(partitionKey)) { + return false; + } + return partitions.get(partitionKey).contains(range); + } + + /* return false if already contained */ + public boolean add(XTextRange range) { + TreeSet partition = partitions.get(range.getText()); + if (partition == null) { + partition = new TreeSet<>(UnoTextRange::compareStartsThenEnds); + partitions.put(range.getText(), partition); + } + return partition.add(range); + } + + /** + * @return A list of the partitions. + */ + public List> partitionValues() { + return new ArrayList<>(partitions.values()); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java new file mode 100644 index 00000000000..2f5daa0e1aa --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java @@ -0,0 +1,90 @@ +package org.jabref.model.openoffice.rangesort; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.jabref.model.openoffice.uno.UnoCast; +import org.jabref.model.openoffice.uno.UnoTextRange; + +import com.sun.star.text.XText; +import com.sun.star.text.XTextRangeCompare; + +public class RangeSort { + + /* + * Sort within a partition + */ + + public static class HolderComparatorWithinPartition implements Comparator { + + XTextRangeCompare cmp; + + HolderComparatorWithinPartition(XText text) { + cmp = UnoCast.unoQI(XTextRangeCompare.class, text); + } + + /* + * Assumes a and b belong to the same XText as cmp. + */ + @Override + public int compare(RangeHolder a, RangeHolder b) { + return UnoTextRange.compareStartsThenEndsUnsafe(cmp, a.getRange(), b.getRange()); + } + } + + public static + void sortWithinPartition(List rangeHolders) { + if (rangeHolders.isEmpty()) { + return; + } + XText text = rangeHolders.get(0).getRange().getText(); + rangeHolders.sort(new HolderComparatorWithinPartition(text)); + } + + /* + * Partitioning + */ + + public static class RangePartitions { + private final Map> partitions; + + public RangePartitions() { + this.partitions = new HashMap<>(); + } + + public void add(V holder) { + XText partitionKey = holder.getRange().getText(); + List partition = partitions.get(partitionKey); + if (partition == null) { + partition = new ArrayList<>(); + partitions.put(partitionKey, partition); + } + partition.add(holder); + } + + public List> getPartitions() { + return new ArrayList<>(partitions.values()); + } + } + + public static + RangePartitions partitionRanges(List holders) { + RangePartitions result = new RangePartitions<>(); + for (V holder : holders) { + result.add(holder); + } + return result; + } + + public static + RangePartitions partitionAndSortRanges(List holders) { + RangePartitions result = partitionRanges(holders); + for (List partition : result.getPartitions()) { + sortWithinPartition(partition); + } + return result; + } +} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java index 67b1fa0471d..2131c3cecb9 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java @@ -1,10 +1,9 @@ package org.jabref.model.openoffice.rangesort; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.Set; -import java.util.TreeSet; import org.jabref.model.openoffice.uno.NoDocumentException; import org.jabref.model.openoffice.uno.UnoScreenRefresh; @@ -53,18 +52,19 @@ public static List> visualSort(List> input LOGGER.warn("visualSort:" + " with ControllersLocked, viewCursor.gotoRange" + " is probably useless"); + throw new RuntimeException("visualSort:" + + " with ControllersLocked, viewCursor.gotoRange" + + " is probably useless"); } XTextViewCursor viewCursor = fcursor.getViewCursor(); // find coordinates List positions = new ArrayList<>(inputSize); - for (RangeSortable v : inputs) { positions.add(findPositionOfTextRange(v.getRange(), viewCursor)); } - fcursor.restore(doc); if (positions.size() != inputSize) { @@ -72,12 +72,14 @@ public static List> visualSort(List> input } // order by position - Set>> set = new TreeSet<>(); + ArrayList>> set = new ArrayList<>(inputSize); for (int i = 0; i < inputSize; i++) { + RangeSortable input = inputs.get(i); set.add(new ComparableMark<>(positions.get(i), - inputs.get(i).getIndexInPosition(), - inputs.get(i))); + input.getIndexInPosition(), + input)); } + Collections.sort(set); if (set.size() != inputSize) { throw new RuntimeException("visualSort: set.size() != inputSize"); diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java index 39a16b4ecb2..66e17a5b35b 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java @@ -5,7 +5,7 @@ /** * This is what {@code visualSort} needs in its input. */ -public interface RangeSortable { +public interface RangeSortable extends RangeHolder { /** The XTextRange * From 6e4c7c299a6033816486ed76c5e492433adb4563 Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 11:02:12 +0200 Subject: [PATCH 014/103] cleanup --- .../openoffice/rangesort/RangeKeyedMap.java | 90 ------------------- .../rangesort/RangeKeyedMapList.java | 49 ---------- .../rangesort/RangeOverlapFinder.java | 61 ------------- 3 files changed, 200 deletions(-) delete mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMap.java delete mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMapList.java delete mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapFinder.java diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMap.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMap.java deleted file mode 100644 index 094705f5fa8..00000000000 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMap.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.jabref.model.openoffice.rangesort; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.TreeMap; - -import com.sun.star.text.XText; -import com.sun.star.text.XTextRange; -import com.sun.star.text.XTextRangeCompare; -import com.sun.star.uno.UnoRuntime; - -/** - * Purpose: in order to check overlaps of XTextRange values, sort - * them, and allow recovering some corresponding information - * (of type V) - * - * Since XTextRange values are only comparable if they share the same - * range.getText(), we group them by these. - * - * Within such groups (partitions) we may define comparison, here - * based on (range.getStart(),range.getEnd()), where equality means identical - * ranges. - * - * For finding overlapping ranges this class proved insufficient, - * beacause it does not allow multiple values to be associated with a - * single XTextRange. The class RangeKeyedMapList solves this. - * - */ -public class RangeKeyedMap { - - private final Map> partitions; - - public RangeKeyedMap() { - this.partitions = new HashMap<>(); - } - - public boolean containsKey(XTextRange range) { - Objects.requireNonNull(range); - XText partitionKey = range.getText(); - if (!partitions.containsKey(partitionKey)) { - return false; - } - return partitions.get(partitionKey).containsKey(range); - } - - public V get(XTextRange range) { - TreeMap partition = partitions.get(range.getText()); - if (partition == null) { - return null; - } - return partition.get(range); - } - - /* - * Same as UnoTextRange.compareStartsThenEnds in logic. - */ - private static int comparator(XTextRange a, XTextRange b) { - if (a.getText() != b.getText()) { - throw new RuntimeException("comparator: got incomparable regions"); - } - - final XTextRangeCompare compare = - UnoRuntime.queryInterface(XTextRangeCompare.class, a.getText()); - - int cmpStart = (-1) * compare.compareRegionStarts(a, b); - if (cmpStart != 0) { - return cmpStart; - } - return (-1) * compare.compareRegionEnds(a, b); - } - - public V put(XTextRange range, V value) { - TreeMap partition = partitions.get(range.getText()); - if (partition == null) { - partition = new TreeMap<>(RangeKeyedMap::comparator); - partitions.put(range.getText(), partition); - } - return partition.put(range, value); - } - - /** - * @return A list of the partitions. - */ - public List> partitionValues() { - return new ArrayList<>(partitions.values()); - } -} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMapList.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMapList.java deleted file mode 100644 index 9e6edd69738..00000000000 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeKeyedMapList.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.jabref.model.openoffice.rangesort; - -import java.util.ArrayList; -import java.util.List; -import java.util.TreeMap; - -import com.sun.star.text.XTextRange; - -/* - * Partition by XTextRange.getText() and sort within the partitions a - * set of XTextRange values, while keeping their associated data - * recoverable. Allows identical XTextRange values, their data is - * collected in a list. - */ -public class RangeKeyedMapList { - - private RangeKeyedMap> partitions; - - public RangeKeyedMapList() { - this.partitions = new RangeKeyedMap<>(); - } - - public boolean containsKey(XTextRange range) { - return partitions.containsKey(range); - } - - public List get(XTextRange range) { - return partitions.get(range); - } - - public void add(XTextRange range, V value) { - List values = partitions.get(range); - if (values == null) { - values = new ArrayList<>(); - values.add(value); - partitions.put(range, values); - } else { - values.add(value); - } - } - - /** - * @return A list of the partitions. - */ - public List>> partitionValues() { - return this.partitions.partitionValues(); - } - -} diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapFinder.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapFinder.java deleted file mode 100644 index c5b74a0b42d..00000000000 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapFinder.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.jabref.model.openoffice.rangesort; - -import java.util.ArrayList; -import java.util.List; -import java.util.TreeMap; - -import org.jabref.model.openoffice.uno.UnoTextRange; - -import com.sun.star.text.XTextRange; - -public class RangeOverlapFinder { - /** - * Report identical, overlapping or touching ranges. - * - * For overlapping and touching, only report consecutive ranges - * and only with a single sample of otherwise identical ranges. - * - * @param atMost Limit the number of records returned to atMost. - * Zero or negative {@code atMost} means no limit. - * - * @param includeTouching Should the result contain ranges - * sharing only a boundary? - */ - public static List> findOverlappingRanges(RangeKeyedMapList input, - int atMost, - boolean includeTouching) { - List> result = new ArrayList<>(); - for (TreeMap> partition : input.partitionValues()) { - List orderedRanges = new ArrayList<>(partition.keySet()); - for (int i = 0; i < orderedRanges.size(); i++) { - XTextRange aRange = orderedRanges.get(i); - List aValues = partition.get(aRange); - if (aValues.size() > 1) { - result.add(new RangeOverlap(RangeOverlapKind.EQUAL_RANGE, aValues)); - if (atMost > 0 && result.size() >= atMost) { - return result; - } - } - if ((i + 1) < orderedRanges.size()) { - XTextRange bRange = orderedRanges.get(i + 1); - int cmp = UnoTextRange.compareStarts(aRange.getEnd(), bRange.getStart()); - if (cmp > 0 || (includeTouching && (cmp == 0))) { - // found overlap or touch - List bValues = partition.get(bRange); - List valuesForOverlappingRanges = new ArrayList<>(); - valuesForOverlappingRanges.add(aValues.get(0)); - valuesForOverlappingRanges.add(bValues.get(0)); - result.add(new RangeOverlap((cmp == 0) - ? RangeOverlapKind.TOUCH - : RangeOverlapKind.OVERLAP, - valuesForOverlappingRanges)); - } - if (atMost > 0 && result.size() >= atMost) { - return result; - } - } - } - } - return result; - } -} From 9388b2a1e6373ef139bd1e4366f3353d2b197036 Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 11:21:54 +0200 Subject: [PATCH 015/103] style additions --- .../logic/openoffice/style/OOBibStyle.java | 457 ++++++++++- .../style/OOBibStyleGetCitationMarker.java | 767 ++++++++++++++++++ .../style/OOBibStyleGetNumCitationMarker.java | 278 +++++++ .../style/OOFormatBibliography.java | 197 +++++ .../logic/openoffice/style/OOProcess.java | 90 ++ .../style/OOProcessAuthorYearMarkers.java | 162 ++++ .../style/OOProcessCitationKeyMarkers.java | 30 + .../style/OOProcessNumericMarkers.java | 43 + .../logic/openoffice/style/StyleLoader.java | 2 +- .../model/openoffice/style/Citation.java | 142 ++++ .../model/openoffice/style/CitationGroup.java | 157 ++++ .../openoffice/style/CitationGroupId.java | 19 + .../openoffice/style/CitationGroups.java | 315 +++++++ .../style/CitationLookupResult.java | 49 ++ .../openoffice/style/CitationMarkerEntry.java | 30 + .../style/CitationMarkerNormEntry.java | 24 + .../style/CitationMarkerNumericBibEntry.java | 19 + .../style/CitationMarkerNumericEntry.java | 20 + .../model/openoffice/style/CitationPath.java | 17 + .../model/openoffice/style/CitationType.java | 24 + .../model/openoffice/style/CitedKey.java | 141 ++++ .../model/openoffice/style/CitedKeys.java | 84 ++ .../openoffice/style/ComparableCitation.java | 13 + .../openoffice/style/ComparableCitedKey.java | 16 + .../openoffice/style/CompareCitation.java | 30 + .../openoffice/style/CompareCitedKey.java | 41 + .../style/NonUniqueCitationMarker.java | 15 + .../model/openoffice/style/OODataModel.java | 38 + .../model/openoffice/style/PageInfo.java | 47 ++ .../openoffice/style/OOBibStyleTest.java | 401 +++++++++ .../style/OOBibStyleTestHelper.java | 359 ++++++++ 31 files changed, 4022 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java create mode 100644 src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java create mode 100644 src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java create mode 100644 src/main/java/org/jabref/logic/openoffice/style/OOProcess.java create mode 100644 src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java create mode 100644 src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java create mode 100644 src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/Citation.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/CitationGroup.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/CitationGroups.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/CitationMarkerEntry.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/CitationMarkerNormEntry.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/CitationMarkerNumericBibEntry.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/CitationMarkerNumericEntry.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/CitationPath.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/CitationType.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/CitedKey.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/CitedKeys.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/ComparableCitation.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/ComparableCitedKey.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/CompareCitation.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/NonUniqueCitationMarker.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/OODataModel.java create mode 100644 src/main/java/org/jabref/model/openoffice/style/PageInfo.java create mode 100644 src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index 561099afe96..113cef246e2 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -31,9 +31,19 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.FieldFactory; +import org.jabref.model.entry.field.OrFields; import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.types.EntryType; import org.jabref.model.entry.types.EntryTypeFactory; +import org.jabref.model.openoffice.ootext.OOFormat; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.CitationMarkerEntry; +import org.jabref.model.openoffice.style.CitationMarkerNormEntry; +import org.jabref.model.openoffice.style.CitationMarkerNumericBibEntry; +import org.jabref.model.openoffice.style.CitationMarkerNumericEntry; +import org.jabref.model.openoffice.style.NonUniqueCitationMarker; +import org.jabref.model.openoffice.style.PageInfo; +import org.jabref.model.openoffice.util.OOListUtil; import org.jabref.model.strings.StringUtil; import org.slf4j.Logger; @@ -84,6 +94,22 @@ public class OOBibStyle implements Comparable { private static final String CITATION_CHARACTER_FORMAT = "CitationCharacterFormat"; private static final String FORMAT_CITATIONS = "FormatCitations"; private static final String GROUPED_NUMBERS_SEPARATOR = "GroupedNumbersSeparator"; + + // These two can do what ItalicCitations, BoldCitations, + // SuperscriptCitations and SubscriptCitations were supposed to do, + // as well as underline smallcaps and strikeout. + private static final String CITATION_GROUP_MARKUP_BEFORE = "CitationGroupMarkupBefore"; + private static final String CITATION_GROUP_MARKUP_AFTER = "CitationGroupMarkupAfter"; + + private static final String AUTHORS_PART_MARKUP_BEFORE = "AuthorsPartMarkupBefore"; + private static final String AUTHORS_PART_MARKUP_AFTER = "AuthorsPartMarkupAfter"; + + private static final String AUTHOR_NAMES_LIST_MARKUP_BEFORE = "AuthorNamesListMarkupBefore"; + private static final String AUTHOR_NAMES_LIST_MARKUP_AFTER = "AuthorNamesListMarkupAfter"; + + private static final String AUTHOR_NAME_MARKUP_BEFORE = "AuthorNameMarkupBefore"; + private static final String AUTHOR_NAME_MARKUP_AFTER = "AuthorNameMarkupAfter"; + private static final String PAGE_INFO_SEPARATOR = "PageInfoSeparator"; private static final String CITATION_SEPARATOR = "CitationSeparator"; private static final String IN_TEXT_YEAR_SEPARATOR = "InTextYearSeparator"; @@ -157,11 +183,24 @@ private void setDefaultProperties() { properties.put(IS_NUMBER_ENTRIES, Boolean.FALSE); properties.put(BRACKET_BEFORE, "["); properties.put(BRACKET_AFTER, "]"); - properties.put(REFERENCE_PARAGRAPH_FORMAT, "Default"); + properties.put(REFERENCE_PARAGRAPH_FORMAT, "Standard"); properties.put(REFERENCE_HEADER_PARAGRAPH_FORMAT, "Heading 1"); // Set default properties for the citation marker: citProperties.put(AUTHOR_FIELD, FieldFactory.serializeOrFields(StandardField.AUTHOR, StandardField.EDITOR)); + + citProperties.put(CITATION_GROUP_MARKUP_BEFORE, ""); + citProperties.put(CITATION_GROUP_MARKUP_AFTER, ""); + + citProperties.put(AUTHORS_PART_MARKUP_BEFORE, ""); + citProperties.put(AUTHORS_PART_MARKUP_AFTER, ""); + + citProperties.put(AUTHOR_NAMES_LIST_MARKUP_BEFORE, ""); + citProperties.put(AUTHOR_NAMES_LIST_MARKUP_AFTER, ""); + + citProperties.put(AUTHOR_NAME_MARKUP_BEFORE, ""); + citProperties.put(AUTHOR_NAME_MARKUP_AFTER, ""); + citProperties.put(YEAR_FIELD, StandardField.YEAR.getName()); citProperties.put(MAX_AUTHORS, 3); citProperties.put(MAX_AUTHORS_FIRST, -1); @@ -178,7 +217,7 @@ private void setDefaultProperties() { citProperties.put(GROUPED_NUMBERS_SEPARATOR, "-"); citProperties.put(MINIMUM_GROUPING_COUNT, 3); citProperties.put(FORMAT_CITATIONS, Boolean.FALSE); - citProperties.put(CITATION_CHARACTER_FORMAT, "Default"); + citProperties.put(CITATION_CHARACTER_FORMAT, "Standard"); citProperties.put(ITALIC_CITATIONS, Boolean.FALSE); citProperties.put(BOLD_CITATIONS, Boolean.FALSE); citProperties.put(SUPERSCRIPT_CITATIONS, Boolean.FALSE); @@ -379,8 +418,8 @@ private void handlePropertiesLine(String line, Map map) { value = value.trim().substring(1, value.trim().length() - 1); } Object toSet = value; - if (NUM_PATTERN.matcher(value).matches()) { - toSet = Integer.parseInt(value); + if (NUM_PATTERN.matcher(value.trim()).matches()) { + toSet = Integer.parseInt(value.trim()); } else if ("true".equalsIgnoreCase(value.trim())) { toSet = Boolean.TRUE; } else if ("false".equalsIgnoreCase(value.trim())) { @@ -408,6 +447,7 @@ public Layout getReferenceFormat(EntryType type) { } } + /* begin_old */ /** * Format a number-based citation marker for the given number. * @@ -474,7 +514,9 @@ public String getNumCitationMarker(List number, int minGroupingCount, b sb.append(bracketAfter); return sb.toString(); } + /* end_old */ + /* begin_old */ /** * Format the marker for the in-text citation according to this BIB style. Uniquefier letters are added as * provided by the uniquefiers argument. If successive entries within the citation are uniquefied from each other, @@ -552,7 +594,9 @@ public String getCitationMarker(List entries, Map entries, String[] uniquefiers, int from, int t } uniquefiers[from] = sb.toString(); } + /* end_old */ + /* begin_old */ /** * This method produces (Author, year) style citation strings in many different forms. * @@ -623,7 +669,9 @@ private String getAuthorYearParenthesisMarker(List entries, Map entries, Map getBibLayout() { + return bibLayout; + } + + protected Map getProperties() { + return properties; + } + + protected Map getCitProperties() { + return citProperties; + } + + protected void addJournal(String s) { + journals.add(s); + } + + protected void setLocalCopy(String s) { + localCopy = s; + } + + protected void setName(String s) { + name = s; + } + + protected boolean getIsDefaultLayoutPresent() { + return isDefaultLayoutPresent; + } + + protected void setIsDefaultLayoutPresent(boolean b) { + isDefaultLayoutPresent = b; + } + + protected void setValid(boolean b) { + valid = b; + } + + protected LayoutFormatterPreferences getPrefs() { + return prefs; + } + + protected void setDefaultBibLayout(Layout l) { + defaultBibLayout = l; + } + + /** + * Format a number-based citation marker for the given entries. + * + * @return The text for the citation. + */ + public OOText getNumCitationMarker2(List entries) { + final int minGroupingCount = this.getMinimumGroupingCount(); + return OOBibStyleGetNumCitationMarker.getNumCitationMarker2(this, + entries, + minGroupingCount); + } + + /** + * For some tests we need to override minGroupingCount. + */ + public OOText getNumCitationMarker2(List entries, + int minGroupingCount) { + return OOBibStyleGetNumCitationMarker.getNumCitationMarker2(this, + entries, + minGroupingCount); + } + + /** + * Format a number-based bibliography label for the given number. + */ + public OOText getNumCitationMarkerForBibliography(CitationMarkerNumericBibEntry entry) { + return OOBibStyleGetNumCitationMarker.getNumCitationMarkerForBibliography(this, entry); + } + + /** + * Make sure that (1) we have exactly one entry for each + * citation, (2) each entry is either Optional.empty or its content is not empty when trimmed. + * + * As a special case: pageInfos may be null. In this case + * the result is a list filled with Optional.empty() values. + */ + static List> + normalizePageInfos(List> pageInfos, int nCitations) { + + // translate null to all-empty + if (pageInfos == null) { + List> res = new ArrayList<>(nCitations); + for (int i = 0; i < nCitations; i++) { + res.add(Optional.empty()); + } + return res; + } + + // not null, check size + if (pageInfos.size() != nCitations) { + throw new RuntimeException("normalizePageInfos: pageInfos.size() != nCitations"); + } + + // not null, normalize elementwise + return OOListUtil.map(pageInfos, PageInfo::normalizePageInfo); + } + + public OOText getNormalizedCitationMarker(CitationMarkerNormEntry ce) { + return OOBibStyleGetCitationMarker.getNormalizedCitationMarker(this, ce, Optional.empty()); + } + + /** + * Format the marker for the in-text citation according to this + * BIB style. Uniquefier letters are added as provided by the + * citationMarkerEntries argument. If successive entries within + * the citation are uniquefied from each other, this method will + * perform a grouping of these entries. + * + * If successive entries within the citation are uniquefied from + * each other, this method will perform a grouping of these + * entries. + * + * @param citationMarkerEntries The list of entries providing the + * data. + * + * @param inParenthesis Signals whether a parenthesized citation + * or an in-text citation is wanted. + * + * @param nonUniqueCitationMarkerHandling + * + * THROWS : Should throw if finds that uniqueLetters + * provided do not make the entries unique. + * + * FORGIVEN : is needed to allow preliminary markers + * for freshly inserted citations without + * going throw the uniquefication process. + * + * @return The formatted citation. The result does not include + * the standard wrappers: + * OOFormat.setLocaleNone() and OOFormat.setCharStyle(). + * These are added by decorateCitationMarker() + */ + public OOText createCitationMarker(List citationMarkerEntries, + boolean inParenthesis, + NonUniqueCitationMarker nonUniqueCitationMarkerHandling) { + return OOBibStyleGetCitationMarker.createCitationMarker(this, + citationMarkerEntries, + inParenthesis, + nonUniqueCitationMarkerHandling); + } + + /** + * Add setLocaleNone and optionally setCharStyle(CitationCharacterFormat) around + * citationText. Called in fillCitationMarkInCursor, so these are + * also applied to "Unresolved()" entries and numeric styles. + */ + public OOText decorateCitationMarker(OOText citationText) { + OOBibStyle style = this; + OOText citationText2 = OOFormat.setLocaleNone(citationText); + if (style.isFormatCitations()) { + String charStyle = style.getCitationCharacterFormat(); + citationText2 = OOFormat.setCharStyle(citationText2, charStyle); + } + return citationText2; + } + + /* + * + * Property getters + * + */ + + /** + * Minimal number of consecutive citation numbers needed to start + * replacing with an range like "10-13". + */ + public int getMinimumGroupingCount() { + return getIntCitProperty(OOBibStyle.MINIMUM_GROUPING_COUNT); + } + + /** + * Used in number ranges like "10-13" in numbered citations. + */ + public String getGroupedNumbersSeparator() { + return getStringCitProperty(OOBibStyle.GROUPED_NUMBERS_SEPARATOR); + } + + private boolean getBooleanProperty(String propName) { + return (Boolean) properties.get(propName); + } + + private String getStringProperty(String propName) { + return (String) properties.get(propName); + } + + /** + * Should citation markers be italicized? + * + */ + public String getCitationGroupMarkupBefore() { + return getStringCitProperty(CITATION_GROUP_MARKUP_BEFORE); + } + + public String getCitationGroupMarkupAfter() { + return getStringCitProperty(CITATION_GROUP_MARKUP_AFTER); + } + + /** Author list, including " et al." */ + public String getAuthorsPartMarkupBefore() { + return getStringCitProperty(AUTHORS_PART_MARKUP_BEFORE); + } + + public String getAuthorsPartMarkupAfter() { + return getStringCitProperty(AUTHORS_PART_MARKUP_AFTER); + } + + /** Author list, excluding " et al." */ + public String getAuthorNamesListMarkupBefore() { + return getStringCitProperty(AUTHOR_NAMES_LIST_MARKUP_BEFORE); + } + + public String getAuthorNamesListMarkupAfter() { + return getStringCitProperty(AUTHOR_NAMES_LIST_MARKUP_AFTER); + } + + /** Author names. Excludes Author separators */ + public String getAuthorNameMarkupBefore() { + return getStringCitProperty(AUTHOR_NAME_MARKUP_BEFORE); + } + + public String getAuthorNameMarkupAfter() { + return getStringCitProperty(AUTHOR_NAME_MARKUP_AFTER); + } + + public boolean getMultiCiteChronological() { + // "MultiCiteChronological" + return this.getBooleanCitProperty(OOBibStyle.MULTI_CITE_CHRONOLOGICAL); + } + + // Probably obsolete, now we can use " et al." instead in EtAlString + public boolean getItalicEtAl() { + // "ItalicEtAl" + return this.getBooleanCitProperty(OOBibStyle.ITALIC_ET_AL); + } + + /** + * @return Names of fields containing authors: the first + * non-empty field will be used. + */ + protected OrFields getAuthorFieldNames() { + String authorFieldNamesString = this.getStringCitProperty(OOBibStyle.AUTHOR_FIELD); + return FieldFactory.parseOrFields(authorFieldNamesString); + } + + /** + * @return Field containing year, with fallback fields. + */ + protected OrFields getYearFieldNames() { + String yearFieldNamesString = this.getStringCitProperty(OOBibStyle.YEAR_FIELD); + return FieldFactory.parseOrFields(yearFieldNamesString); + } + + /* The String to add between the two last author names, e.g. " & ". */ + protected String getAuthorLastSeparator() { + return getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR); + } + + /* As getAuthorLastSeparator, for in-text citation. */ + protected String getAuthorLastSeparatorInTextWithFallBack() { + String a = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR_IN_TEXT); + String b = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR); + return Objects.requireNonNullElse(a, b); + } + + protected String getPageInfoSeparator() { + return getStringCitProperty(OOBibStyle.PAGE_INFO_SEPARATOR); + } + + protected String getUniquefierSeparator() { + return getStringCitProperty(OOBibStyle.UNIQUEFIER_SEPARATOR); + } + + protected String getCitationSeparator() { + return getStringCitProperty(OOBibStyle.CITATION_SEPARATOR); + } + + protected String getYearSeparator() { + return getStringCitProperty(OOBibStyle.YEAR_SEPARATOR); + } + + protected String getYearSeparatorInText() { + return getStringCitProperty(OOBibStyle.IN_TEXT_YEAR_SEPARATOR); + } + + /** The maximum number of authors to write out in full without + * using "et al." Set to -1 to always write out all authors. + */ + protected int getMaxAuthors() { + return getIntCitProperty(OOBibStyle.MAX_AUTHORS); + } + + public int getMaxAuthorsFirst() { + return getIntCitProperty(OOBibStyle.MAX_AUTHORS_FIRST); + } + + /** Opening parenthesis before citation (or year, for in-text) */ + protected String getBracketBefore() { + return getStringCitProperty(OOBibStyle.BRACKET_BEFORE); + } + + /** Closing parenthesis after citation */ + protected String getBracketAfter() { + return getStringCitProperty(OOBibStyle.BRACKET_AFTER); + } + + /** Opening parenthesis before citation marker in the bibliography. */ + private String getBracketBeforeInList() { + return getStringCitProperty(OOBibStyle.BRACKET_BEFORE_IN_LIST); + } + + public String getBracketBeforeInListWithFallBack() { + return Objects.requireNonNullElse(getBracketBeforeInList(), getBracketBefore()); + } + + /** Closing parenthesis after citation marker in the bibliography */ + private String getBracketAfterInList() { + return getStringCitProperty(OOBibStyle.BRACKET_AFTER_IN_LIST); + } + + String getBracketAfterInListWithFallBack() { + return Objects.requireNonNullElse(getBracketAfterInList(), getBracketAfter()); + } + + public OOText getFormattedBibliographyTitle() { + OOBibStyle style = this; + OOText title = style.getReferenceHeaderText(); + String parStyle = style.getReferenceHeaderParagraphFormat(); + if (parStyle != null) { + title = OOFormat.paragraph(title, parStyle); + } else { + title = OOFormat.paragraph(title); + } + return title; + } + } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java new file mode 100644 index 00000000000..ee2bba27e7e --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java @@ -0,0 +1,767 @@ +package org.jabref.logic.openoffice.style; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.Author; +import org.jabref.model.entry.AuthorList; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.OrFields; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.CitationLookupResult; +import org.jabref.model.openoffice.style.CitationMarkerEntry; +import org.jabref.model.openoffice.style.CitationMarkerNormEntry; +import org.jabref.model.openoffice.style.NonUniqueCitationMarker; +import org.jabref.model.openoffice.style.PageInfo; +import org.jabref.model.strings.StringUtil; + +class OOBibStyleGetCitationMarker { + + /** + * Look up the nth author and return the "proper" last name for + * citation markers. + * + * Note: "proper" in the sense that it includes the "von" part + * of the name (followed by a space) if there is one. + * + * @param al The author list. + * @param number The number of the author to return. + * @return The author name, or an empty String if inapplicable. + */ + private static String getAuthorLastName(AuthorList al, int number) { + StringBuilder sb = new StringBuilder(); + + if (al.getNumberOfAuthors() > number) { + Author a = al.getAuthor(number); + // "von " if von exists + Optional von = a.getVon(); + if (von.isPresent() && !von.get().isEmpty()) { + sb.append(von.get()); + sb.append(' '); + } + // last name if it exists + sb.append(a.getLast().orElse("")); + } + + return sb.toString(); + } + + private static String markupAuthorName(OOBibStyle style, String name) { + return (style.getAuthorNameMarkupBefore() + + name + + style.getAuthorNameMarkupAfter()); + } + + /** + * @param authorList Parsed list of authors. + * + * @param maxAuthors The maximum number of authors to write out. + * If there are more authors, then ET_AL_STRING is emitted + * to mark their omission. + * Set to -1 to write out all authors. + * + * maxAuthors=0 is pointless, now throws RuntimeException + * (Earlier it behaved as maxAuthors=1) + * + * maxAuthors less than -1 : throw RuntimeException + * + * @param andString For "A, B[ and ]C" + * + * @return "Au[AS]Bu[AS]Cu[OXFORD_COMMA][andString]Du[yearSep]" + * or "Au[etAlString][yearSep]" + * + * where AS = AUTHOR_SEPARATOR + * Au, Bu, Cu, Du are last names of authors. + * + * Note: + * - The "Au[AS]Bu[AS]Cu" (or the "Au") part may be empty (maxAuthors==0 or nAuthors==0). + * - OXFORD_COMMA is only emitted if nAuthors is at least 3. + * - andString is only emitted if nAuthors is at least 2. + */ + private static String formatAuthorList(OOBibStyle style, + AuthorList authorList, + int maxAuthors, + String andString) { + + Objects.requireNonNull(authorList); + + // Apparently maxAuthorsBeforeEtAl is always 1 for in-text citations. + // In reference lists can be for example 7, + // (https://www.chicagomanualofstyle.org/turabian/turabian-author-date-citation-quick-guide.html) + // but those are handled elsewhere. + // + // There is also + // https://apastyle.apa.org/style-grammar-guidelines/ ... + // ... citations/basic-principles/same-year-first-author + // suggesting the to avoid ambiguity, we may need more than one name + // before "et al.". We do not currently do this kind of disambiguation, + // but we might, one day. + // + final int maxAuthorsBeforeEtAl = 1; + + // The String to represent authors that are not mentioned, + // e.g. " et al." + String etAlString = style.getEtAlString(); + + // getItalicEtAl is not necessary now, since etAlString could + // itself contain the markup. + // This is for backward compatibility. + if (style.getItalicEtAl()) { + etAlString = "" + etAlString + ""; + } + + // The String to add between author names except the last two, + // e.g. ", ". + String authorSep = style.getAuthorSeparator(); + + // The String to put after the second to last author in case + // of three or more authors: (A, B[,] and C) + String oxfordComma = style.getOxfordComma(); + + StringBuilder sb = new StringBuilder(); + + final int nAuthors = authorList.getNumberOfAuthors(); + + // To reduce ambiguity, throw on unexpected values of maxAuthors + if (maxAuthors == 0 && nAuthors != 0) { + throw new RuntimeException("maxAuthors = 0 in formatAuthorList"); + } + if (maxAuthors < -1) { + throw new RuntimeException("maxAuthors < -1 in formatAuthorList"); + } + + // emitAllAuthors == false means use "et al." + boolean emitAllAuthors = ((nAuthors <= maxAuthors) || (maxAuthors == -1)); + + int nAuthorsToEmit = (emitAllAuthors + ? nAuthors + // If we use "et al." maxAuthorsBeforeEtAl also limits the + // number of authors emitted. + : Math.min(maxAuthorsBeforeEtAl, nAuthors)); + + if (nAuthorsToEmit >= 1) { + sb.append(style.getAuthorsPartMarkupBefore()); + sb.append(style.getAuthorNamesListMarkupBefore()); + // The first author + String name = getAuthorLastName(authorList, 0); + sb.append(markupAuthorName(style, name)); + } + + if (nAuthors >= 2) { + + if (emitAllAuthors) { + // Emit last names, except for the last author + int j = 1; + while (j < (nAuthors - 1)) { + sb.append(authorSep); + String name = getAuthorLastName(authorList, j); + sb.append(markupAuthorName(style, name)); + j++; + } + // oxfordComma if at least 3 authors + if (nAuthors >= 3) { + sb.append(oxfordComma); + } + // Emit " and "+"LastAuthor" + sb.append(andString); + String name = getAuthorLastName(authorList, nAuthors - 1); + sb.append(markupAuthorName(style, name)); + + } else { + // Emit last names up to nAuthorsToEmit. + // + // The (maxAuthorsBeforeEtAl > 1) test is intended to + // make sure the compiler eliminates this block as + // long as maxAuthorsBeforeEtAl is fixed to 1. + if (maxAuthorsBeforeEtAl > 1) { + int j = 1; + while (j < nAuthorsToEmit) { + sb.append(authorSep); + String name = getAuthorLastName(authorList, j); + sb.append(markupAuthorName(style, name)); + j++; + } + } + } + } + + if (nAuthorsToEmit >= 1) { + sb.append(style.getAuthorNamesListMarkupAfter()); + } + + if (nAuthors >= 2 && !emitAllAuthors) { + sb.append(etAlString); + } + + sb.append(style.getAuthorsPartMarkupAfter()); + return sb.toString(); + } + + /** + * On success, getRawCitationMarkerField returns content, + * but we also need to know which field matched, because + * for some fields (actually: for author names) we need to + * reproduce the surrounding braces to inform AuthorList.parse + * not to split up the content. + */ + private static class FieldAndContent { + Field field; + String content; + FieldAndContent(Field field, String content) { + this.field = field; + this.content = content; + } + } + + /** + * @return the field and the content of the first nonempty (after trimming) + * field (or alias) from {@code fields} found in {@code entry}. + * Return {@code Optional.empty()} if found nothing. + */ + private static Optional getRawCitationMarkerField(BibEntry entry, + BibDatabase database, + OrFields fields) { + Objects.requireNonNull(entry, "Entry cannot be null"); + Objects.requireNonNull(database, "database cannot be null"); + + for (Field field : fields /* FieldFactory.parseOrFields(fields)*/) { + Optional optionalContent = entry.getResolvedFieldOrAlias(field, database); + final boolean foundSomething = (optionalContent.isPresent() + && !optionalContent.get().trim().isEmpty()); + if (foundSomething) { + return Optional.of(new FieldAndContent(field, optionalContent.get())); + } + } + return Optional.empty(); + } + + /** + * This method looks up a field for an entry in a database. + * + * Any number of backup fields can be used if the primary field is + * empty. + * + * @param fields A list of fields, to look up, using first nonempty hit. + * + * If backup fields are needed, separate field + * names by /. + * + * E.g. to use "author" with "editor" as backup, + * specify + * FieldFactory.serializeOrFields(StandardField.AUTHOR, + * StandardField.EDITOR) + * + * @return The resolved field content, or an empty string if the + * field(s) were empty. + * + * + * + */ + private static String getCitationMarkerField(OOBibStyle style, + CitationLookupResult db, + OrFields fields) { + Objects.requireNonNull(db); + + Optional optionalFieldAndContent = + getRawCitationMarkerField(db.entry, db.database, fields); + + if (optionalFieldAndContent.isEmpty()) { + // No luck? Return an empty string: + return ""; + } + + FieldAndContent fc = optionalFieldAndContent.get(); + String result = style.getFieldFormatter().format(fc.content); + + // If the field we found is mentioned in authorFieldNames and + // content has a pair of braces around it, we add a pair of + // braces around the result, so that AuthorList.parse does not split + // the content. + final OrFields fieldsToRebrace = style.getAuthorFieldNames(); + if (fieldsToRebrace.contains(fc.field) && StringUtil.isInCurlyBrackets(fc.content)) { + result = "{" + result + "}"; + } + return result; + } + + private static AuthorList getAuthorList(OOBibStyle style, CitationLookupResult db) { + + // The bibtex fields providing author names, e.g. "author" or + // "editor". + OrFields authorFieldNames = style.getAuthorFieldNames(); + + String authorListAsString = getCitationMarkerField(style, db, authorFieldNames); + return AuthorList.parse(authorListAsString); + } + + private enum AuthorYearMarkerPurpose { + IN_PARENTHESIS, + IN_TEXT, + NORMALIZED + } + + /** + * How many authors would be emitted for ce, considering + * style and ce.getIsFirstAppearanceOfSource() + * + * If ce is unresolved, return 0. + */ + private static int calculateNAuthorsToEmit(OOBibStyle style, CitationMarkerEntry ce) { + + int maxAuthors = (ce.getIsFirstAppearanceOfSource() + ? style.getMaxAuthorsFirst() + : style.getMaxAuthors()); + + if (ce.getLookupResult().isEmpty()) { + // unresolved + return 0; + } + + AuthorList authorList = getAuthorList(style, ce.getLookupResult().get()); + int nAuthors = authorList.getNumberOfAuthors(); + + if (maxAuthors == -1) { + return nAuthors; + } else { + return Integer.min(nAuthors, maxAuthors); + } + } + + /** + * Produce (Author, year) or "Author (year)" style citation strings. + * + * @param purpose IN_PARENTHESIS and NORMALIZED puts parentheses around the whole, + * IN_TEXT around each (year,uniqueLetter,pageInfo) part. + * + * NORMALIZED omits uniqueLetter and pageInfo, + * ignores isFirstAppearanceOfSource (always + * style.getMaxAuthors, not getMaxAuthorsFirst) + * + * @param ces The list of CitationMarkerEntry values to process. + * + * Here we do not check for duplicate entries: those + * are handled by {@code getCitationMarker} by + * omitting them from the list. + * + * Unresolved citations recognized by + * ce.getBibEntry() and/or + * ce.getDatabase() returning empty, and + * emitted as "Unresolved${citationKey}". + * + * Neither uniqueLetter nor pageInfo are emitted + * for unresolved citations. + * + * @param startsNewGroup Should have the same length as {@code ces}, and + * contain true for entries starting a new group, + * false for those that only add a uniqueLetter to + * the grouped presentation. + * + * @param maxAuthorsOverride If not empty, always show this number of authors. + * Added to allow NORMALIZED to use maxAuthors value that differs from + * style.getMaxAuthors() + * + * @return The formatted citation. + * + */ + private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, + AuthorYearMarkerPurpose purpose, + List ces, + boolean[] startsNewGroup, + Optional maxAuthorsOverride) { + + boolean inParenthesis = (purpose == AuthorYearMarkerPurpose.IN_PARENTHESIS + || purpose == AuthorYearMarkerPurpose.NORMALIZED); + + // The String to separate authors from year, e.g. "; ". + String yearSep = (inParenthesis + ? style.getYearSeparator() + : style.getYearSeparatorInText()); + + // The opening parenthesis. + String startBrace = style.getBracketBefore(); + + // The closing parenthesis. + String endBrace = style.getBracketAfter(); + + // The String to separate citations from each other. + String citationSeparator = style.getCitationSeparator(); + + // The bibtex field providing the year, e.g. "year". + OrFields yearFieldNames = style.getYearFieldNames(); + + // The String to add between the two last author names, e.g. " & ". + String andString = (inParenthesis + ? style.getAuthorLastSeparator() + : style.getAuthorLastSeparatorInTextWithFallBack()); + + String pageInfoSeparator = style.getPageInfoSeparator(); + String uniquefierSeparator = style.getUniquefierSeparator(); + + StringBuilder sb = new StringBuilder(); + sb.append(style.getCitationGroupMarkupBefore()); + + if (inParenthesis) { + sb.append(startBrace); // shared parenthesis + } + + for (int j = 0; j < ces.size(); j++) { + CitationMarkerEntry ce = ces.get(j); + boolean startingNewGroup = startsNewGroup[j]; + boolean endingAGroup = (j + 1 == ces.size()) || startsNewGroup[j + 1]; + + if (!startingNewGroup) { + // Just add our uniqueLetter + String uniqueLetter = ce.getUniqueLetter().orElse(null); + if (uniqueLetter != null) { + sb.append(uniquefierSeparator); + sb.append(uniqueLetter); + } + + // And close the brace, if we are the last in the group. + if (!inParenthesis && endingAGroup) { + sb.append(endBrace); + } + continue; + } + + if (j > 0) { + sb.append(citationSeparator); + } + + StringBuilder pageInfoPart = new StringBuilder(""); + if (purpose != AuthorYearMarkerPurpose.NORMALIZED) { + Optional pageInfo = + PageInfo.normalizePageInfo(ce.getPageInfo()); + if (pageInfo.isPresent()) { + pageInfoPart.append(pageInfoSeparator); + pageInfoPart.append(OOText.toString(pageInfo.get())); + } + } + + final boolean isUnresolved = ce.getLookupResult().isEmpty(); + if (isUnresolved) { + sb.append(String.format("Unresolved(%s)", ce.getCitationKey())); + if (purpose != AuthorYearMarkerPurpose.NORMALIZED) { + sb.append(pageInfoPart); + } + } else { + + CitationLookupResult db = ce.getLookupResult().get(); + + int maxAuthors = (purpose == AuthorYearMarkerPurpose.NORMALIZED + ? style.getMaxAuthors() + : calculateNAuthorsToEmit(style, ce)); + + if (maxAuthorsOverride.isPresent()) { + maxAuthors = maxAuthorsOverride.get(); + } + + AuthorList authorList = getAuthorList(style, db); + String authorString = formatAuthorList(style, authorList, maxAuthors, andString); + sb.append(authorString); + sb.append(yearSep); + + if (!inParenthesis) { + sb.append(startBrace); // parenthesis before year + } + + String year = getCitationMarkerField(style, db, yearFieldNames); + if (year != null) { + sb.append(year); + } + + if (purpose != AuthorYearMarkerPurpose.NORMALIZED) { + String uniqueLetter = ce.getUniqueLetter().orElse(null); + if (uniqueLetter != null) { + sb.append(uniqueLetter); + } + } + + if (purpose != AuthorYearMarkerPurpose.NORMALIZED) { + sb.append(pageInfoPart); + } + + if (!inParenthesis && endingAGroup) { + sb.append(endBrace); // parenthesis after year + } + } + } // for j + + if (inParenthesis) { + sb.append(endBrace); // shared parenthesis + } + sb.append(style.getCitationGroupMarkupAfter()); + return OOText.fromString(sb.toString()); + } + + private static class CitationMarkerNormEntryWrap implements CitationMarkerEntry { + + CitationMarkerNormEntry inner; + + CitationMarkerNormEntryWrap(CitationMarkerNormEntry inner) { + this.inner = inner; + } + + @Override + public String getCitationKey() { + return inner.getCitationKey(); + } + + @Override + public Optional getLookupResult() { + return inner.getLookupResult(); + } + + @Override + public Optional getUniqueLetter() { + return Optional.empty(); + } + + @Override + public Optional getPageInfo() { + return Optional.empty(); + } + + @Override + public boolean getIsFirstAppearanceOfSource() { + return false; + } + } + + /** + * @param cne A citation to process. + * + * @return A normalized citation marker for deciding which + * citations need uniqueLetters. + * + * For details of what "normalized" means: {@see getAuthorYearParenthesisMarker2} + * + * Note: now includes some markup. + */ + static OOText getNormalizedCitationMarker(OOBibStyle style, + CitationMarkerNormEntry cne, + Optional maxAuthorsOverride) { + boolean[] startsNewGroup = {true}; + CitationMarkerEntry ce = new CitationMarkerNormEntryWrap(cne); + return getAuthorYearParenthesisMarker2(style, + AuthorYearMarkerPurpose.NORMALIZED, + Collections.singletonList(ce), + startsNewGroup, + maxAuthorsOverride); + } + + private static List + getNormalizedCitationMarkers(OOBibStyle style, + List citationMarkerEntries, + Optional maxAuthorsOverride) { + + List normalizedMarkers = new ArrayList<>(citationMarkerEntries.size()); + for (CitationMarkerEntry citationMarkerEntry : citationMarkerEntries) { + OOText nm = getNormalizedCitationMarker(style, + citationMarkerEntry, + maxAuthorsOverride); + normalizedMarkers.add(nm); + } + return normalizedMarkers; + } + + /** + * Produce citation marker for a citation group. + * + * Attempts to join consecutive citations: if normalized citations + * markers match and no pageInfo is present, the second entry + * can be presented by appending its uniqueLetter to the + * previous. + * + * If either entry has pageInfo, join is inhibited. + * If the previous entry has more names than we need + * we check with extended normalizedMarkers if they match. + * + * For consecutive identical entries, the second one is omitted. + * Identical requires same pageInfo here, we do not try to merge them. + * Note: notifying the user about them would be nice. + * + * @param citationMarkerEntries A group of citations to process. + * + * @param inParenthesis If true, put parenthesis around the whole group, + * otherwise around each (year,uniqueLetter,pageInfo) part. + * + * @param nonUniqueCitationMarkerHandling What should happen if we + * stumble upon citations with identical normalized + * citation markers which cite different sources and + * are not distinguished by uniqueLetters. + * + * Note: only consecutive citations are checked. + * + */ + public static OOText + createCitationMarker(OOBibStyle style, + List citationMarkerEntries, + boolean inParenthesis, + NonUniqueCitationMarker nonUniqueCitationMarkerHandling) { + + final int nEntries = citationMarkerEntries.size(); + + // Original: + // + // Look for groups of uniquefied entries that should be combined in the output. + // E.g. (Olsen, 2005a, b) should be output instead of (Olsen, 2005a; Olsen, 2005b). + // + // Now: + // - handle pageInfos + // - allow duplicate entries with same or different pageInfos. + // + // We assume entries are already sorted, all we need is to + // group consecutive entries if we can. + // + // We also assume, that identical entries have the same uniqueLetters. + // + + List normalizedMarkers = getNormalizedCitationMarkers(style, + citationMarkerEntries, + Optional.empty()); + + // How many authors would be emitted without grouping. + int[] nAuthorsToEmit = new int[nEntries]; + int[] nAuthorsToEmitRevised = new int[nEntries]; + for (int i = 0; i < nEntries; i++) { + CitationMarkerEntry ce = citationMarkerEntries.get(i); + int n = calculateNAuthorsToEmit(style, ce); + nAuthorsToEmit[i] = n; + nAuthorsToEmitRevised[i] = n; + } + + boolean[] startsNewGroup = new boolean[nEntries]; + List filteredCitationMarkerEntries = new ArrayList<>(nEntries); + int i_out = 0; + + if (nEntries > 0) { + filteredCitationMarkerEntries.add(citationMarkerEntries.get(0)); + startsNewGroup[i_out] = true; + i_out++; + } + + for (int i = 1; i < nEntries; i++) { + final CitationMarkerEntry ce1 = citationMarkerEntries.get(i - 1); + final CitationMarkerEntry ce2 = citationMarkerEntries.get(i); + + final String nm1 = OOText.toString(normalizedMarkers.get(i - 1)); + final String nm2 = OOText.toString(normalizedMarkers.get(i)); + + final boolean isUnresolved1 = ce1.getLookupResult().isEmpty(); + final boolean isUnresolved2 = ce2.getLookupResult().isEmpty(); + + boolean startingNewGroup; + boolean sameAsPrev; /* true indicates ce2 may be omitted from output */ + if (isUnresolved2) { + startingNewGroup = true; + sameAsPrev = false; // keep it visible + } else { + // Does the number of authors to be shown differ? + // Since we compared normalizedMarkers, the difference + // between maxAuthors and maxAuthorsFirst may invalidate + // our expectation that adding uniqueLetter is valid. + + boolean nAuthorsShownInhibitsJoin; + if (isUnresolved1) { + nAuthorsShownInhibitsJoin = true; // no join for unresolved + } else { + final boolean isFirst1 = ce1.getIsFirstAppearanceOfSource(); + final boolean isFirst2 = ce2.getIsFirstAppearanceOfSource(); + + // nAuthorsToEmitRevised[i-1] may have been indirectly increased, + // we have to check that too. + if (!isFirst1 && + !isFirst2 && + (nAuthorsToEmitRevised[i - 1] == nAuthorsToEmit[i - 1])) { + // we can rely on normalizedMarkers + nAuthorsShownInhibitsJoin = false; + } else if (style.getMaxAuthors() == style.getMaxAuthorsFirst()) { + // we can rely on normalizedMarkers + nAuthorsShownInhibitsJoin = false; + } else { + final int prevShown = nAuthorsToEmitRevised[i - 1]; + final int need = nAuthorsToEmit[i]; + + if (prevShown < need) { + // We do not retrospectively change the number of authors shown + // at the previous entry, take that as decided. + nAuthorsShownInhibitsJoin = true; + } else { + // prevShown >= need + // Check with extended normalizedMarkers. + OOText nmx1 = + getNormalizedCitationMarker(style, ce1, Optional.of(prevShown)); + OOText nmx2 = + getNormalizedCitationMarker(style, ce2, Optional.of(prevShown)); + boolean extendedMarkersDiffer = !nmx2.equals(nmx1); + nAuthorsShownInhibitsJoin = extendedMarkersDiffer; + } + } + } + + final boolean citationKeysDiffer = !ce2.getCitationKey().equals(ce1.getCitationKey()); + final boolean normalizedMarkersDiffer = !nm2.equals(nm1); + + Optional pageInfo2 = PageInfo.normalizePageInfo(ce2.getPageInfo()); + Optional pageInfo1 = PageInfo.normalizePageInfo(ce1.getPageInfo()); + final boolean bothPageInfosAreEmpty = pageInfo2.isEmpty() && pageInfo1.isEmpty(); + final boolean pageInfosDiffer = !pageInfo2.equals(pageInfo1); + + Optional ul2 = ce2.getUniqueLetter(); + Optional ul1 = ce1.getUniqueLetter(); + final boolean uniqueLetterPresenceChanged = (ul2.isPresent() != ul1.isPresent()); + final boolean uniqueLettersDiffer = !ul2.equals(ul1); + + final boolean uniqueLetterDoesNotMakeUnique = (citationKeysDiffer + && !normalizedMarkersDiffer + && !uniqueLettersDiffer); + + if (uniqueLetterDoesNotMakeUnique && + nonUniqueCitationMarkerHandling.equals(NonUniqueCitationMarker.THROWS)) { + throw new RuntimeException("different citation keys," + + " but same normalizedMarker and uniqueLetter"); + } + + final boolean pageInfoInhibitsJoin = (bothPageInfosAreEmpty + ? false + : (citationKeysDiffer || pageInfosDiffer)); + + startingNewGroup = (normalizedMarkersDiffer + || nAuthorsShownInhibitsJoin + || pageInfoInhibitsJoin + || uniqueLetterPresenceChanged + || uniqueLetterDoesNotMakeUnique); + + if (!startingNewGroup) { + // inherit from first of group. Used at next i. + nAuthorsToEmitRevised[i] = nAuthorsToEmitRevised[i - 1]; + } + + sameAsPrev = (!startingNewGroup + && !uniqueLettersDiffer + && !citationKeysDiffer + && !pageInfosDiffer); + } + + if (!sameAsPrev) { + filteredCitationMarkerEntries.add(ce2); + startsNewGroup[i_out] = startingNewGroup; + i_out++; + } + } + + return getAuthorYearParenthesisMarker2(style, + (inParenthesis + ? AuthorYearMarkerPurpose.IN_PARENTHESIS + : AuthorYearMarkerPurpose.IN_TEXT), + filteredCitationMarkerEntries, + startsNewGroup, + Optional.empty()); + } +} diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java new file mode 100644 index 00000000000..376c4478421 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java @@ -0,0 +1,278 @@ +package org.jabref.logic.openoffice.style; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.CitationMarkerNumericBibEntry; +import org.jabref.model.openoffice.style.CitationMarkerNumericEntry; +import org.jabref.model.openoffice.style.PageInfo; +import org.jabref.model.openoffice.util.OOListUtil; + +class OOBibStyleGetNumCitationMarker { + + /* + * The number encoding "this entry is unresolved" + */ + public final static int UNRESOLVED_ENTRY_NUMBER = 0; + + /** + * Defines sort order for CitationMarkerNumericEntry. + */ + private static int compareCitationMarkerNumericEntry(CitationMarkerNumericEntry a, + CitationMarkerNumericEntry b) { + int na = a.getNumber().orElse(UNRESOLVED_ENTRY_NUMBER); + int nb = b.getNumber().orElse(UNRESOLVED_ENTRY_NUMBER); + int res = Integer.compare(na, nb); + if (res == 0) { + res = PageInfo.comparePageInfo(a.getPageInfo(), b.getPageInfo()); + } + return res; + } + + /** + * Create a numeric marker for use in the bibliography as label for the entry. + * + * To support for example numbers in superscript without brackets for the text, + * but "[1]" form for the bibliography, the style can provide + * the optional "BracketBeforeInList" and "BracketAfterInList" strings + * to be used in the bibliography instead of "BracketBefore" and "BracketAfter" + * + * @return "[${number}]" where + * "[" stands for BRACKET_BEFORE_IN_LIST (with fallback BRACKET_BEFORE) + * "]" stands for BRACKET_AFTER_IN_LIST (with fallback BRACKET_AFTER) + * "${number}" stands for the formatted number. + */ + public static OOText getNumCitationMarkerForBibliography(OOBibStyle style, + CitationMarkerNumericBibEntry entry) { + // prefer BRACKET_BEFORE_IN_LIST and BRACKET_AFTER_IN_LIST + String bracketBefore = style.getBracketBeforeInListWithFallBack(); + String bracketAfter = style.getBracketAfterInListWithFallBack(); + StringBuilder sb = new StringBuilder(); + sb.append(style.getCitationGroupMarkupBefore()); + sb.append(bracketBefore); + final Optional current = entry.getNumber(); + sb.append(current.isPresent() + ? String.valueOf(current.get()) + : (OOBibStyle.UNDEFINED_CITATION_MARKER + entry.getCitationKey())); + sb.append(bracketAfter); + sb.append(style.getCitationGroupMarkupAfter()); + return OOText.fromString(sb.toString()); + } + + /* + * emitBlock : a helper for getNumCitationMarker2 + * + * Given a block containing either a single entry or two or more + * entries that are joinable into an "i-j" form, append to {@code sb} the + * formatted text. + * + * Assumes: + * + * - block is not empty + * + * - For a block with a single element the element may have + * pageInfo and its num part may be Optional.empty() + * + * - For a block with two or more elements + * + * - The elements do not have pageInfo and their number part is + * not empty. + * + * - The elements number parts are consecutive positive integers, + * without repetition. + * + */ + private static void emitBlock(List block, + OOBibStyle style, + int minGroupingCount, + StringBuilder sb) { + + final int blockSize = block.size(); + if (blockSize == 0) { + throw new RuntimeException("The block is empty"); + } + + if (blockSize == 1) { + // Add single entry: + CitationMarkerNumericEntry entry = block.get(0); + final Optional num = entry.getNumber(); + sb.append(num.isEmpty() + ? (OOBibStyle.UNDEFINED_CITATION_MARKER + entry.getCitationKey()) + : String.valueOf(num.get())); + // Emit pageInfo + Optional pageInfo = entry.getPageInfo(); + if (pageInfo.isPresent()) { + sb.append(style.getPageInfoSeparator()); + sb.append(OOText.toString(pageInfo.get())); + } + return; + } + + if (blockSize >= 2) { + + /* + * Check assumptions + */ + + if (block.stream().anyMatch(x -> x.getPageInfo().isPresent())) { + throw new RuntimeException("Found pageInfo in a block with more than one elements"); + } + + if (block.stream().anyMatch(x -> x.getNumber().isEmpty())) { + throw new RuntimeException("Found unresolved entry" + + " in a block with more than one elements"); + } + + for (int j = 1; j < blockSize; j++) { + if ((block.get(j).getNumber().get() - block.get(j - 1).getNumber().get()) != 1) { + throw new RuntimeException("Numbers are not consecutive"); + } + } + + /* + * Do the actual work + */ + + if (blockSize >= minGroupingCount) { + int first = block.get(0).getNumber().get(); + int last = block.get(blockSize - 1).getNumber().get(); + if (last != (first + blockSize - 1)) { + throw new RuntimeException("blockSize and length of num range differ"); + } + + // Emit: "first-last" + sb.append(first); + sb.append(style.getGroupedNumbersSeparator()); + sb.append(last); + } else { + + // Emit: first, first+1,..., last + for (int j = 0; j < blockSize; j++) { + if (j > 0) { + sb.append(style.getCitationSeparator()); + } + sb.append(block.get(j).getNumber().get()); + } + } + return; + } + } + + /** + * Format a number-based citation marker for the given number or numbers. + * + * @param entries Provide the citation numbers. + * + * An Optional.empty() number means: could not look this up + * in the databases. Positive integers are the valid numbers. + * + * Duplicate citation numbers are allowed: + * + * - If their pageInfos are identical, only a + * single instance is emitted. + * + * - If their pageInfos differ, the number is emitted with each + * distinct pageInfo. + * + * pageInfos are expected to be normalized + * + * @param minGroupingCount Zero and negative means never group. + * Only used by tests to override the value in style. + * + * @return The text for the citation. + * + */ + public static OOText getNumCitationMarker2(OOBibStyle style, + List entries, + int minGroupingCount) { + + final boolean joinIsDisabled = (minGroupingCount <= 0); + final int nCitations = entries.size(); + + String bracketBefore = style.getBracketBefore(); + String bracketAfter = style.getBracketAfter(); + + // Sort a copy of entries + List sorted = OOListUtil.map(entries, e -> e); + sorted.sort(OOBibStyleGetNumCitationMarker::compareCitationMarkerNumericEntry); + + // "[" + StringBuilder sb = new StringBuilder(bracketBefore); + + /* + * Original: + * [2,3,4] -> [2-4] + * [0,1,2] -> [??,1,2] + * [0,1,2,3] -> [??,1-3] + * + * Now we have to consider: duplicate numbers and pageInfos + * [1,1] -> [1] + * [1,1 "pp nn"] -> keep separate if pageInfo differs + * [1 "pp nn",1 "pp nn"] -> [1 "pp nn"] + */ + + boolean blocksEmitted = false; + List currentBlock = new ArrayList<>(); + List nextBlock = new ArrayList<>(); + + for (int i = 0; i < nCitations; i++) { + + final CitationMarkerNumericEntry current = sorted.get(i); + if (current.getNumber().isPresent() && current.getNumber().get() < 0) { + throw new RuntimeException("getNumCitationMarker2: found negative value"); + } + + if (currentBlock.size() == 0) { + currentBlock.add(current); + } else { + CitationMarkerNumericEntry prev = currentBlock.get(currentBlock.size() - 1); + if (current.getNumber().isEmpty() || prev.getNumber().isEmpty()) { + nextBlock.add(current); // do not join if not found + } else if (joinIsDisabled) { + nextBlock.add(current); // join disabled + } else if (compareCitationMarkerNumericEntry(current, prev) == 0) { + // Same as prev, just forget it. + } else if ((current.getNumber().get() == (prev.getNumber().get() + 1)) + && (prev.getPageInfo().isEmpty()) + && (current.getPageInfo().isEmpty())) { + // Just two consecutive numbers without pageInfo: join + currentBlock.add(current); + } else { + // do not join + nextBlock.add(current); + } + } + + if (nextBlock.size() > 0) { + // emit current block + if (blocksEmitted) { + sb.append(style.getCitationSeparator()); + } + emitBlock(currentBlock, style, minGroupingCount, sb); + blocksEmitted = true; + currentBlock = nextBlock; + nextBlock = new ArrayList<>(); + } + + } + + if (nextBlock.size() != 0) { + throw new RuntimeException("impossible: (nextBlock.size() != 0) after loop"); + } + + if (currentBlock.size() > 0) { + // We are emitting a block + if (blocksEmitted) { + sb.append(style.getCitationSeparator()); + } + emitBlock(currentBlock, style, minGroupingCount, sb); + } + + // Emit: "]" + sb.append(bracketAfter); + return OOText.fromString(sb.toString()); + } + +} diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java b/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java new file mode 100644 index 00000000000..c9ae527dcec --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java @@ -0,0 +1,197 @@ +package org.jabref.logic.openoffice.style; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.jabref.logic.l10n.Localization; +import org.jabref.logic.layout.Layout; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.UnknownField; +import org.jabref.model.openoffice.ootext.OOFormat; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.CitationGroup; +import org.jabref.model.openoffice.style.CitationGroupId; +import org.jabref.model.openoffice.style.CitationGroups; +import org.jabref.model.openoffice.style.CitationPath; +import org.jabref.model.openoffice.style.CitedKey; +import org.jabref.model.openoffice.style.CitedKeys; + +public class OOFormatBibliography { + private static final OOPreFormatter POSTFORMATTER = new OOPreFormatter(); + private static final Field UNIQUEFIER_FIELD = new UnknownField("uniq"); + + private OOFormatBibliography() { + } + + /** + * @return The formatted bibliography, including its title. + */ + public static OOText formatBibliography(CitationGroups cgs, + CitedKeys bibliography, + OOBibStyle style, + boolean alwaysAddCitedOnPages) { + + OOText title = style.getFormattedBibliographyTitle(); + OOText body = formatBibliographyBody(cgs, bibliography, style, alwaysAddCitedOnPages); + return OOText.fromString(title.asString() + body.asString()); + } + + /** + * @return Formatted body of the bibliography. Excludes the title. + */ + public static OOText formatBibliographyBody(CitationGroups cgs, + CitedKeys bibliography, + OOBibStyle style, + boolean alwaysAddCitedOnPages) { + + StringBuilder stringBuilder = new StringBuilder(); + + for (CitedKey ck : bibliography.values()) { + OOText entryText = formatBibliographyEntry(cgs, ck, style, alwaysAddCitedOnPages); + stringBuilder.append(entryText.asString()); + } + + return OOText.fromString(stringBuilder.toString()); + } + + /** + * @return A paragraph. Includes label and "Cited on pages". + */ + public static OOText formatBibliographyEntry(CitationGroups cgs, + CitedKey ck, + OOBibStyle style, + boolean alwaysAddCitedOnPages) { + StringBuilder sb = new StringBuilder(); + + // insert marker "[1]" + if (style.isNumberEntries()) { + sb.append(style.getNumCitationMarkerForBibliography(ck).asString()); + } else { + // !style.isNumberEntries() : emit no prefix + // Note: We might want [citationKey] prefix for style.isCitationKeyCiteMarkers(); + } + + // Add entry body + sb.append(formatBibliographyEntryBody(ck, style).asString()); + + // Add "Cited on pages" + if (ck.getLookupResult().isEmpty() || alwaysAddCitedOnPages) { + sb.append(formatCitedOnPages(cgs, ck).asString()); + } + + // Add paragraph + OOText entryText = OOText.fromString(sb.toString()); + String parStyle = style.getReferenceParagraphFormat(); + return OOFormat.paragraph(entryText, parStyle); + } + + /** + * @return just the body of a bibliography entry. No label, "Cited on pages" or paragraph. + */ + public static OOText formatBibliographyEntryBody(CitedKey ck, OOBibStyle style) { + if (ck.getLookupResult().isEmpty()) { + // Unresolved entry + return OOText.fromString(String.format("Unresolved(%s)", ck.citationKey)); + } else { + // Resolved entry, use the layout engine + BibEntry bibentry = ck.getLookupResult().get().entry; + Layout layout = style.getReferenceFormat(bibentry.getType()); + layout.setPostFormatter(POSTFORMATTER); + + return formatFullReferenceOfBibEntry(layout, + bibentry, + ck.getLookupResult().get().database, + ck.getUniqueLetter().orElse(null)); + } + } + + /** + * Format the reference part of a bibliography entry using a Layout. + * + * @param layout The Layout to format the reference with. + * @param entry The entry to insert. + * @param database The database the entry belongs to. + * @param uniquefier Uniqiefier letter, if any, to append to the entry's year. + * + * @return OOText The reference part of a bibliography entry formatted as OOText + */ + private static OOText formatFullReferenceOfBibEntry(Layout layout, + BibEntry entry, + BibDatabase database, + String uniquefier) { + + // Backup the value of the uniq field, just in case the entry already has it: + Optional oldUniqVal = entry.getField(UNIQUEFIER_FIELD); + + // Set the uniq field with the supplied uniquefier: + if (uniquefier == null) { + entry.clearField(UNIQUEFIER_FIELD); + } else { + entry.setField(UNIQUEFIER_FIELD, uniquefier); + } + + // Do the layout for this entry: + OOText formattedText = OOText.fromString(layout.doLayout(entry, database)); + + // Afterwards, reset the old value: + if (oldUniqVal.isPresent()) { + entry.setField(UNIQUEFIER_FIELD, oldUniqVal.get()); + } else { + entry.clearField(UNIQUEFIER_FIELD); + } + + return formattedText; + } + + /** + * Format links to citations of the source (ck). + * + * Requires reference marks for the citation groups. + * + * - The links are created as references that show page numbers of the reference marks. + * - We do not control the text shown, that is provided by OpenOffice. + */ + private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey ck) { + + if (!cgs.citationGroupsProvideReferenceMarkNameForLinking()) { + return OOText.fromString(""); + } + + StringBuilder sb = new StringBuilder(); + + String prefix = String.format(" (%s: ", Localization.lang("Cited on pages")); + String suffix = ")"; + sb.append(prefix); + + List citationGroups = new ArrayList<>(); + for (CitationPath p : ck.getCitationPaths()) { + CitationGroupId cgid = p.group; + CitationGroup cg = cgs.getCitationGroupOrThrow(cgid); + citationGroups.add(cg); + } + + // sort the citationGroups according to their indexInGlobalOrder + citationGroups.sort((a, b) -> { + Integer aa = a.getIndexInGlobalOrder().orElseThrow(RuntimeException::new); + Integer bb = b.getIndexInGlobalOrder().orElseThrow(RuntimeException::new); + return (aa.compareTo(bb)); + }); + + int i = 0; + for (CitationGroup cg : citationGroups) { + if (i > 0) { + sb.append(", "); + } + String markName = cg.getReferenceMarkNameForLinking().orElseThrow(RuntimeException::new); + OOText xref = OOFormat.formatReferenceToPageNumberOfReferenceMark(markName); + sb.append(xref.asString()); + i++; + } + sb.append(suffix); + return OOText.fromString(sb.toString()); + } + +} diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java new file mode 100644 index 00000000000..6f7709aac10 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java @@ -0,0 +1,90 @@ +package org.jabref.logic.openoffice.style; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +import org.jabref.logic.bibtex.comparator.FieldComparator; +import org.jabref.logic.bibtex.comparator.FieldComparatorStack; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.StandardField; +import org.jabref.model.openoffice.style.CitationGroups; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OOProcess { + + static final Comparator AUTHOR_YEAR_TITLE_COMPARATOR = makeAuthorYearTitleComparator(); + static final Comparator YEAR_AUTHOR_TITLE_COMPARATOR = makeYearAuthorTitleComparator(); + + private static final Logger LOGGER = LoggerFactory.getLogger(OOProcess.class); + + private static Comparator makeAuthorYearTitleComparator() { + FieldComparator a = new FieldComparator(StandardField.AUTHOR); + FieldComparator y = new FieldComparator(StandardField.YEAR); + FieldComparator t = new FieldComparator(StandardField.TITLE); + + List> ayt = new ArrayList<>(3); + ayt.add(a); + ayt.add(y); + ayt.add(t); + return new FieldComparatorStack<>(ayt); + } + + private static Comparator makeYearAuthorTitleComparator() { + FieldComparator y = new FieldComparator(StandardField.YEAR); + FieldComparator a = new FieldComparator(StandardField.AUTHOR); + FieldComparator t = new FieldComparator(StandardField.TITLE); + + List> yat = new ArrayList<>(3); + yat.add(y); + yat.add(a); + yat.add(t); + return new FieldComparatorStack<>(yat); + } + + /** + * The comparator used to sort within a group of merged + * citations. + * + * The term used here is "multicite". The option controlling the + * order is "MultiCiteChronological" in style files. + * + * Yes, they are always sorted one way or another. + */ + public static Comparator comparatorForMulticite(OOBibStyle style) { + if (style.getMultiCiteChronological()) { + return OOProcess.YEAR_AUTHOR_TITLE_COMPARATOR; + } else { + return OOProcess.AUTHOR_YEAR_TITLE_COMPARATOR; + } + } + + /** + * Fill cgs.bibliography and cgs.citationGroupsUnordered//CitationMarker + * according to style. + */ + public static void produceCitationMarkers(CitationGroups cgs, + List databases, + OOBibStyle style) { + + if (!cgs.hasGlobalOrder()) { + throw new RuntimeException("produceCitationMarkers: globalOrder is misssing in cgs"); + } + + cgs.lookupCitations(databases); + cgs.imposeLocalOrder(comparatorForMulticite(style)); + + // fill CitationGroup.citationMarker + if (style.isCitationKeyCiteMarkers()) { + OOProcessCitationKeyMarkers.produceCitationMarkers(cgs, style); + } else if (style.isNumberEntries()) { + OOProcessNumericMarkers.produceCitationMarkers(cgs, style); + } else { + OOProcessAuthorYearMarkers.produceCitationMarkers(cgs, style); + } + } + +} diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java new file mode 100644 index 00000000000..a55d59107a8 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java @@ -0,0 +1,162 @@ +package org.jabref.logic.openoffice.style; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.Citation; +import org.jabref.model.openoffice.style.CitationGroup; +import org.jabref.model.openoffice.style.CitationGroups; +import org.jabref.model.openoffice.style.CitationMarkerEntry; +import org.jabref.model.openoffice.style.CitationType; +import org.jabref.model.openoffice.style.CitedKey; +import org.jabref.model.openoffice.style.CitedKeys; +import org.jabref.model.openoffice.style.NonUniqueCitationMarker; +import org.jabref.model.openoffice.util.OOListUtil; + +class OOProcessAuthorYearMarkers { + + /** + * Fills {@code sortedCitedKeys//normCitMarker} + */ + private static void createNormalizedCitationMarkers(CitedKeys sortedCitedKeys, OOBibStyle style) { + + for (CitedKey ck : sortedCitedKeys.values()) { + ck.setNormalizedCitationMarker(Optional.of(style.getNormalizedCitationMarker(ck))); + } + } + + /** + * For each cited source make the citation keys unique by setting + * the uniqueLetter fields to letters ("a", "b") or Optional.empty() + * + * precondition: sortedCitedKeys already has normalized citation markers. + * precondition: sortedCitedKeys is sorted (according to the order we want the letters to be assigned) + * + * Expects to see data for all cited sources here. + * Clears uniqueLetters before filling. + * + * On return: Each citedKey in sortedCitedKeys has uniqueLetter set as needed. + * The same values are copied to the corresponding citations in cgs. + * + * Depends on: style, citations and their order. + */ + private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroups cgs) { + + // The entries in the clashingKeys lists preserve + // firstAppearance order from sortedCitedKeys.values(). + // + // The index of the citationKey in this order will decide + // which unique letter it receives. + // + Map> normCitMarkerToClachingKeys = new HashMap<>(); + for (CitedKey citedKey : sortedCitedKeys.values()) { + String normCitMarker = OOText.toString(citedKey.getNormalizedCitationMarker().get()); + String citationKey = citedKey.citationKey; + + if (!normCitMarkerToClachingKeys.containsKey(normCitMarker)) { + // Found new normCitMarker + List clashingKeys = new ArrayList<>(1); + normCitMarkerToClachingKeys.put(normCitMarker, clashingKeys); + clashingKeys.add(citationKey); + } else { + List clashingKeys = normCitMarkerToClachingKeys.get(normCitMarker); + if (!clashingKeys.contains(citationKey)) { + // First appearance of citationKey, add to list. + clashingKeys.add(citationKey); + } + } + } + + // Clear old uniqueLetter values. + for (CitedKey citedKey : sortedCitedKeys.values()) { + citedKey.setUniqueLetter(Optional.empty()); + } + + // For sets of citation keys figthing for a normCitMarker + // add unique letters to the year. + for (List clashingKeys : normCitMarkerToClachingKeys.values()) { + if (clashingKeys.size() <= 1) { + continue; // No fight, no letters. + } + // Multiple citation keys: they get their letters + // according to their order in clashingKeys. + int nextUniqueLetter = 'a'; + for (String citationKey : clashingKeys) { + String ul = String.valueOf((char) nextUniqueLetter); + sortedCitedKeys.get(citationKey).setUniqueLetter(Optional.of(ul)); + nextUniqueLetter++; + } + } + sortedCitedKeys.distributeUniqueLetters(cgs); + } + + /* *************************************** + * + * Calculate presentation of citation groups + * (create citMarkers) + * + * **************************************/ + + /** + * Set isFirstAppearanceOfSource in each citation. + * + * Preconditions: globalOrder, localOrder + */ + private static void setIsFirstAppearanceOfSourceInCitations(CitationGroups cgs) { + Set seenBefore = new HashSet<>(); + for (CitationGroup cg : cgs.getCitationGroupsInGlobalOrder()) { + for (Citation cit : cg.getCitationsInLocalOrder()) { + String currentKey = cit.citationKey; + if (!seenBefore.contains(currentKey)) { + cit.setIsFirstAppearanceOfSource(true); + seenBefore.add(currentKey); + } else { + cit.setIsFirstAppearanceOfSource(false); + } + } + } + } + + /** + * Produce citMarkers for normal + * (!isCitationKeyCiteMarkers && !isNumberEntries) styles. + * + * @param cgs + * @param style Bibliography style. + */ + static void produceCitationMarkers(CitationGroups cgs, OOBibStyle style) { + + assert !style.isCitationKeyCiteMarkers(); + assert !style.isNumberEntries(); + // Citations in (Au1, Au2 2000) form + + CitedKeys citedKeys = cgs.getCitedKeysSortedInOrderOfAppearance(); + + createNormalizedCitationMarkers(citedKeys, style); + createUniqueLetters(citedKeys, cgs); + cgs.createPlainBibliographySortedByComparator(OOProcess.AUTHOR_YEAR_TITLE_COMPARATOR); + + // Mark first appearance of each citationKey + setIsFirstAppearanceOfSourceInCitations(cgs); + + for (CitationGroup cg : cgs.getCitationGroupsInGlobalOrder()) { + + final boolean inParenthesis = (cg.citationType == CitationType.AUTHORYEAR_PAR); + final NonUniqueCitationMarker strictlyUnique = NonUniqueCitationMarker.THROWS; + + List cits = cg.getCitationsInLocalOrder(); + List citationMarkerEntries = OOListUtil.map(cits, e -> e); + OOText citMarker = style.createCitationMarker(citationMarkerEntries, + inParenthesis, + strictlyUnique); + cg.setCitationMarker(Optional.of(citMarker)); + } + } + +} diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java new file mode 100644 index 00000000000..c63a4b3d0e4 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java @@ -0,0 +1,30 @@ +package org.jabref.logic.openoffice.style; + +import java.util.Optional; + +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.Citation; +import org.jabref.model.openoffice.style.CitationGroup; +import org.jabref.model.openoffice.style.CitationGroups; +import org.jabref.model.openoffice.util.OOListUtil; + +class OOProcessCitationKeyMarkers { + /** + * Produce citation markers for the case when the citation + * markers are the citation keys themselves, separated by commas. + */ + static void produceCitationMarkers(CitationGroups cgs, OOBibStyle style) { + + assert style.isCitationKeyCiteMarkers(); + + cgs.createPlainBibliographySortedByComparator(OOProcess.AUTHOR_YEAR_TITLE_COMPARATOR); + + for (CitationGroup cg : cgs.getCitationGroupsInGlobalOrder()) { + String citMarker = + style.getCitationGroupMarkupBefore() + + String.join(",", OOListUtil.map(cg.getCitationsInLocalOrder(), Citation::getCitationKey)) + + style.getCitationGroupMarkupAfter(); + cg.setCitationMarker(Optional.of(OOText.fromString(citMarker))); + } + } +} diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java new file mode 100644 index 00000000000..4023ed0e028 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java @@ -0,0 +1,43 @@ +package org.jabref.logic.openoffice.style; + +import java.util.List; +import java.util.Optional; + +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.CitationGroup; +import org.jabref.model.openoffice.style.CitationGroups; +import org.jabref.model.openoffice.style.CitationMarkerNumericEntry; +import org.jabref.model.openoffice.util.OOListUtil; + +class OOProcessNumericMarkers { + + /** + * Produce citation markers for the case of numbered citations + * with bibliography sorted by first appearance in the text. + * + * Numbered citation markers for each CitationGroup. + * Numbering is according to first appearance. + * Assumes global order and local order are already applied. + * + * @param cgs + * @param style + * + */ + static void produceCitationMarkers(CitationGroups cgs, OOBibStyle style) { + + assert style.isNumberEntries(); + + if (style.isSortByPosition()) { + cgs.createNumberedBibliographySortedInOrderOfAppearance(); + } else { + cgs.createNumberedBibliographySortedByComparator(OOProcess.AUTHOR_YEAR_TITLE_COMPARATOR); + } + + for (CitationGroup cg : cgs.getCitationGroupsInGlobalOrder()) { + List cits = OOListUtil.map(cg.getCitationsInLocalOrder(), e -> e); + OOText citMarker = style.getNumCitationMarker2(cits); + cg.setCitationMarker(Optional.of(citMarker)); + } + } + +} diff --git a/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java b/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java index 6d7651a24de..727db88cbc4 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java +++ b/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java @@ -92,7 +92,7 @@ private void loadExternalStyles() { } } catch (FileNotFoundException e) { // The file couldn't be found... should we tell anyone? - LOGGER.info("Cannot find external style file " + filename, e); + LOGGER.info("Cannot find external style file " + filename); } catch (IOException e) { LOGGER.info("Problem reading external style file " + filename, e); } diff --git a/src/main/java/org/jabref/model/openoffice/style/Citation.java b/src/main/java/org/jabref/model/openoffice/style/Citation.java new file mode 100644 index 00000000000..f0b732a9240 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/Citation.java @@ -0,0 +1,142 @@ +package org.jabref.model.openoffice.style; + +import java.util.List; +import java.util.Optional; + +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.util.OOPair; + +public class Citation implements ComparableCitation, CitationMarkerEntry, CitationMarkerNumericEntry { + + /** key in database */ + public final String citationKey; + + /** Result from database lookup. Optional.empty() if not found. */ + private Optional db; + + /** The number used for numbered citation styles . */ + private Optional number; + + /** Letter that makes the in-text citation unique. */ + private Optional uniqueLetter; + + /** pageInfo */ + private Optional pageInfo; + + /** isFirstAppearanceOfSource */ + private boolean isFirstAppearanceOfSource; + + /** + * + */ + public Citation(String citationKey) { + this.citationKey = citationKey; + this.db = Optional.empty(); + this.number = Optional.empty(); + this.uniqueLetter = Optional.empty(); + this.pageInfo = Optional.empty(); + this.isFirstAppearanceOfSource = false; + } + + @Override + public String getCitationKey() { + return citationKey; + } + + @Override + public Optional getPageInfo() { + return pageInfo; + } + + @Override + public boolean getIsFirstAppearanceOfSource() { + return isFirstAppearanceOfSource; + } + + @Override + public Optional getBibEntry() { + return (db.isPresent() + ? Optional.of(db.get().entry) + : Optional.empty()); + } + + public static Optional lookup(List databases, String key) { + for (BibDatabase database : databases) { + Optional entry = database.getEntryByCitationKey(key); + if (entry.isPresent()) { + return Optional.of(new CitationLookupResult(entry.get(), database)); + } + } + return Optional.empty(); + } + + public void lookupInDatabases(List databases) { + db = Citation.lookup(databases, citationKey); + } + + public Optional getLookupResult() { + return db; + } + + public void setLookupResult(Optional db) { + this.db = db; + } + + public boolean isUnresolved() { + return db.isEmpty(); + } + + @Override + public Optional getNumber() { + return number; + } + + public void setNumber(Optional n) { + number = n; + } + + public int getNumberOrThrow() { + return number.get(); + } + + public Optional getUniqueLetter() { + return uniqueLetter; + } + + public void setUniqueLetter(Optional uniqueLetter) { + this.uniqueLetter = uniqueLetter; + } + + public void setPageInfo(Optional v) { + Optional vv = PageInfo.normalizePageInfo(v); + if (!vv.equals(v)) { + throw new RuntimeException("setPageInfo argument is not normalized"); + } + this.pageInfo = vv; + } + + public void setIsFirstAppearanceOfSource(boolean value) { + isFirstAppearanceOfSource = value; + } + + /* + * Setters for CitationGroups.distribute() + */ + public static void setLookupResult(OOPair> x) { + Citation cit = x.a; + cit.db = x.b; + } + + public static void setNumber(OOPair> x) { + Citation cit = x.a; + cit.number = x.b; + } + + public static void setUniqueLetter(OOPair> x) { + Citation cit = x.a; + cit.uniqueLetter = x.b; + } + +} diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java new file mode 100644 index 00000000000..075c55cc2ef --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java @@ -0,0 +1,157 @@ +package org.jabref.model.openoffice.style; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; + +import org.jabref.model.entry.BibEntry; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.util.OOListUtil; + +/** + * A CitationGroup describes a group of citations. + */ +public class CitationGroup { + + public final OODataModel dataModel; + + /* + * Identifies this citation group. + */ + public final CitationGroupId cgid; + + /* + * The core data, stored in the document: + * The type of citation and citations in storage order. + */ + public final CitationType citationType; + public final List citationsInStorageOrder; + + /* + * Extra data + */ + + /* + * A name of a reference mark to link to by formatCitedOnPages. + * May be initially empty, if backend does not use reference marks. + * + * produceCitationMarkers might want fill it to support + * cross-references to citation groups from the bibliography. + */ + private Optional referenceMarkNameForLinking; + + /* + * Indices into citations: citations[localOrder[i]] provides ith + * citation according to the currently imposed local order for + * presentation. + * + * Initialized to (0..(nCitations-1)) in the constructor. + */ + private List localOrder; + + /* + * "Cited on pages" uses this to sort the cross-references. + */ + private Optional indexInGlobalOrder; + + /* + * Citation marker. + */ + private Optional citationMarker; + + public CitationGroup(OODataModel dataModel, + CitationGroupId cgid, + CitationType citationType, + List citationsInStorageOrder, + Optional referenceMarkNameForLinking) { + this.dataModel = dataModel; + this.cgid = cgid; + this.citationType = citationType; + this.citationsInStorageOrder = Collections.unmodifiableList(citationsInStorageOrder); + this.localOrder = OOListUtil.makeIndices(citationsInStorageOrder.size()); + this.referenceMarkNameForLinking = referenceMarkNameForLinking; + this.indexInGlobalOrder = Optional.empty(); + this.citationMarker = Optional.empty(); + } + + public int numberOfCitations() { + return citationsInStorageOrder.size(); + } + + /* + * localOrder + */ + + /** + * Sort citations for presentation within a CitationGroup. + */ + void imposeLocalOrder(Comparator entryComparator) { + + // For JabRef52 the single pageInfo is always in the last-in-localorder citation. + // We adjust here accordingly by taking it out and adding it back after sorting. + final int last = this.numberOfCitations() - 1; + Optional lastPageInfo = Optional.empty(); + if (dataModel == OODataModel.JabRef52) { + Citation lastCitation = getCitationsInLocalOrder().get(last); + lastPageInfo = lastCitation.getPageInfo(); + lastCitation.setPageInfo(Optional.empty()); + } + + this.localOrder = OOListUtil.order(citationsInStorageOrder, + new CompareCitation(entryComparator, true)); + + if (dataModel == OODataModel.JabRef52) { + getCitationsInLocalOrder().get(last).setPageInfo(lastPageInfo); + } + } + + public List getLocalOrder() { + return Collections.unmodifiableList(localOrder); + } + + /* + * citations + */ + + public List getCitationsInLocalOrder() { + return OOListUtil.map(localOrder, i -> citationsInStorageOrder.get(i)); + } + + /* + * indexInGlobalOrder + */ + + public void setIndexInGlobalOrder(Optional i) { + this.indexInGlobalOrder = i; + } + + public Optional getIndexInGlobalOrder() { + return this.indexInGlobalOrder; + } + + /* + * referenceMarkNameForLinking + */ + + public Optional getReferenceMarkNameForLinking() { + return referenceMarkNameForLinking; + } + + public void setReferenceMarkNameForLinking(Optional referenceMarkNameForLinking) { + this.referenceMarkNameForLinking = referenceMarkNameForLinking; + } + + /* + * citationMarker + */ + + public void setCitationMarker(Optional citationMarker) { + this.citationMarker = citationMarker; + } + + public Optional getCitationMarker() { + return this.citationMarker; + } + +} diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java new file mode 100644 index 00000000000..bac1e3c1387 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java @@ -0,0 +1,19 @@ +package org.jabref.model.openoffice.style; + +/** + * Identifies a citation group in a document. + */ +public class CitationGroupId { + String id; + public CitationGroupId(String id) { + this.id = id; + } + + /** + * CitationEntry needs some string identifying the group + * that it can pass back later. + */ + public String citationGroupIdAsString() { + return id; + } +} diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java new file mode 100644 index 00000000000..f68aa4f115c --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java @@ -0,0 +1,315 @@ +package org.jabref.model.openoffice.style; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Consumer; + +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.openoffice.util.OOListUtil; +import org.jabref.model.openoffice.util.OOPair; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * CitationGroups : the set of citation groups in the document. + * + * This is the main input (as well as output) for creating citation + * markers and bibliography. + * + */ +public class CitationGroups { + + private static final Logger LOGGER = LoggerFactory.getLogger(CitationGroups.class); + + private Map citationGroupsUnordered; + + /** + * Provides order of appearance for the citation groups. + */ + private Optional> globalOrder; + + /** + * This is going to be the bibliography + */ + private Optional bibliography; + + /** + * Constructor + */ + public CitationGroups(Map citationGroups) { + + this.citationGroupsUnordered = citationGroups; + + this.globalOrder = Optional.empty(); + this.bibliography = Optional.empty(); + } + + public int numberOfCitationGroups() { + return citationGroupsUnordered.size(); + } + + /** + * For each citation in {@code where} + * call {@code fun.accept(new Pair(citation, value));} + */ + public void distributeToCitations(List where, + Consumer> fun, + T value) { + + for (CitationPath p : where) { + CitationGroup cg = citationGroupsUnordered.get(p.group); + if (cg == null) { + LOGGER.warn("CitationGroups.distributeToCitations: group missing"); + continue; + } + Citation cit = cg.citationsInStorageOrder.get(p.storageIndexInGroup); + fun.accept(new OOPair<>(cit, value)); + } + } + + /* + * Look up each Citation in databases. + */ + public void lookupCitations(List databases) { + /* + * It is not clear which of the two solutions below is better. + */ + if (true) { + // collect-lookup-distribute + // + // CitationDatabaseLookupResult for the same citation key + // is the same object. Until we insert a new citation from the GUI. + CitedKeys cks = getCitedKeysUnordered(); + cks.lookupInDatabases(databases); + cks.distributeLookupResults(this); + } else { + // lookup each citation directly + // + // CitationDatabaseLookupResult for the same citation key + // may be a different object: CitedKey.addPath has to use equals, + // so CitationDatabaseLookupResult has to override Object.equals, + // which depends on BibEntry.equals and BibDatabase.equals + // doing the right thing. Seems to work. But what we gained + // from avoiding collect-and-distribute may be lost in more + // complicated consistency checking in addPath. + // + for (CitationGroup cg : getCitationGroupsUnordered()) { + for (Citation cit : cg.citationsInStorageOrder) { + cit.lookupInDatabases(databases); + } + } + } + } + + public List getCitationGroupsUnordered() { + return new ArrayList<>(citationGroupsUnordered.values()); + } + + /** + * Citation groups in {@code globalOrder} + */ + public List getCitationGroupsInGlobalOrder() { + if (globalOrder.isEmpty()) { + throw new RuntimeException("getCitationGroupsInGlobalOrder: not ordered yet"); + } + return OOListUtil.map(globalOrder.get(), cgid -> citationGroupsUnordered.get(cgid)); + } + + /** + * Impose an order of citation groups by providing the order + * of their citation group idendifiers. + * + * Also set indexInGlobalOrder for each citation group. + */ + public void setGlobalOrder(List globalOrder) { + Objects.requireNonNull(globalOrder); + if (globalOrder.size() != numberOfCitationGroups()) { + throw new RuntimeException("setGlobalOrder:" + + " globalOrder.size() != numberOfCitationGroups()"); + } + this.globalOrder = Optional.of(globalOrder); + + // Propagate to each CitationGroup + int i = 0; + for (CitationGroupId cgid : globalOrder) { + citationGroupsUnordered.get(cgid).setIndexInGlobalOrder(Optional.of(i)); + i++; + } + } + + public boolean hasGlobalOrder() { + return globalOrder.isPresent(); + } + + /** + * Impose an order for citations within each group. + */ + public void imposeLocalOrder(Comparator entryComparator) { + for (CitationGroup cg : citationGroupsUnordered.values()) { + cg.imposeLocalOrder(entryComparator); + } + } + + /** + * Collect citations into a list of cited sources using neither + * CitationGroup.globalOrder or Citation.localOrder + */ + public CitedKeys getCitedKeysUnordered() { + LinkedHashMap res = new LinkedHashMap<>(); + for (CitationGroup cg : citationGroupsUnordered.values()) { + int storageIndexInGroup = 0; + for (Citation cit : cg.citationsInStorageOrder) { + String key = cit.citationKey; + CitationPath p = new CitationPath(cg.cgid, storageIndexInGroup); + if (res.containsKey(key)) { + res.get(key).addPath(p, cit); + } else { + res.put(key, new CitedKey(key, p, cit)); + } + storageIndexInGroup++; + } + } + return new CitedKeys(res); + } + + /** + * CitedKeys created iterating citations in (globalOrder,localOrder) + */ + public CitedKeys getCitedKeysSortedInOrderOfAppearance() { + LinkedHashMap res = new LinkedHashMap<>(); + if (!hasGlobalOrder()) { + throw new RuntimeException("getSortedCitedKeys: no globalOrder"); + } + for (CitationGroup cg : getCitationGroupsInGlobalOrder()) { + for (int i : cg.getLocalOrder()) { + Citation cit = cg.citationsInStorageOrder.get(i); + String citationKey = cit.citationKey; + CitationPath p = new CitationPath(cg.cgid, i); + if (res.containsKey(citationKey)) { + res.get(citationKey).addPath(p, cit); + } else { + res.put(citationKey, new CitedKey(citationKey, p, cit)); + } + } + } + return new CitedKeys(res); + } + + public Optional getBibliography() { + return bibliography; + } + + /** + * @return Citation keys where lookupCitations() failed. + */ + public List getUnresolvedKeys() { + + CitedKeys bib = getBibliography().orElse(getCitedKeysUnordered()); + + List unresolvedKeys = new ArrayList<>(); + for (CitedKey ck : bib.values()) { + if (ck.getLookupResult().isEmpty()) { + unresolvedKeys.add(ck.citationKey); + } + } + return unresolvedKeys; + } + + public void createNumberedBibliographySortedInOrderOfAppearance() { + if (!bibliography.isEmpty()) { + throw new RuntimeException("createNumberedBibliographySortedInOrderOfAppearance:" + + " already have a bibliography"); + } + CitedKeys citedKeys = getCitedKeysSortedInOrderOfAppearance(); + citedKeys.numberCitedKeysInCurrentOrder(); + citedKeys.distributeNumbers(this); + bibliography = Optional.of(citedKeys); + } + + /** + * precondition: database lookup already performed (otherwise we just sort citation keys) + */ + public void createPlainBibliographySortedByComparator(Comparator entryComparator) { + if (!bibliography.isEmpty()) { + throw new RuntimeException("createPlainBibliographySortedByComparator:" + + " already have a bibliography"); + } + CitedKeys citedKeys = getCitedKeysUnordered(); + citedKeys.sortByComparator(entryComparator); + bibliography = Optional.of(citedKeys); + } + + /** + * precondition: database lookup already performed (otherwise we just sort citation keys) + */ + public void createNumberedBibliographySortedByComparator(Comparator entryComparator) { + if (!bibliography.isEmpty()) { + throw new RuntimeException("createNumberedBibliographySortedByComparator:" + + " already have a bibliography"); + } + CitedKeys citedKeys = getCitedKeysUnordered(); + citedKeys.sortByComparator(entryComparator); + citedKeys.numberCitedKeysInCurrentOrder(); + citedKeys.distributeNumbers(this); + bibliography = Optional.of(citedKeys); + } + + /* + * Query by CitationGroupId + */ + + public Optional getCitationGroup(CitationGroupId cgid) { + CitationGroup cg = citationGroupsUnordered.get(cgid); + return Optional.ofNullable(cg); + } + + /** + * Call this when the citation group is unquestionably there. + */ + public CitationGroup getCitationGroupOrThrow(CitationGroupId cgid) { + CitationGroup cg = citationGroupsUnordered.get(cgid); + if (cg == null) { + throw new RuntimeException("getCitationGroupOrThrow:" + + " the requested CitationGroup is not available"); + } + return cg; + } + + /* + * @return true if all citation groups have referenceMarkNameForLinking + */ + public boolean citationGroupsProvideReferenceMarkNameForLinking() { + for (CitationGroup cg : citationGroupsUnordered.values()) { + if (cg.getReferenceMarkNameForLinking().isEmpty()) { + return false; + } + } + return true; + } + + /* + * Callbacks. + */ + + public void afterCreateCitationGroup(CitationGroup cg) { + citationGroupsUnordered.put(cg.cgid, cg); + + globalOrder = Optional.empty(); + bibliography = Optional.empty(); + } + + public void afterRemoveCitationGroup(CitationGroup cg) { + citationGroupsUnordered.remove(cg.cgid); + globalOrder.map(l -> l.remove(cg.cgid)); + + bibliography = Optional.empty(); + } + +} diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java b/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java new file mode 100644 index 00000000000..866a0de34c3 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java @@ -0,0 +1,49 @@ +package org.jabref.model.openoffice.style; + +import java.util.Objects; + +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; + +public class CitationLookupResult { + + public final BibEntry entry; + public final BibDatabase database; + + public CitationLookupResult(BibEntry entry, BibDatabase database) { + Objects.requireNonNull(entry); + Objects.requireNonNull(database); + this.entry = entry; + this.database = database; + } + + /** + * Note: BibEntry overrides Object.equals, but BibDatabase does not. + * + * Consequently, {@code this.database.equals(that.database)} below + * is equivalent to {@code this.database == that.database}. + * + * Since within each GUI call we use a fixed list of + * databases, it is OK. + */ + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof CitationLookupResult)) { + return false; + } + CitationLookupResult that = (CitationLookupResult) o; + return this.entry.equals(that.entry) && this.database.equals(that.database); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + entry.hashCode(); + result = prime * result + database.hashCode(); + return result; + } +} diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationMarkerEntry.java b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerEntry.java new file mode 100644 index 00000000000..4ab2c626b68 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerEntry.java @@ -0,0 +1,30 @@ +package org.jabref.model.openoffice.style; + +import java.util.Optional; + +import org.jabref.model.openoffice.ootext.OOText; + +/** + * This is what we need for createCitationMarker to produce author-year + * citation markers. + */ +public interface CitationMarkerEntry extends CitationMarkerNormEntry { + + /** + * uniqueLetter or Optional.empty() if not needed. + */ + Optional getUniqueLetter(); + + /** + * pageInfo for this citation, provided by the user. + * May be empty, for none. + */ + Optional getPageInfo(); + + /** + * @return true if this citation is the first appearance of the + * source cited. Some styles use different limit on the number of + * authors shown in this case. + */ + boolean getIsFirstAppearanceOfSource(); +} diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNormEntry.java b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNormEntry.java new file mode 100644 index 00000000000..e9df5ec961f --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNormEntry.java @@ -0,0 +1,24 @@ +package org.jabref.model.openoffice.style; + +import java.util.Optional; + +/** + * This is what we need to produce normalized author-year citation + * markers. + */ +public interface CitationMarkerNormEntry { + + /** Citation key. This is what we usually get from the document. + * + * Used if getBibEntry() and/or getDatabase() returns + * empty, which indicates failure to lookup in the databases. + * + */ + String getCitationKey(); + + /** Result of looking up citation key in databases. + * + * Optional.empty() indicates unresolved citation. + */ + Optional getLookupResult(); +} diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNumericBibEntry.java b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNumericBibEntry.java new file mode 100644 index 00000000000..398282113b8 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNumericBibEntry.java @@ -0,0 +1,19 @@ +package org.jabref.model.openoffice.style; + +import java.util.Optional; + +/** + * This is for the numeric bibliography labels. + */ +public interface CitationMarkerNumericBibEntry { + + /** + * For unresolved citation we show the citation key. + */ + String getCitationKey(); + + /** + * @return Optional.empty() for unresolved + */ + Optional getNumber(); +} diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNumericEntry.java b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNumericEntry.java new file mode 100644 index 00000000000..9c0c6081489 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNumericEntry.java @@ -0,0 +1,20 @@ +package org.jabref.model.openoffice.style; + +import java.util.Optional; + +import org.jabref.model.openoffice.ootext.OOText; + +/** + * This is what we need for numeric citation markers. + */ +public interface CitationMarkerNumericEntry { + + String getCitationKey(); + + /** + * @return Optional.empty() for unresolved + */ + Optional getNumber(); + + Optional getPageInfo(); +} diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationPath.java b/src/main/java/org/jabref/model/openoffice/style/CitationPath.java new file mode 100644 index 00000000000..05aeb6547f6 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/CitationPath.java @@ -0,0 +1,17 @@ +package org.jabref.model.openoffice.style; + +/** + * Identifies a citation with the citation group containing it and + * its storage index within. + */ +public class CitationPath { + + public final CitationGroupId group; + + public final int storageIndexInGroup; + + CitationPath(CitationGroupId group, int storageIndexInGroup) { + this.group = group; + this.storageIndexInGroup = storageIndexInGroup; + } +} diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationType.java b/src/main/java/org/jabref/model/openoffice/style/CitationType.java new file mode 100644 index 00000000000..14189e903e3 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/CitationType.java @@ -0,0 +1,24 @@ +package org.jabref.model.openoffice.style; + +/* + * Presentation types of citation groups. + */ +public enum CitationType { + + AUTHORYEAR_PAR, + AUTHORYEAR_INTEXT, + INVISIBLE_CIT; + + public boolean inParenthesis() { + return switch (this) { + case AUTHORYEAR_PAR, INVISIBLE_CIT -> true; + case AUTHORYEAR_INTEXT -> false; + }; + } + + public boolean withText() { + return (this != INVISIBLE_CIT); + } +} + + diff --git a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java new file mode 100644 index 00000000000..08b2ffb1bb8 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java @@ -0,0 +1,141 @@ +package org.jabref.model.openoffice.style; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.openoffice.ootext.OOText; + +/** + * Cited keys are collected from the citations in citation groups. + * + * They contain backreferences to the corresponding citations in + * {@code where}. This allows the extra information generated using + * CitedKeys to be distributed back to the in-text citations. + */ +public class CitedKey implements + ComparableCitedKey, + CitationMarkerNormEntry, + CitationMarkerNumericBibEntry { + + public final String citationKey; + private final List where; + + private Optional db; + private Optional number; // For Numbered citation styles. + private Optional uniqueLetter; // For AuthorYear citation styles. + private Optional normCitMarker; // For AuthorYear citation styles. + + CitedKey(String citationKey, CitationPath p, Citation cit) { + + this.citationKey = citationKey; + this.where = new ArrayList<>(); // remember order + this.where.add(p); + + // synchronized with Citation + this.db = cit.getLookupResult(); + this.number = cit.getNumber(); + this.uniqueLetter = cit.getUniqueLetter(); + + // CitedKey only + this.normCitMarker = Optional.empty(); + } + + /* + * Implement ComparableCitedKey + */ + @Override + public String getCitationKey() { + return citationKey; + } + + @Override + public Optional getBibEntry() { + return (db.isPresent() + ? Optional.of(db.get().entry) + : Optional.empty()); + } + + /* + * Implement CitationMarkerNormEntry + */ + @Override + public Optional getLookupResult() { + return db; + } + + /* + * Implement CitationMarkerNumericBibEntry + */ + @Override + public Optional getNumber() { + return number; + } + + public void setNumber(Optional number) { + this.number = number; + } + + public List getCitationPaths() { + return new ArrayList<>(where); + } + + public Optional getUniqueLetter() { + return uniqueLetter; + } + + public void setUniqueLetter(Optional uniqueLetter) { + this.uniqueLetter = uniqueLetter; + } + + public Optional getNormalizedCitationMarker() { + return normCitMarker; + } + + public void setNormalizedCitationMarker(Optional normCitMarker) { + this.normCitMarker = normCitMarker; + } + + /** + * Appends to end of {@code where} + */ + void addPath(CitationPath p, Citation cit) { + this.where.add(p); + + // Check consistency + if (!cit.getLookupResult().equals(this.db)) { + throw new RuntimeException("CitedKey.addPath: mismatch on cit.db"); + } + if (!cit.getNumber().equals(this.number)) { + throw new RuntimeException("CitedKey.addPath: mismatch on cit.number"); + } + if (!cit.getUniqueLetter().equals(this.uniqueLetter)) { + throw new RuntimeException("CitedKey.addPath: mismatch on cit.uniqueLetter"); + } + } + + /* + * Lookup + */ + void lookupInDatabases(List databases) { + this.db = Citation.lookup(databases, this.citationKey); + } + + void distributeLookupResult(CitationGroups cgs) { + cgs.distributeToCitations(where, Citation::setLookupResult, db); + } + + /* + * Make unique using a letter or by numbering + */ + + void distributeNumber(CitationGroups cgs) { + cgs.distributeToCitations(where, Citation::setNumber, number); + } + + void distributeUniqueLetter(CitationGroups cgs) { + cgs.distributeToCitations(where, Citation::setUniqueLetter, uniqueLetter); + } +} diff --git a/src/main/java/org/jabref/model/openoffice/style/CitedKeys.java b/src/main/java/org/jabref/model/openoffice/style/CitedKeys.java new file mode 100644 index 00000000000..898fadbebe9 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/CitedKeys.java @@ -0,0 +1,84 @@ +package org.jabref.model.openoffice.style; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Optional; + +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; + +public class CitedKeys { + + /** + * Order-preserving map from citation keys to associated data. + */ + private LinkedHashMap data; + + CitedKeys(LinkedHashMap data) { + this.data = data; + } + + /** + * The cited keys in their current order. + */ + public List values() { + return new ArrayList<>(data.values()); + } + + public CitedKey get(String citationKey) { + return data.get(citationKey); + } + + /** + * Sort entries for the bibliography. + */ + void sortByComparator(Comparator entryComparator) { + List cks = new ArrayList<>(data.values()); + cks.sort(new CompareCitedKey(entryComparator, true)); + LinkedHashMap newData = new LinkedHashMap<>(); + for (CitedKey ck : cks) { + newData.put(ck.citationKey, ck); + } + data = newData; + } + + void numberCitedKeysInCurrentOrder() { + int i = 1; + for (CitedKey ck : data.values()) { + if (ck.getLookupResult().isPresent()) { + ck.setNumber(Optional.of(i)); + i++; + } else { + // Unresolved citations do not get a number. + ck.setNumber(Optional.empty()); + } + } + } + + public void lookupInDatabases(List databases) { + for (CitedKey ck : this.data.values()) { + ck.lookupInDatabases(databases); + } + } + + void distributeLookupResults(CitationGroups cgs) { + for (CitedKey ck : this.data.values()) { + ck.distributeLookupResult(cgs); + } + } + + void distributeNumbers(CitationGroups cgs) { + for (CitedKey ck : this.data.values()) { + ck.distributeNumber(cgs); + } + } + + public void distributeUniqueLetters(CitationGroups cgs) { + for (CitedKey ck : this.data.values()) { + ck.distributeUniqueLetter(cgs); + } + } + +} diff --git a/src/main/java/org/jabref/model/openoffice/style/ComparableCitation.java b/src/main/java/org/jabref/model/openoffice/style/ComparableCitation.java new file mode 100644 index 00000000000..a6ac799b017 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/ComparableCitation.java @@ -0,0 +1,13 @@ +package org.jabref.model.openoffice.style; + +import java.util.Optional; + +import org.jabref.model.openoffice.ootext.OOText; + +/** + * When sorting citations (in a group), we also consider pageInfo. + * Otherwise we sort citations as cited keys. + */ +public interface ComparableCitation extends ComparableCitedKey { + public Optional getPageInfo(); +} diff --git a/src/main/java/org/jabref/model/openoffice/style/ComparableCitedKey.java b/src/main/java/org/jabref/model/openoffice/style/ComparableCitedKey.java new file mode 100644 index 00000000000..0d4c8e2efce --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/ComparableCitedKey.java @@ -0,0 +1,16 @@ +package org.jabref.model.openoffice.style; + +import java.util.Optional; + +import org.jabref.model.entry.BibEntry; + +/** + * This is what we need to sort bibliography entries. + */ +public interface ComparableCitedKey { + + public String getCitationKey(); + + public Optional getBibEntry(); +} + diff --git a/src/main/java/org/jabref/model/openoffice/style/CompareCitation.java b/src/main/java/org/jabref/model/openoffice/style/CompareCitation.java new file mode 100644 index 00000000000..916f8ec610c --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/CompareCitation.java @@ -0,0 +1,30 @@ +package org.jabref.model.openoffice.style; + +import java.util.Comparator; + +import org.jabref.model.entry.BibEntry; + +/* + * Given a Comparator provide a Comparator + * that can handle unresolved citation keys and takes pageInfo into account. + */ +public class CompareCitation implements Comparator { + + private CompareCitedKey citedKeyComparator; + + CompareCitation(Comparator entryComparator, boolean unresolvedComesFirst) { + this.citedKeyComparator = new CompareCitedKey(entryComparator, unresolvedComesFirst); + } + + public int compare(ComparableCitation a, ComparableCitation b) { + int res = citedKeyComparator.compare(a, b); + + // Also consider pageInfo + if (res == 0) { + res = PageInfo.comparePageInfo(a.getPageInfo(), b.getPageInfo()); + } + return res; + } +} + + diff --git a/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java b/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java new file mode 100644 index 00000000000..439d0556c2d --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java @@ -0,0 +1,41 @@ +package org.jabref.model.openoffice.style; + +import java.util.Comparator; +import java.util.Optional; + +import org.jabref.model.entry.BibEntry; + +/* + * Given a Comparator provide a Comparator + * that also handles unresolved citation keys. + */ +public class CompareCitedKey implements Comparator { + + Comparator entryComparator; + boolean unresolvedComesFirst; + + CompareCitedKey(Comparator entryComparator, boolean unresolvedComesFirst) { + this.entryComparator = entryComparator; + this.unresolvedComesFirst = unresolvedComesFirst; + } + + public int compare(ComparableCitedKey a, ComparableCitedKey b) { + Optional aBibEntry = a.getBibEntry(); + Optional bBibEntry = b.getBibEntry(); + final int mul = unresolvedComesFirst ? (+1) : (-1); + + int res = 0; + if (aBibEntry.isEmpty() && bBibEntry.isEmpty()) { + // Both are unresolved: compare them by citation key. + res = a.getCitationKey().compareTo(b.getCitationKey()); + } else if (aBibEntry.isEmpty()) { + return -mul; + } else if (bBibEntry.isEmpty()) { + return mul; + } else { + // Proper comparison of entries + res = entryComparator.compare(aBibEntry.get(), bBibEntry.get()); + } + return res; + } +} diff --git a/src/main/java/org/jabref/model/openoffice/style/NonUniqueCitationMarker.java b/src/main/java/org/jabref/model/openoffice/style/NonUniqueCitationMarker.java new file mode 100644 index 00000000000..e7d988ee216 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/NonUniqueCitationMarker.java @@ -0,0 +1,15 @@ +package org.jabref.model.openoffice.style; + +/** + * What should createCitationMarker do if it discovers that + * uniqueLetters provided are not sufficient for unique presentation? + */ +public enum NonUniqueCitationMarker { + + /** Give an insufficient representation anyway. */ + FORGIVEN, + + /** Throw a RuntimeException */ + THROWS +} + diff --git a/src/main/java/org/jabref/model/openoffice/style/OODataModel.java b/src/main/java/org/jabref/model/openoffice/style/OODataModel.java new file mode 100644 index 00000000000..50c3a9e4842 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/OODataModel.java @@ -0,0 +1,38 @@ +package org.jabref.model.openoffice.style; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.jabref.model.openoffice.ootext.OOText; + +/** What is the data stored? */ +public enum OODataModel { + + /** + * JabRef52: pageInfo belongs to CitationGroup, not Citation. + */ + JabRef52, + + /** + * JabRef53: pageInfo belongs to Citation. + */ + JabRef53; + + /** + * @param pageInfo Nullable. + * @return JabRef53 style pageInfo list with pageInfo in the last slot. + */ + public static List> fakePageInfos(String pageInfo, int nCitations) { + List> pageInfos = new ArrayList<>(nCitations); + for (int i = 0; i < nCitations; i++) { + pageInfos.add(Optional.empty()); + } + if (pageInfo != null) { + final int last = nCitations - 1; + Optional pi = Optional.ofNullable(OOText.fromString(pageInfo)); + pageInfos.set(last, PageInfo.normalizePageInfo(pi)); + } + return pageInfos; + } +} diff --git a/src/main/java/org/jabref/model/openoffice/style/PageInfo.java b/src/main/java/org/jabref/model/openoffice/style/PageInfo.java new file mode 100644 index 00000000000..6807ecf0753 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/style/PageInfo.java @@ -0,0 +1,47 @@ +package org.jabref.model.openoffice.style; + +import java.util.Optional; + +import org.jabref.model.openoffice.ootext.OOText; + +public class PageInfo { + + private PageInfo() { + // hide public constructor + } + + /* + * pageInfo normalization + */ + public static Optional normalizePageInfo(Optional o) { + if (o == null || o.isEmpty() || "".equals(OOText.toString(o.get()))) { + return Optional.empty(); + } + String s = OOText.toString(o.get()); + if (s.trim().equals("")) { + return Optional.empty(); + } + return Optional.of(OOText.fromString(s.trim())); + } + + /** + * Defines sort order for pageInfo strings. + * + * Optional.empty comes before non-empty. + */ + public static int comparePageInfo(Optional a, Optional b) { + + Optional aa = PageInfo.normalizePageInfo(a); + Optional bb = PageInfo.normalizePageInfo(b); + if (aa.isEmpty() && bb.isEmpty()) { + return 0; + } + if (aa.isEmpty()) { + return -1; + } + if (bb.isEmpty()) { + return +1; + } + return aa.get().asString().compareTo(bb.get().asString()); + } +} diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java index 786e678324c..bf0bdf945a4 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java @@ -11,7 +11,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.jabref.logic.layout.Layout; import org.jabref.logic.layout.LayoutFormatterPreferences; @@ -20,6 +24,14 @@ import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.types.StandardEntryType; import org.jabref.model.entry.types.UnknownEntryType; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.Citation; +import org.jabref.model.openoffice.style.CitationLookupResult; +import org.jabref.model.openoffice.style.CitationMarkerEntry; +import org.jabref.model.openoffice.style.CitationMarkerNumericBibEntry; +import org.jabref.model.openoffice.style.CitationMarkerNumericEntry; +import org.jabref.model.openoffice.style.NonUniqueCitationMarker; +import org.jabref.model.openoffice.style.PageInfo; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -80,13 +92,86 @@ void testNumerical() throws IOException { assertTrue(style.isSortByPosition()); } + /* + * begin helpers + */ + static String runGetNumCitationMarker2a(OOBibStyle style, + List num, int minGroupingCount, boolean inList ) { + return OOBibStyleTestHelper.runGetNumCitationMarker2a(style, num, minGroupingCount, inList); + } + + static CitationMarkerNumericEntry numEntry(String key, int num, String pageInfoOrNull) { + return OOBibStyleTestHelper.numEntry(key, num, pageInfoOrNull); + } + + static CitationMarkerNumericBibEntry numBibEntry(String key, Optional num) { + return OOBibStyleTestHelper.numBibEntry(key, num); + } + + static String runGetNumCitationMarker2b(OOBibStyle style, + int minGroupingCount, + CitationMarkerNumericEntry... s) { + List input = Stream.of(s).collect(Collectors.toList()); + OOText res = style.getNumCitationMarker2(input, minGroupingCount); + return res.asString(); + } + + static CitationMarkerEntry makeCitationMarkerEntry(BibEntry entry, + BibDatabase database, + String uniqueLetterQ, + String pageInfoQ, + boolean isFirstAppearanceOfSource) { + return OOBibStyleTestHelper.makeCitationMarkerEntry(entry, + database, + uniqueLetterQ, + pageInfoQ, + isFirstAppearanceOfSource ); + } + + /* + * Similar to old API. pageInfo is new, and unlimAuthors is + * replaced with isFirstAppearanceOfSource + */ + static String getCitationMarker2(OOBibStyle style, + List entries, + Map entryDBMap, + boolean inParenthesis, + String[] uniquefiers, + Boolean[] isFirstAppearanceOfSource, + String[] pageInfo) { + return OOBibStyleTestHelper.getCitationMarker2(style, + entries, + entryDBMap, + inParenthesis, + uniquefiers, + isFirstAppearanceOfSource, + pageInfo ); + } + + /* + * end helpers + */ + + @Test void testGetNumCitationMarker() throws IOException { OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, layoutFormatterPreferences); assertEquals("[1] ", style.getNumCitationMarker(Arrays.asList(1), -1, true)); + assertEquals("[1] ", runGetNumCitationMarker2a(style, Arrays.asList(1), -1, true)); + assertEquals("[1]", style.getNumCitationMarker(Arrays.asList(1), -1, false)); + assertEquals("[1]", runGetNumCitationMarker2a(style, Arrays.asList(1), -1, false)); + assertEquals("[1]", runGetNumCitationMarker2b(style, -1, numEntry("key", 1, null))); + assertEquals("[1] ", style.getNumCitationMarker(Arrays.asList(1), 0, true)); + assertEquals("[1] ", runGetNumCitationMarker2a(style, Arrays.asList(1), 0, true)); + + /* + * The following tests as for a numeric label for a + * bibliography entry containing more than one numbers. + * We do not need this, not reproduced. + */ assertEquals("[1-3] ", style.getNumCitationMarker(Arrays.asList(1, 2, 3), 1, true)); assertEquals("[1; 2; 3] ", style.getNumCitationMarker(Arrays.asList(1, 2, 3), 5, true)); assertEquals("[1; 2; 3] ", style.getNumCitationMarker(Arrays.asList(1, 2, 3), -1, true)); @@ -95,12 +180,24 @@ void testGetNumCitationMarker() throws IOException { String citation = style.getNumCitationMarker(Arrays.asList(1), -1, false); assertEquals("[1; pp. 55-56]", style.insertPageInfo(citation, "pp. 55-56")); + + CitationMarkerNumericEntry e2 = numEntry("key", 1, "pp. 55-56"); + assertEquals(true, e2.getPageInfo().isPresent()); + assertEquals("pp. 55-56", e2.getPageInfo().get().asString()); + citation = runGetNumCitationMarker2b(style, -1, e2); + assertEquals("[1; pp. 55-56]", citation); + + OOBibStyleTestHelper.testGetNumCitationMarkerExtra(style); } @Test void testGetNumCitationMarkerUndefined() throws IOException { OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, layoutFormatterPreferences); + /* + * Testing bibliography labels with multiple numbers again. + * Not reproduced. + */ assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "; 2-4] ", style.getNumCitationMarker(Arrays.asList(4, 2, 3, 0), 1, true)); @@ -113,6 +210,55 @@ void testGetNumCitationMarkerUndefined() throws IOException { assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "; " + OOBibStyle.UNDEFINED_CITATION_MARKER + "; " + OOBibStyle.UNDEFINED_CITATION_MARKER + "] ", style.getNumCitationMarker(Arrays.asList(0, 0, 0), 1, true)); + + /* + * We have these instead: + */ + + // unresolved citations look like [??key] + assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "]", + runGetNumCitationMarker2b(style, 1, + numEntry("key",0,null))); + + // pageInfo is shown for unresolved citations + assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "; p1]", + runGetNumCitationMarker2b(style, 1, + numEntry("key",0,"p1"))); + + // unresolved citations sorted to the front + assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "; 2-4]", + runGetNumCitationMarker2b(style, 1, + numEntry("x4",4,""), + numEntry("x2",2,""), + numEntry("x3",3,""), + numEntry("key",0,""))); + + assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "; 1-3]", + runGetNumCitationMarker2b(style, 1, + numEntry("x1",1,""), + numEntry("x2",2,""), + numEntry("y3",3,""), + numEntry("key",0,""))); + + // multiple unresolved citations are not collapsed + assertEquals("[" + + OOBibStyle.UNDEFINED_CITATION_MARKER + "x1" + "; " + + OOBibStyle.UNDEFINED_CITATION_MARKER + "x2" + "; " + + OOBibStyle.UNDEFINED_CITATION_MARKER + "x3" + "]", + runGetNumCitationMarker2b(style, 1, + numEntry("x1",0,""), + numEntry("x2",0,""), + numEntry("x3",0,""))); + + /* + * BIBLIOGRAPHY + */ + { + CitationMarkerNumericBibEntry x = numBibEntry("key", Optional.empty()); + assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "] ", + style.getNumCitationMarkerForBibliography(x).asString()); + } + } @Test @@ -120,14 +266,21 @@ void testGetCitProperty() throws IOException { OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, layoutFormatterPreferences); assertEquals(", ", style.getStringCitProperty("AuthorSeparator")); + + // old assertEquals(3, style.getIntCitProperty("MaxAuthors")); assertTrue(style.getBooleanCitProperty(OOBibStyle.MULTI_CITE_CHRONOLOGICAL)); + // new + assertEquals(3, style.getMaxAuthors()); + assertTrue(style.getMultiCiteChronological()); + assertEquals("Default", style.getCitationCharacterFormat()); assertEquals("Default [number] style file.", style.getName()); Set journals = style.getJournals(); assertTrue(journals.contains("Journal name 1")); } + @Test void testGetCitationMarker() throws IOException { OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, layoutFormatterPreferences); @@ -138,17 +291,39 @@ void testGetCitationMarker() throws IOException { .withField(StandardField.PUBLISHER, "ACM") .withField(StandardField.TITLE, "Extending XP practices to support security requirements engineering") .withField(StandardField.PAGES, "11--18"); + entry.setCitationKey("Bostrom2006"); // citation key is not optional now BibDatabase database = new BibDatabase(); database.insertEntry(entry); Map entryDBMap = new HashMap<>(); entryDBMap.put(entry, database); + // Check what unlimAuthors values correspond to isFirstAppearanceOfSource false/true + assertEquals(3, style.getMaxAuthors()); + assertEquals(-1, style.getMaxAuthorsFirst()); + assertEquals("[Boström et al., 2006]", style.getCitationMarker(Collections.singletonList(entry), entryDBMap, true, null, null)); + assertEquals("[Boström et al., 2006]", + getCitationMarker2(style, + Collections.singletonList(entry), entryDBMap, + true, null, null, null)); + assertEquals("Boström et al. [2006]", style.getCitationMarker(Collections.singletonList(entry), entryDBMap, false, null, new int[]{3})); + assertEquals("Boström et al. [2006]", + getCitationMarker2(style, + Collections.singletonList(entry), entryDBMap, + false, null, new Boolean[]{false}, null)); + assertEquals("[Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006]", style.getCitationMarker(Collections.singletonList(entry), entryDBMap, true, null, new int[]{5})); + assertEquals("[Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006]", + getCitationMarker2(style, + Collections.singletonList(entry), entryDBMap, + true, + null, + new Boolean[]{true} /* corresponds to -1, not 5 */, + null)); } @Test @@ -225,6 +400,7 @@ void testInstitutionAuthorMarker() throws IOException { BibDatabase database = new BibDatabase(); BibEntry entry = new BibEntry(); + entry.setCitationKey("JabRef2016"); entry.setType(StandardEntryType.Article); entry.setField(StandardField.AUTHOR, "{JabRef Development Team}"); entry.setField(StandardField.TITLE, "JabRef Manual"); @@ -233,6 +409,10 @@ void testInstitutionAuthorMarker() throws IOException { entries.add(entry); entryDBMap.put(entry, database); assertEquals("[JabRef Development Team, 2016]", style.getCitationMarker(entries, entryDBMap, true, null, null)); + + assertEquals("[JabRef Development Team, 2016]", + getCitationMarker2(style, + entries, entryDBMap, true, null, null, null)); } @Test @@ -513,4 +693,225 @@ void testIsValidWithDefaultSectionAtTheStart() throws Exception { OOBibStyle style = new OOBibStyle("testWithDefaultAtFirstLIne.jstyle", layoutFormatterPreferences); assertTrue(style.isValid()); } + + @Test + void testGetCitationMarkerJoinFirst() throws IOException { + OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, + layoutFormatterPreferences); + + // Question: What should happen if some of the sources is + // marked as isFirstAppearanceOfSource? + // This test documents what is happening now. + + // Two entries with identical normalizedMarkers and many authors. + BibEntry entry1 = new BibEntry() + .withField(StandardField.AUTHOR, + "Gustav Bostr\\\"{o}m" + + " and Jaana W\\\"{a}yrynen" + + " and Marine Bod\\'{e}n" + + " and Konstantin Beznosov" + + " and Philippe Kruchten") + .withField(StandardField.YEAR, "2006") + .withField(StandardField.BOOKTITLE, "A book 1") + .withField(StandardField.PUBLISHER, "ACM") + .withField(StandardField.TITLE, "Title 1") + .withField(StandardField.PAGES, "11--18"); + entry1.setCitationKey("b1"); + + BibEntry entry2 = new BibEntry() + .withField(StandardField.AUTHOR, + "Gustav Bostr\\\"{o}m" + + " and Jaana W\\\"{a}yrynen" + + " and Marine Bod\\'{e}n" + + " and Konstantin Beznosov" + + " and Philippe Kruchten") + .withField(StandardField.YEAR, "2006") + .withField(StandardField.BOOKTITLE, "A book 2") + .withField(StandardField.PUBLISHER, "ACM") + .withField(StandardField.TITLE, "title2") + .withField(StandardField.PAGES, "11--18"); + entry2.setCitationKey("b2"); + + // Last Author differs. + BibEntry entry3 = new BibEntry() + .withField(StandardField.AUTHOR, + "Gustav Bostr\\\"{o}m" + + " and Jaana W\\\"{a}yrynen" + + " and Marine Bod\\'{e}n" + + " and Konstantin Beznosov" + + " and Philippe NotKruchten") + .withField(StandardField.YEAR, "2006") + .withField(StandardField.BOOKTITLE, "A book 3") + .withField(StandardField.PUBLISHER, "ACM") + .withField(StandardField.TITLE, "title3") + .withField(StandardField.PAGES, "11--18"); + entry3.setCitationKey("b3"); + + BibDatabase database = new BibDatabase(); + database.insertEntry(entry1); + database.insertEntry(entry2); + database.insertEntry(entry3); + + // Without pageInfo, two isFirstAppearanceOfSource may be joined. + // The third is NotKruchten, should not be joined. + if (true) { + List citationMarkerEntries = new ArrayList<>(); + CitationMarkerEntry cm1 = + makeCitationMarkerEntry(entry1, database, "a", null, true); + citationMarkerEntries.add(cm1); + CitationMarkerEntry cm2 = + makeCitationMarkerEntry(entry2, database, "b", null, true); + citationMarkerEntries.add(cm2); + CitationMarkerEntry cm3 = + makeCitationMarkerEntry(entry3, database, "c", null, true); + citationMarkerEntries.add(cm3); + + assertEquals("[Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006a,b" + +"; Boström, Wäyrynen, Bodén, Beznosov & NotKruchten, 2006c]", + style.createCitationMarker(citationMarkerEntries, + true, + NonUniqueCitationMarker.THROWS).asString()); + + assertEquals("Boström, Wäyrynen, Bodén, Beznosov & Kruchten [2006a,b]" + + "; Boström, Wäyrynen, Bodén, Beznosov & NotKruchten [2006c]", + style.createCitationMarker(citationMarkerEntries, + false, + NonUniqueCitationMarker.THROWS).asString()); + } + + // Without pageInfo, only the first is isFirstAppearanceOfSource. + // The second may be joined, based on expanded normalizedMarkers. + // The third is NotKruchten, should not be joined. + if (true) { + List citationMarkerEntries = new ArrayList<>(); + CitationMarkerEntry cm1 = + makeCitationMarkerEntry(entry1, database, "a", null, true); + citationMarkerEntries.add(cm1); + CitationMarkerEntry cm2 = + makeCitationMarkerEntry(entry2, database, "b", null, false); + citationMarkerEntries.add(cm2); + CitationMarkerEntry cm3 = + makeCitationMarkerEntry(entry3, database, "c", null, false); + citationMarkerEntries.add(cm3); + + assertEquals("[Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006a,b" + +"; Boström et al., 2006c]", + style.createCitationMarker(citationMarkerEntries, + true, + NonUniqueCitationMarker.THROWS).asString()); + + } + // Without pageInfo, only the second is isFirstAppearanceOfSource. + // The second is not joined, because it is a first appearance, thus + // requires more names to be shown. + // The third is NotKruchten, should not be joined. + if (true) { + List citationMarkerEntries = new ArrayList<>(); + CitationMarkerEntry cm1 = + makeCitationMarkerEntry(entry1, database, "a", null, false); + citationMarkerEntries.add(cm1); + CitationMarkerEntry cm2 = + makeCitationMarkerEntry(entry2, database, "b", null, true); + citationMarkerEntries.add(cm2); + CitationMarkerEntry cm3 = + makeCitationMarkerEntry(entry3, database, "c", null, false); + citationMarkerEntries.add(cm3); + + assertEquals("[Boström et al., 2006a" + + "; Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006b" + + "; Boström et al., 2006c]", + style.createCitationMarker(citationMarkerEntries, + true, + NonUniqueCitationMarker.THROWS).asString()); + } + + // Without pageInfo, neither is isFirstAppearanceOfSource. + // The second is joined. + // The third is NotKruchten, but is joined because NotKruchten is not among the names shown. + // Is this the correct behaviour? + if (true) { + List citationMarkerEntries = new ArrayList<>(); + CitationMarkerEntry cm1 = + makeCitationMarkerEntry(entry1, database, "a", null, false); + citationMarkerEntries.add(cm1); + CitationMarkerEntry cm2 = + makeCitationMarkerEntry(entry2, database, "b", null, false); + citationMarkerEntries.add(cm2); + CitationMarkerEntry cm3 = + makeCitationMarkerEntry(entry3, database, "c", null, false); + citationMarkerEntries.add(cm3); + + assertEquals("[Boström et al., 2006a,b,c]", + style.createCitationMarker(citationMarkerEntries, + true, + NonUniqueCitationMarker.THROWS).asString()); + } + + // With pageInfo: different entries with identical non-null pageInfo: not joined. + // XY [2000a,b,c; p1] whould be confusing. + if (true) { + List citationMarkerEntries = new ArrayList<>(); + CitationMarkerEntry cm1 = + makeCitationMarkerEntry(entry1, database, "a", "p1", false); + citationMarkerEntries.add(cm1); + CitationMarkerEntry cm2 = + makeCitationMarkerEntry(entry2, database, "b", "p1", false); + citationMarkerEntries.add(cm2); + CitationMarkerEntry cm3 = + makeCitationMarkerEntry(entry3, database, "c", "p1", false); + citationMarkerEntries.add(cm3); + + assertEquals("[Boström et al., 2006a; p1" + + "; Boström et al., 2006b; p1" + + "; Boström et al., 2006c; p1]", + style.createCitationMarker(citationMarkerEntries, + true, + NonUniqueCitationMarker.THROWS).asString()); + } + + // With pageInfo: same entries with identical non-null pageInfo: collapsed. + // Note: "same" here looks at the visible parts and citation key only, + // but ignores the rest. Normally the citation key should distinguish. + if (true) { + List citationMarkerEntries = new ArrayList<>(); + CitationMarkerEntry cm1 = + makeCitationMarkerEntry(entry1, database, "a", "p1", false); + citationMarkerEntries.add(cm1); + CitationMarkerEntry cm2 = + makeCitationMarkerEntry(entry1, database, "a", "p1", false); + citationMarkerEntries.add(cm2); + CitationMarkerEntry cm3 = + makeCitationMarkerEntry(entry1, database, "a", "p1", false); + citationMarkerEntries.add(cm3); + + assertEquals("[Boström et al., 2006a; p1]", + style.createCitationMarker(citationMarkerEntries, + true, + NonUniqueCitationMarker.THROWS).asString()); + } + // With pageInfo: same entries with different pageInfo: kept separate. + // Empty ("") and missing pageInfos considered equal, thus collapsed. + if (true) { + List citationMarkerEntries = new ArrayList<>(); + CitationMarkerEntry cm1 = + makeCitationMarkerEntry(entry1, database, "a", "p1", false); + citationMarkerEntries.add(cm1); + CitationMarkerEntry cm2 = + makeCitationMarkerEntry(entry1, database, "a", "p2", false); + citationMarkerEntries.add(cm2); + CitationMarkerEntry cm3 = + makeCitationMarkerEntry(entry1, database, "a", "", false); + citationMarkerEntries.add(cm3); + CitationMarkerEntry cm4 = + makeCitationMarkerEntry(entry1, database, "a", null, false); + citationMarkerEntries.add(cm4); + + assertEquals("[Boström et al., 2006a; p1" + + "; Boström et al., 2006a; p2" + + "; Boström et al., 2006a]", + style.createCitationMarker(citationMarkerEntries, + true, + NonUniqueCitationMarker.THROWS).asString()); + } + } } diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java new file mode 100644 index 00000000000..c8302030fc6 --- /dev/null +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java @@ -0,0 +1,359 @@ +package org.jabref.logic.openoffice.style; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.jabref.logic.layout.Layout; +import org.jabref.logic.layout.LayoutFormatterPreferences; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.StandardField; +import org.jabref.model.entry.types.StandardEntryType; +import org.jabref.model.entry.types.UnknownEntryType; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.Citation; +import org.jabref.model.openoffice.style.CitationLookupResult; +import org.jabref.model.openoffice.style.CitationMarkerEntry; +import org.jabref.model.openoffice.style.CitationMarkerNumericBibEntry; +import org.jabref.model.openoffice.style.CitationMarkerNumericEntry; +import org.jabref.model.openoffice.style.NonUniqueCitationMarker; +import org.jabref.model.openoffice.style.PageInfo; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Answers; + +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.Assertions.assertTrue; +import static org.mockito.Mockito.mock; + +class OOBibStyleTestHelper { + /* + * begin Helpers for testing style.getNumCitationMarker2 + */ + + /* + * Minimal implementation for CitationMarkerNumericEntry + */ + static class CitationMarkerNumericEntryImpl implements CitationMarkerNumericEntry { + + /* + * The number encoding "this entry is unresolved" for the constructor. + */ + public final static int UNRESOLVED_ENTRY_NUMBER = 0; + + private String citationKey; + private Optional num; + private Optional pageInfo; + + public CitationMarkerNumericEntryImpl(String citationKey, int num, Optional pageInfo) { + this.citationKey = citationKey; + this.num = (num == UNRESOLVED_ENTRY_NUMBER + ? Optional.empty() + : Optional.of(num)); + this.pageInfo = PageInfo.normalizePageInfo(pageInfo); + } + + @Override + public String getCitationKey() { + return citationKey; + } + + @Override + public Optional getNumber() { + return num; + } + + @Override + public Optional getPageInfo() { + return pageInfo; + } + } + + static class CitationMarkerNumericBibEntryImpl implements CitationMarkerNumericBibEntry { + String key; + Optional number; + + public CitationMarkerNumericBibEntryImpl(String key, Optional number) { + this.key = key; + this.number = number; + } + + @Override + public String getCitationKey() { + return key; + } + + @Override + public Optional getNumber() { + return number; + } + } + + static CitationMarkerNumericBibEntry numBibEntry(String key, Optional number) { + return new CitationMarkerNumericBibEntryImpl(key, number); + } + + /** + * Reproduce old method + * + * @param inList true means label for the bibliography + */ + static String runGetNumCitationMarker2a(OOBibStyle style, + List num, int minGroupingCount, boolean inList ) { + if (inList) { + if (num.size() != 1) { + throw new RuntimeException("Numeric label for the bibliography with " + + String.valueOf(num.size()) + " numbers?"); + } + int n = num.get(0); + CitationMarkerNumericBibEntryImpl x = + new CitationMarkerNumericBibEntryImpl("key", + (n == 0) ? Optional.empty() : Optional.of(n)); + return style.getNumCitationMarkerForBibliography(x).asString(); + } else { + List input = + num.stream() + .map(n -> + new CitationMarkerNumericEntryImpl("key" + String.valueOf(n), + n, + Optional.empty())) + .collect(Collectors.toList()); + return style.getNumCitationMarker2(input, minGroupingCount).asString(); + } + } + + /* + * Unlike getNumCitationMarker, getNumCitationMarker2 can handle pageInfo. + */ + static CitationMarkerNumericEntry numEntry(String key, int num, String pageInfoOrNull) { + Optional pageInfo = Optional.ofNullable(OOText.fromString(pageInfoOrNull)); + return new CitationMarkerNumericEntryImpl(key, num, pageInfo); + } + + static String runGetNumCitationMarker2b(OOBibStyle style, + int minGroupingCount, + CitationMarkerNumericEntry... s) { + List input = Stream.of(s).collect(Collectors.toList()); + OOText res = style.getNumCitationMarker2(input, minGroupingCount); + return res.asString(); + } + + /* + * end Helpers for testing style.getNumCitationMarker2 + */ + + + /* + * begin helper + */ + static CitationMarkerEntry makeCitationMarkerEntry(BibEntry entry, + BibDatabase database, + String uniqueLetterQ, + String pageInfoQ, + boolean isFirstAppearanceOfSource) { + if (!entry.getCitationKey().isPresent()) { + throw new RuntimeException("!entry.getCitationKey().isPresent()"); + } + String citationKey = entry.getCitationKey().get(); + Citation result = new Citation(citationKey); + result.setLookupResult(Optional.of(new CitationLookupResult(entry, database))); + result.setUniqueLetter(Optional.ofNullable(uniqueLetterQ)); + Optional pageInfo = Optional.ofNullable(OOText.fromString(pageInfoQ)); + result.setPageInfo(PageInfo.normalizePageInfo(pageInfo)); + result.setIsFirstAppearanceOfSource(isFirstAppearanceOfSource); + return result; + } + + /* + * Similar to old API. pageInfo is new, and unlimAuthors is + * replaced with isFirstAppearanceOfSource + */ + static String getCitationMarker2(OOBibStyle style, + List entries, + Map entryDBMap, + boolean inParenthesis, + String[] uniquefiers, + Boolean[] isFirstAppearanceOfSource, + String[] pageInfo) { + if (uniquefiers == null) { + uniquefiers = new String[entries.size()]; + Arrays.fill(uniquefiers, null); + } + if (pageInfo == null) { + pageInfo = new String[entries.size()]; + Arrays.fill(pageInfo, null); + } + if (isFirstAppearanceOfSource == null) { + isFirstAppearanceOfSource = new Boolean[entries.size()]; + Arrays.fill(isFirstAppearanceOfSource, false); + } + List citationMarkerEntries = new ArrayList<>(); + for (int i = 0; i < entries.size(); i++) { + BibEntry entry = entries.get(i); + CitationMarkerEntry e = makeCitationMarkerEntry(entry, + entryDBMap.get(entry), + uniquefiers[i], + pageInfo[i], + isFirstAppearanceOfSource[i]); + citationMarkerEntries.add(e); + } + return style.createCitationMarker(citationMarkerEntries, + inParenthesis, + NonUniqueCitationMarker.THROWS).asString(); + } + + /* + * end helper + */ + + + static void testGetNumCitationMarkerExtra(OOBibStyle style) throws IOException { + // Identical numeric entries are joined. + assertEquals("[1; 2]", runGetNumCitationMarker2b(style, 3, + numEntry("x1",1,null), + numEntry("x2",2,null), + numEntry("x1",2,null), + numEntry("x2",1,null))); + + // ... unless minGroupingCount <= 0 + assertEquals("[1; 1; 2; 2]", runGetNumCitationMarker2b(style, 0, + numEntry("x1",1,null), + numEntry("x2",2,null), + numEntry("x1",2,null), + numEntry("x2",1,null))); + + // ... or have different pageInfos + assertEquals("[1; p1a; 1; p1b; 2; p2; 3]", runGetNumCitationMarker2b(style, 1, + numEntry("x1", 1, "p1a"), + numEntry("x1", 1, "p1b"), + numEntry("x2", 2, "p2"), + numEntry("x2", 2, "p2"), + numEntry("x3", 3, null), + numEntry("x3", 3, null))); + + // Consecutive numbers can become a range ... + assertEquals("[1-3]", runGetNumCitationMarker2b(style, 1, + numEntry("x1", 1, null), + numEntry("x2", 2, null), + numEntry("x3", 3, null))); + + // ... unless minGroupingCount is too high + assertEquals("[1; 2; 3]", runGetNumCitationMarker2b(style, 4, + numEntry("x1", 1, null), + numEntry("x2", 2, null), + numEntry("x3", 3, null))); + + // ... or if minGroupingCount <= 0 + assertEquals("[1; 2; 3]", runGetNumCitationMarker2b(style, 0, + numEntry("x1", 1, null), + numEntry("x2", 2, null), + numEntry("x3", 3, null))); + + // ... a pageInfo needs to be emitted + assertEquals("[1; p1; 2-3]", runGetNumCitationMarker2b(style, 1, + numEntry("x1", 1, "p1"), + numEntry("x2", 2, null), + numEntry("x3", 3, null))); + + // null and "" pageInfos are taken as equal. + // Due to trimming, " " is the same as well. + assertEquals("[1]", runGetNumCitationMarker2b(style, 1, + numEntry("x1", 1, ""), + numEntry("x1", 1, null), + numEntry("x1", 1, " "))); + + // pageInfos are trimmed + assertEquals("[1; p1]", runGetNumCitationMarker2b(style, 1, + numEntry("x1", 1, "p1"), + numEntry("x1", 1, " p1"), + numEntry("x1", 1, "p1 "))); + + // The citation numbers come out sorted + assertEquals("[3-5; 7; 10-12]", runGetNumCitationMarker2b(style, 1, + numEntry("x12", 12, null), + numEntry("x7", 7, null), + numEntry("x3", 3, null), + numEntry("x4", 4, null), + numEntry("x11", 11, null), + numEntry("x10", 10, null), + numEntry("x5", 5, null))); + + // pageInfos are sorted together with the numbers + // (but they inhibit ranges where they are, even if they are identical, + // but not empty-or-null) + assertEquals("[3; p3; 4; p4; 5; p5; 7; p7; 10; px; 11; px; 12; px]", + runGetNumCitationMarker2b(style, 1, + numEntry("x12", 12, "px"), + numEntry("x7", 7, "p7"), + numEntry("x3", 3, "p3"), + numEntry("x4", 4, "p4"), + numEntry("x11", 11, "px"), + numEntry("x10", 10, "px"), + numEntry("x5", 5, "p5"))); + + // pageInfo sorting (for the same number) + assertEquals("[1; 1; a; 1; b]", + runGetNumCitationMarker2b(style, 1, + numEntry("x1", 1, ""), + numEntry("x1", 1, "b"), + numEntry("x1", 1, "a"))); + + // pageInfo sorting (for the same number) is not numeric. + assertEquals("[1; p100; 1; p20; 1; p9]", + runGetNumCitationMarker2b(style, 1, + numEntry("x1", 1, "p20"), + numEntry("x1", 1, "p9"), + numEntry("x1", 1, "p100"))); + + assertEquals("[1-3]", + runGetNumCitationMarker2b(style, 1, + numEntry("x1", 1, null), + numEntry("x2", 2, null), + numEntry("x3", 3, null))); + + assertEquals("[1; 2; 3]", + runGetNumCitationMarker2b(style, 5, + numEntry("x1", 1, null), + numEntry("x2", 2, null), + numEntry("x3", 3, null))); + + assertEquals("[1; 2; 3]", + runGetNumCitationMarker2b(style, -1, + numEntry("x1", 1, null), + numEntry("x2", 2, null), + numEntry("x3", 3, null))); + + assertEquals("[1; 3; 12]", + runGetNumCitationMarker2b(style, 1, + numEntry("x1", 1, null), + numEntry("x12", 12, null), + numEntry("x3", 3, null))); + + assertEquals("[3-5; 7; 10-12]", + runGetNumCitationMarker2b(style, 1, + numEntry("x12", 12, ""), + numEntry("x7", 7, ""), + numEntry("x3", 3, ""), + numEntry("x4", 4, ""), + numEntry("x11", 11, ""), + numEntry("x10", 10, ""), + numEntry("x5", 5, ""))); + } +} From d2a53c7061f59a623c1b86cb873e4db16210ed83 Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 11:39:40 +0200 Subject: [PATCH 016/103] add backend --- .../logic/openoffice/backend/Backend52.java | 465 ++++++++++++++++ .../logic/openoffice/backend/Codec52.java | 148 ++++++ .../logic/openoffice/backend/GetContext.java | 87 +++ .../NamedRangeManagerReferenceMark.java | 50 ++ .../backend/NamedRangeReferenceMark.java | 500 ++++++++++++++++++ .../model/openoffice/backend/NamedRange.java | 65 +++ .../openoffice/backend/NamedRangeManager.java | 31 ++ src/main/resources/l10n/JabRef_en.properties | 1 + 8 files changed, 1347 insertions(+) create mode 100644 src/main/java/org/jabref/logic/openoffice/backend/Backend52.java create mode 100644 src/main/java/org/jabref/logic/openoffice/backend/Codec52.java create mode 100644 src/main/java/org/jabref/logic/openoffice/backend/GetContext.java create mode 100644 src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java create mode 100644 src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java create mode 100644 src/main/java/org/jabref/model/openoffice/backend/NamedRange.java create mode 100644 src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java new file mode 100644 index 00000000000..d7c1b62086a --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java @@ -0,0 +1,465 @@ +package org.jabref.logic.openoffice.backend; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import org.jabref.model.openoffice.CitationEntry; +import org.jabref.model.openoffice.backend.NamedRange; +import org.jabref.model.openoffice.backend.NamedRangeManager; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.Citation; +import org.jabref.model.openoffice.style.CitationGroup; +import org.jabref.model.openoffice.style.CitationGroupId; +import org.jabref.model.openoffice.style.CitationGroups; +import org.jabref.model.openoffice.style.CitationType; +import org.jabref.model.openoffice.style.OODataModel; +import org.jabref.model.openoffice.style.PageInfo; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoUserDefinedProperty; +import org.jabref.model.openoffice.util.OOListUtil; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Backend52 { + private static final Logger LOGGER = LoggerFactory.getLogger(Backend52.class); + public final OODataModel dataModel; + private final NamedRangeManager citationStorageManager; + private final Map cgidToNamedRange; + + // uses: Codec52 + public Backend52() { + this.dataModel = OODataModel.JabRef52; + this.citationStorageManager = new NamedRangeManagerReferenceMark(); + this.cgidToNamedRange = new HashMap<>(); + } + + /** + * Get reference mark names from the document matching the pattern + * used for JabRef reference mark names. + * + * Note: the names returned are in arbitrary order. + * + */ + public List getJabRefReferenceMarkNames(XTextDocument doc) + throws + NoDocumentException { + List allNames = this.citationStorageManager.nrmGetUsedNames(doc); + return Codec52.filterIsJabRefReferenceMarkName(allNames); + } + + /** + * Names of custom properties belonging to us, but without a + * corresponding reference mark. These can be deleted. + * + * @param citationGroupNames These are the names that are used. + * + */ + private List findUnusedJabrefPropertyNames(XTextDocument doc, + List citationGroupNames) { + + // Collect unused jabrefPropertyNames + Set citationGroupNamesSet = citationGroupNames.stream().collect(Collectors.toSet()); + + List pageInfoThrash = new ArrayList<>(); + List jabrefPropertyNames = + UnoUserDefinedProperty.getListOfNames(doc) + .stream() + .filter(Codec52::isJabRefReferenceMarkName) + .collect(Collectors.toList()); + for (String pn : jabrefPropertyNames) { + if (!citationGroupNamesSet.contains(pn)) { + pageInfoThrash.add(pn); + } + } + return pageInfoThrash; + } + + /** + * @return Optional.empty if all is OK, message text otherwise. + */ + public Optional healthReport(XTextDocument doc) + throws + NoDocumentException { + List pageInfoThrash = + this.findUnusedJabrefPropertyNames(doc, this.getJabRefReferenceMarkNames(doc)); + if (pageInfoThrash.isEmpty()) { + return Optional.empty(); // "Backend52: found no unused pageInfo data"; + } + String msg = + "Backend52: found unused pageInfo data, with names listed below.\n" + + "In LibreOffice you may remove these in [File]/[Properties]/[Custom Properties]\n"; + msg += "" + String.join("\n", pageInfoThrash) + ""; + return Optional.of(msg); + } + + private static void setPageInfoInDataInitial(List citations, Optional pageInfo) { + // attribute to last citation (initially localOrder == storageOrder) + if (citations.size() > 0) { + citations.get(citations.size() - 1).setPageInfo(pageInfo); + } + } + + private static void setPageInfoInData(CitationGroup cg, Optional pageInfo) { + List citations = cg.getCitationsInLocalOrder(); + if (citations.size() > 0) { + citations.get(citations.size() - 1).setPageInfo(pageInfo); + } + } + + private static Optional getPageInfoFromData(CitationGroup cg) { + List citations = cg.getCitationsInLocalOrder(); + if (citations.size() > 0) { + return citations.get(citations.size() - 1).getPageInfo(); + } else { + return Optional.empty(); + } + } + + /** + * We have circular dependency here: backend uses + * class from ... + */ + public CitationGroup readCitationGroupFromDocumentOrThrow(XTextDocument doc, String refMarkName) + throws + WrappedTargetException, + NoDocumentException { + + Optional op = Codec52.parseMarkName(refMarkName); + if (op.isEmpty()) { + throw new IllegalArgumentException("readCitationGroupFromDocumentOrThrow:" + + " found unparsable referenceMarkName"); + } + Codec52.ParsedMarkName ov = op.get(); + CitationGroupId cgid = new CitationGroupId(refMarkName); + List citations = (ov.citationKeys.stream() + .map(Citation::new) + .collect(Collectors.toList())); + + Optional pageInfo = + (UnoUserDefinedProperty.getStringValue(doc, refMarkName) + .map(OOText::fromString)); + pageInfo = PageInfo.normalizePageInfo(pageInfo); + + setPageInfoInDataInitial(citations, pageInfo); + + Optional namedRange = citationStorageManager.nrmGetFromDocument(doc, refMarkName); + + if (namedRange.isEmpty()) { + throw new IllegalArgumentException("readCitationGroupFromDocumentOrThrow:" + + " referenceMarkName is not in the document"); + } + + CitationGroup cg = new CitationGroup(OODataModel.JabRef52, + cgid, + ov.citationType, + citations, + Optional.of(refMarkName)); + this.cgidToNamedRange.put(cgid, namedRange.get()); + return cg; + } + + /** + * Create a reference mark with the given name, at the + * end of position. + * + * On return {@code position} is collapsed, and is after the + * inserted space, or at the end of the reference mark. + * + * @param position Collapsed to its end. + * @param insertSpaceAfter We insert a space after the mark, that + * carries on format of characters from + * the original position. + */ + public CitationGroup createCitationGroup(XTextDocument doc, + List citationKeys, + List> pageInfos, + CitationType citationType, + XTextCursor position, + boolean insertSpaceAfter) + throws + CreationException, + NoDocumentException, + WrappedTargetException, + NotRemoveableException, + PropertyExistException, + PropertyVetoException, + IllegalTypeException { + + Objects.requireNonNull(pageInfos); + if (pageInfos.size() != citationKeys.size()) { + throw new RuntimeException("pageInfos.size != citationKeys.size"); + } + + // Get a new refMarkName + Set usedNames = new HashSet<>(this.citationStorageManager.nrmGetUsedNames(doc)); + String xkey = (citationKeys.stream().collect(Collectors.joining(","))); + String refMarkName = Codec52.getUniqueMarkName(usedNames, xkey, citationType); + + CitationGroupId cgid = new CitationGroupId(refMarkName); + + final int nCitations = citationKeys.size(); + final int last = nCitations - 1; + + // Build citations, add pageInfo to each citation + List citations = new ArrayList<>(nCitations); + for (int i = 0; i < nCitations; i++) { + Citation cit = new Citation(citationKeys.get(i)); + citations.add(cit); + + Optional pageInfo = PageInfo.normalizePageInfo(pageInfos.get(i)); + switch (dataModel) { + case JabRef52: + if (i == last) { + cit.setPageInfo(pageInfo); + } else { + if (pageInfo.isPresent()) { + LOGGER.warn("dataModel JabRef52" + + " only supports pageInfo for the last citation of a group"); + } + } + break; + case JabRef53: + cit.setPageInfo(pageInfo); + break; + } + } + + /* + * Apply to document + */ + boolean withoutBrackets = (citationType == CitationType.INVISIBLE_CIT); + NamedRange namedRange = + this.citationStorageManager.nrmCreate(doc, refMarkName, position, insertSpaceAfter, + withoutBrackets); + + switch (dataModel) { + case JabRef52: + Optional pageInfo = PageInfo.normalizePageInfo(pageInfos.get(last)); + + if (pageInfo.isPresent()) { + String pageInfoString = OOText.toString(pageInfo.get()); + UnoUserDefinedProperty.createStringProperty(doc, refMarkName, pageInfoString); + } else { + // do not inherit from trash + UnoUserDefinedProperty.removeIfExists(doc, refMarkName); + } + CitationGroup cg = new CitationGroup(OODataModel.JabRef52, + cgid, + citationType, citations, + Optional.of(refMarkName)); + this.cgidToNamedRange.put(cgid, namedRange); + return cg; + default: + throw new RuntimeException("Backend52 requires JabRef52 dataModel"); + } + } + + /** + * @return A list with a nullable pageInfo entry for each citation in + * joinableGroups. + * + * TODO: JabRef52 combinePageInfos is not reversible. Should warn + * user to check the result. Or ask what to do. + */ + public static List> + combinePageInfosCommon(OODataModel dataModel, List joinableGroup) { + switch (dataModel) { + case JabRef52: + // collect to cgPageInfos + List> cgPageInfos = OOListUtil.map(joinableGroup, + Backend52::getPageInfoFromData); + + // Try to do something of the cgPageInfos. + String cgPageInfo = (cgPageInfos.stream() + .filter(pi -> pi.isPresent()) + .map(pi -> OOText.toString(pi.get())) + .distinct() + .collect(Collectors.joining("; "))); + + int nCitations = (joinableGroup.stream() + .map(cg -> cg.numberOfCitations()) + .mapToInt(Integer::intValue).sum()); + if ("".equals(cgPageInfo)) { + cgPageInfo = null; + } + return OODataModel.fakePageInfos(cgPageInfo, nCitations); + + case JabRef53: + return (joinableGroup.stream() + .flatMap(cg -> (cg.citationsInStorageOrder.stream() + .map(Citation::getPageInfo))) + .collect(Collectors.toList())); + default: + throw new RuntimeException("unhandled dataModel here"); + } + } + + /** + * + */ + public List> combinePageInfos(List joinableGroup) { + return combinePageInfosCommon(this.dataModel, joinableGroup); + } + + private NamedRange getNamedRangeOrThrow(CitationGroup cg) { + NamedRange namedRange = this.cgidToNamedRange.get(cg.cgid); + if (namedRange == null) { + LOGGER.warn("getNamedRange: could not lookup namedRange"); + throw new RuntimeException("getNamedRange: could not lookup namedRange"); + } + return namedRange; + } + + public void removeCitationGroup(CitationGroup cg, XTextDocument doc) + throws + WrappedTargetException, + NoDocumentException, + NoSuchElementException, + NotRemoveableException, + IllegalTypeException, + PropertyExistException { + + NamedRange namedRange = getNamedRangeOrThrow(cg); + String refMarkName = namedRange.nrGetRangeName(); + namedRange.nrRemoveFromDocument(doc); + UnoUserDefinedProperty.removeIfExists(doc, refMarkName); + this.cgidToNamedRange.remove(cg.cgid); + } + + /** + * + * @return Optional.empty if the reference mark is missing. + * + */ + public Optional getMarkRange(CitationGroup cg, XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + + NamedRange namedRange = getNamedRangeOrThrow(cg); + return namedRange.nrGetMarkRange(doc); + } + + /** + * Cursor for the reference marks as is, not prepared for filling, + * but does not need cleanFillCursorForCitationGroup either. + */ + public Optional getRawCursorForCitationGroup(CitationGroup cg, XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + NamedRange namedRange = getNamedRangeOrThrow(cg); + return namedRange.nrGetRawCursor(doc); + } + + /** + * Must be followed by call to cleanFillCursorForCitationGroup + */ + public XTextCursor getFillCursorForCitationGroup(CitationGroup cg, XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException, + CreationException { + + NamedRange namedRange = getNamedRangeOrThrow(cg); + return namedRange.nrGetFillCursor(doc); + } + + /** To be called after getFillCursorForCitationGroup */ + public void cleanFillCursorForCitationGroup(CitationGroup cg, XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException, + CreationException { + NamedRange namedRange = getNamedRangeOrThrow(cg); + namedRange.nrCleanFillCursor(doc); + } + + public List getCitationEntries(XTextDocument doc, CitationGroups cgs) + throws + UnknownPropertyException, + WrappedTargetException, + NoDocumentException { + + switch (dataModel) { + case JabRef52: + // One context per CitationGroup: Backend52 (DataModel.JabRef52) + // For DataModel.JabRef53 (Backend53) we need one context per Citation + int n = cgs.numberOfCitationGroups(); + List citations = new ArrayList<>(n); + for (CitationGroup cg : cgs.getCitationGroupsUnordered()) { + String name = cg.cgid.citationGroupIdAsString(); + XTextCursor cursor = (this + .getRawCursorForCitationGroup(cg, doc) + .orElseThrow(RuntimeException::new)); + String context = GetContext.getCursorStringWithContext(cursor, 30, 30, true); + Optional pageInfo = (cg.numberOfCitations() > 0 + ? (getPageInfoFromData(cg) + .map(e -> OOText.toString(e))) + : Optional.empty()); + CitationEntry entry = new CitationEntry(name, context, pageInfo); + citations.add(entry); + } + return citations; + case JabRef53: + // xx + throw new RuntimeException("getCitationEntries for JabRef53 is not implemented yet"); + default: + throw new RuntimeException("getCitationEntries: unhandled dataModel "); + } + } + + /* + * Only applies to storage. Citation markers are not changed. + */ + public void applyCitationEntries(XTextDocument doc, List citationEntries) + throws + UnknownPropertyException, + NotRemoveableException, + PropertyExistException, + PropertyVetoException, + IllegalTypeException, + IllegalArgumentException, + NoDocumentException, + WrappedTargetException { + + switch (dataModel) { + case JabRef52: + for (CitationEntry entry : citationEntries) { + Optional pageInfo = entry.getPageInfo().map(OOText::fromString); + pageInfo = PageInfo.normalizePageInfo(pageInfo); + if (pageInfo.isPresent()) { + String name = entry.getRefMarkName(); + UnoUserDefinedProperty.createStringProperty(doc, name, pageInfo.get().asString()); + } + } + break; + case JabRef53: + // xx + throw new RuntimeException("applyCitationEntries for JabRef53 is not implemented yet"); + default: + throw new RuntimeException("applyCitationEntries: unhandled dataModel "); + } + } + +} + diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java new file mode 100644 index 00000000000..352df27cdeb --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java @@ -0,0 +1,148 @@ +package org.jabref.logic.openoffice.backend; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.jabref.model.openoffice.style.CitationType; +import org.jabref.model.openoffice.uno.NoDocumentException; + +/** + * How and what is encoded in a mark names. + * + * - pageInfo does not appear here. It is not encoded in the mark name. + * - Does not depend on the type of marks (reference mark of bookmark) used. + */ +class Codec52 { + private static final String BIB_CITATION = "JR_cite"; + private static final Pattern CITE_PATTERN = + // Pattern.compile(BIB_CITATION + "(\\d*)_(\\d*)_(.*)"); + // citationType is always "1" "2" or "3" + Pattern.compile(BIB_CITATION + "(\\d*)_([123])_(.*)"); + + /** + * This is what we get back from parsing a refMarkName. + * + */ + public static class ParsedMarkName { + /** "", "0", "1" ... */ + public final String i; + /** in-text-citation type */ + public final CitationType citationType; + /** Citation keys embedded in the reference mark. */ + public final List citationKeys; + + ParsedMarkName(String i, CitationType citationType, List citationKeys) { + Objects.requireNonNull(i); + Objects.requireNonNull(citationKeys); + this.i = i; + this.citationType = citationType; + this.citationKeys = citationKeys; + } + } + + /* + * Integer representation was written into the document in + * JabRef52, keep it for compatibility. + */ + public static CitationType CitationTypeFromInt(int i) { + switch (i) { + case 1: + return CitationType.AUTHORYEAR_PAR; + case 2: + return CitationType.AUTHORYEAR_INTEXT; + case 3: + return CitationType.INVISIBLE_CIT; + default: + throw new RuntimeException("Invalid CitationType code"); + } + } + + public static int CitationTypeToInt(CitationType i) { + switch (i) { + case AUTHORYEAR_PAR: + return 1; + case AUTHORYEAR_INTEXT: + return 2; + case INVISIBLE_CIT: + return 3; + default: + throw new RuntimeException("Invalid CitationType"); + } + } + + /** + * Produce a reference mark name for JabRef for the given citation + * key and citationType that does not yet appear among the reference + * marks of the document. + * + * @param bibtexKey The citation key. + * @param citationType Encodes the effect of withText and + * inParenthesis options. + * + * The first occurrence of bibtexKey gets no serial number, the + * second gets 0, the third 1 ... + * + * Or the first unused in this series, after removals. + */ + public static String getUniqueMarkName(Set usedNames, + String bibtexKey, + CitationType citationType) + throws + NoDocumentException { + + int i = 0; + int j = CitationTypeToInt(citationType); + String name = BIB_CITATION + '_' + j + '_' + bibtexKey; + while (usedNames.contains(name)) { + name = BIB_CITATION + i + '_' + j + '_' + bibtexKey; + i++; + } + return name; + } + + /** + * Parse a JabRef (reference) mark name. + * + * @return Optional.empty() on failure. + * + */ + public static Optional parseMarkName(String refMarkName) { + + Matcher citeMatcher = CITE_PATTERN.matcher(refMarkName); + if (!citeMatcher.find()) { + return Optional.empty(); + } + + List keys = Arrays.asList(citeMatcher.group(3).split(",")); + String i = citeMatcher.group(1); + int j = Integer.parseInt(citeMatcher.group(2)); + CitationType citationType = CitationTypeFromInt(j); + return (Optional.of(new Codec52.ParsedMarkName(i, citationType, keys))); + } + + /** + * @return true if name matches the pattern used for JabRef + * reference mark names. + */ + public static boolean isJabRefReferenceMarkName(String name) { + return (CITE_PATTERN.matcher(name).find()); + } + + /** + * Filter a list of reference mark names by `isJabRefReferenceMarkName` + * + * @param names The list to be filtered. + */ + public static List filterIsJabRefReferenceMarkName(List names) { + return (names + .stream() + .filter(Codec52::isJabRefReferenceMarkName) + .collect(Collectors.toList())); + } +} diff --git a/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java b/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java new file mode 100644 index 00000000000..468d630e756 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java @@ -0,0 +1,87 @@ +package org.jabref.logic.openoffice.backend; + +import org.jabref.model.openoffice.uno.NoDocumentException; + +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility methods for processing OO Writer documents. + */ +public class GetContext { + + private static final Logger LOGGER = LoggerFactory.getLogger(GetContext.class); + + private GetContext() { + // Just to hide the public constructor + } + + /** + * Get the text belonging to cursor with up to + * charBefore and charAfter characters of context. + * + * The actual context may be smaller than requested. + * + * @param cursor + * @param charBefore Number of characters requested. + * @param charAfter Number of characters requested. + * @param htmlMarkup If true, the text belonging to the + * reference mark is surrounded by bold html tag. + * + */ + public static String getCursorStringWithContext(XTextCursor cursor, + int charBefore, + int charAfter, + boolean htmlMarkup) + throws + WrappedTargetException, + NoDocumentException { + + String citPart = cursor.getString(); + + // extend cursor range left + int flex = 8; + for (int i = 0; i < charBefore; i++) { + try { + cursor.goLeft((short) 1, true); + // If we are close to charBefore and see a space, + // then cut here. Might avoid cutting a word in half. + if ((i >= (charBefore - flex)) + && Character.isWhitespace(cursor.getString().charAt(0))) { + break; + } + } catch (IndexOutOfBoundsException ex) { + LOGGER.warn("Problem going left", ex); + } + } + + int lengthWithBefore = cursor.getString().length(); + int addedBefore = lengthWithBefore - citPart.length(); + + cursor.collapseToStart(); + for (int i = 0; i < (charAfter + lengthWithBefore); i++) { + try { + cursor.goRight((short) 1, true); + if (i >= ((charAfter + lengthWithBefore) - flex)) { + String strNow = cursor.getString(); + if (Character.isWhitespace(strNow.charAt(strNow.length() - 1))) { + break; + } + } + } catch (IndexOutOfBoundsException ex) { + LOGGER.warn("Problem going right", ex); + } + } + + String result = cursor.getString(); + if (htmlMarkup) { + result = (result.substring(0, addedBefore) + + "" + citPart + "" + + result.substring(lengthWithBefore)); + } + return result.trim(); + } + +} diff --git a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java new file mode 100644 index 00000000000..157dd87cf0c --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java @@ -0,0 +1,50 @@ +package org.jabref.logic.openoffice.backend; + +import java.util.List; +import java.util.Optional; + +import org.jabref.model.openoffice.backend.NamedRange; +import org.jabref.model.openoffice.backend.NamedRangeManager; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoReferenceMark; + +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; + +public class NamedRangeManagerReferenceMark implements NamedRangeManager { + + @Override + public NamedRange nrmCreate(XTextDocument doc, + String refMarkName, + XTextCursor position, + boolean insertSpaceAfter, + boolean withoutBrackets) + throws + CreationException { + return NamedRangeReferenceMark.create(doc, + refMarkName, + position, + insertSpaceAfter, + withoutBrackets); + } + + @Override + public List nrmGetUsedNames(XTextDocument doc) + throws + NoDocumentException { + return UnoReferenceMark.getListOfNames(doc); + } + + @Override + public Optional nrmGetFromDocument(XTextDocument doc, String refMarkName) + throws + NoDocumentException, + WrappedTargetException { + return (NamedRangeReferenceMark + .getFromDocument(doc, refMarkName) + .map(x -> x)); + } +} + diff --git a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java new file mode 100644 index 00000000000..38ac716d9ac --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java @@ -0,0 +1,500 @@ +package org.jabref.logic.openoffice.backend; + +import java.util.Optional; + +import org.jabref.model.openoffice.backend.NamedRange; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoCursor; +import org.jabref.model.openoffice.uno.UnoReferenceMark; + +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XText; +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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +// was StorageBaseRefMark + +class NamedRangeReferenceMark implements NamedRange { + + private static final String ZERO_WIDTH_SPACE = "\u200b"; + + // for debugging we may want visible bracket + private static final boolean + REFERENCE_MARK_USE_INVISIBLE_BRACKETS = true; // !debug; + + public static final String + REFERENCE_MARK_LEFT_BRACKET = REFERENCE_MARK_USE_INVISIBLE_BRACKETS ? ZERO_WIDTH_SPACE : "<"; + + public static final String + REFERENCE_MARK_RIGHT_BRACKET = REFERENCE_MARK_USE_INVISIBLE_BRACKETS ? ZERO_WIDTH_SPACE : ">"; + + private static final Logger LOGGER = LoggerFactory.getLogger(NamedRangeReferenceMark.class); + + private String id; /* reference mark name */ + + private NamedRangeReferenceMark(String id) { + this.id = id; + } + + String getId() { + return id; + } + + /** + * Insert {@code n} spaces in a way that reference + * marks just before or just after the cursor are not affected. + * + * This is based on the observation, that starting two + * new paragraphs separates us from a reference mark on either side. + * + * The pattern used is: + * {@code safeInsertSpaces(n): para, para, left, space(n), right-delete, left(n), left-delete} + * + * @param position Where to insert (at position.getStart()) + * @param n Number of spaces to insert. + * + * @return a new cursor, covering the just-inserted spaces. + * + * This could be generalized to insert arbitrary text safely + * between two reference marks. But we do not need that now. + */ + private static XTextCursor safeInsertSpacesBetweenReferenceMarks(XTextRange position, int n) { + // Start with an empty cursor at position.getStart(); + XText text = position.getText(); + XTextCursor cursor = text.createTextCursorByRange(position.getStart()); + text.insertString(cursor, "\r\r", false); // para, para + cursor.goLeft((short) 1, false); // left + text.insertString(cursor, " ".repeat(n), false); // space(n) + cursor.goRight((short) 1, true); + cursor.setString(""); // right-delete + cursor.goLeft((short) n, false); // left(n) + cursor.goLeft((short) 1, true); + cursor.setString(""); // left-delete + cursor.goRight((short) n, true); // select the newly inserted spaces + return cursor; + } + + private static void createReprInDocument(XTextDocument doc, + String refMarkName, + XTextCursor position, + boolean insertSpaceAfter, + boolean withoutBrackets) + throws + CreationException { + + // The cursor we received: we push it before us. + position.collapseToEnd(); + + XTextCursor cursor = safeInsertSpacesBetweenReferenceMarks(position.getEnd(), 2); + + // cursors before the first and after the last space + XTextCursor cursorBefore = cursor.getText().createTextCursorByRange(cursor.getStart()); + XTextCursor cursorAfter = cursor.getText().createTextCursorByRange(cursor.getEnd()); + + cursor.collapseToStart(); + cursor.goRight((short) 1, false); + // now we are between two spaces + + final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; + final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; + final short leftLength = (short) left.length(); + final short rightLength = (short) right.length(); + String bracketedContent = (withoutBrackets + ? "" + : left + right); + + cursor.getText().insertString(cursor, bracketedContent, true); + + UnoReferenceMark.create(doc, refMarkName, cursor, true /* absorb */); + + cursorBefore.goRight((short) 1, true); + cursorBefore.setString(""); + if (!insertSpaceAfter) { + cursorAfter.goLeft((short) 1, true); + cursorAfter.setString(""); + } + } + + static NamedRangeReferenceMark create(XTextDocument doc, + String refMarkName, + XTextCursor position, + boolean insertSpaceAfter, + boolean withoutBrackets) + throws + CreationException { + + createReprInDocument(doc, + refMarkName, + position, + insertSpaceAfter, + withoutBrackets); + return new NamedRangeReferenceMark(refMarkName); + } + + /** + * @return Optional.empty if there is no corresponding range. + */ + static Optional getFromDocument(XTextDocument doc, + String refMarkName) + throws + NoDocumentException, + WrappedTargetException { + return (UnoReferenceMark.getAnchor(doc, refMarkName) + .map(e -> new NamedRangeReferenceMark(refMarkName))); + } + + /* + * Remove it from the document. + * + * See: removeCitationGroups + */ + @Override + public void nrRemoveFromDocument(XTextDocument doc) + throws + WrappedTargetException, + NoDocumentException, + NoSuchElementException { + UnoReferenceMark.remove(doc, this.nrGetRangeName()); + } + + @Override + public String nrGetRangeName() { + return id; + } + + /* + * ranges controlled by citation groups should not overlap with each other. + * + * @return Optional.empty if the reference mark is missing. + * + * See: UnoReferenceMark.getAnchor + */ + @Override + public Optional nrGetMarkRange(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + String name = this.nrGetRangeName(); + return UnoReferenceMark.getAnchor(doc, name); + } + + /** + * Cursor for the reference marks as is, not prepared for filling, + * but does not need nrCleanFillCursor either. + * + * @return Optional.empty() if reference mark is missing from the document, + * otherwise an XTextCursor for getMarkRange + * + * See: getRawCursorForCitationGroup + */ + @Override + public Optional nrGetRawCursor(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + + String name = this.nrGetRangeName(); + Optional full = Optional.empty(); + + Optional markAsTextContent = UnoReferenceMark.getAsTextContent(doc, name); + + if (markAsTextContent.isEmpty()) { + String msg = String.format("nrGetRawCursor: markAsTextContent(%s).isEmpty()", name); + LOGGER.warn(msg); + } + + full = UnoCursor.getTextCursorOfTextContentAnchor(markAsTextContent.get()); + if (full.isEmpty()) { + String msg = "nrGetRawCursor: full.isEmpty()"; + LOGGER.warn(msg); + return Optional.empty(); + } + return full; + } + + /** + * See: getFillCursorForCitationGroup + */ + @Override + public XTextCursor nrGetFillCursor(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException, + CreationException { + + String name = this.nrGetRangeName(); + + final boolean debugThisFun = false; + final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; + final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; + final short leftLength = (short) left.length(); + final short rightLength = (short) right.length(); + + XTextCursor full = null; + String fullText = null; + for (int i = 1; i <= 2; i++) { + Optional markAsTextContent = UnoReferenceMark.getAsTextContent(doc, name); + + if (markAsTextContent.isEmpty()) { + String msg = String.format("nrGetFillCursor:" + + " markAsTextContent(%s).isEmpty (attempt %d)", + name, + i); + throw new RuntimeException(msg); + } + + full = UnoCursor.getTextCursorOfTextContentAnchor(markAsTextContent.get()).orElse(null); + if (full == null) { + String msg = String.format("nrGetFillCursor: full == null (attempt %d)", i); + throw new RuntimeException(msg); + } + + fullText = full.getString(); + + if (debugThisFun) { + System.out.printf("nrGetFillCursor: fulltext = '%s'%n", fullText); + } + + if (fullText.length() >= 2) { + if (debugThisFun) { + System.out.printf("nrGetFillCursor: (attempt: %d) fulltext.length() >= 2," + + " break loop%n", i); + } + break; + } else { + // (fullText.length() < 2) + if (i == 2) { + String msg = String.format("nrGetFillCursor:" + + " (fullText.length() < 2) (attempt %d)", + i); + throw new RuntimeException(msg); + } + // too short, recreate + if (true || debugThisFun) { + System.out.println("nrGetFillCursor: too short, recreate"); + } + full.setString(""); + try { + UnoReferenceMark.remove(doc, name); + } catch (NoSuchElementException ex) { + String msg = String.format("nrGetFillCursor got NoSuchElementException" + + " for '%s'", + name); + LOGGER.warn(msg); + } + createReprInDocument(doc, + name, + full, + false, /* insertSpaceAfter */ + false /* withoutBrackets */); + } + } + + if (full == null) { + throw new RuntimeException("nrGetFillCursorFor: full == null (after loop)"); + } + if (fullText == null) { + throw new RuntimeException("nrGetFillCursor: fullText == null (after loop)"); + } + + fullText = full.getString(); + if (fullText.length() < 2) { + throw new RuntimeException("nrGetFillCursor: fullText.length() < 2 (after loop)'%n"); + } + XTextCursor beta = full.getText().createTextCursorByRange(full); + beta.collapseToStart(); + beta.goRight((short) 1, false); + beta.goRight((short) (fullText.length() - 2), true); + if (debugThisFun) { + System.out.printf("nrGetFillCursor: beta(1) covers '%s'%n", beta.getString()); + } + if (fullText.startsWith(left) && fullText.endsWith(right)) { + beta.setString(""); + } else { + if (debugThisFun) { + String msg = String.format("nrGetFillCursor: recreating brackets for '%s'", fullText); + // LOGGER.warn(msg); + System.out.println(msg); + } + + // we have at least two characters inside + XTextCursor alpha = full.getText().createTextCursorByRange(full); + alpha.collapseToStart(); + + XTextCursor omega = full.getText().createTextCursorByRange(full); + omega.collapseToEnd(); + + // beta now covers everything except first and last character + // Replace its content with brackets + String paddingx = "x"; + String paddingy = "y"; + String paddingz = "z"; + beta.setString(paddingx + left + paddingy + right + paddingz); + if (debugThisFun) { + System.out.printf("nrGetFillCursor: beta(2) covers '%s'%n", beta.getString()); + } + // move beta to before the right bracket + beta.collapseToEnd(); + beta.goLeft((short) (rightLength + 1), false); + // remove middle padding + beta.goLeft((short) 1, true); + if (debugThisFun) { + System.out.printf("nrGetFillCursor: beta(3) covers '%s'%n", beta.getString()); + } + // only drop paddingy later: beta.setString(""); + + // drop the initial character and paddingx + alpha.collapseToStart(); + alpha.goRight((short) (1 + 1), true); + if (debugThisFun) { + System.out.printf("nrGetFillCursor: alpha(4) covers '%s'%n", alpha.getString()); + } + alpha.setString(""); + // drop the last character and paddingz + omega.collapseToEnd(); + omega.goLeft((short) (1 + 1), true); + if (debugThisFun) { + System.out.printf("nrGetFillCursor: omega(5) covers '%s'%n", omega.getString()); + } + omega.setString(""); + + // drop paddingy now + if (debugThisFun) { + System.out.printf("nrGetFillCursor: beta(6) covers '%s'%n", beta.getString()); + } + beta.setString(""); + // should be OK now. + if (debugThisFun) { + alpha.goRight(leftLength, true); + System.out.printf("nrGetFillCursor: alpha(7) covers '%s', should be '%s'%n", + alpha.getString(), left); + omega.goLeft(rightLength, true); + System.out.printf("nrGetFillCursor: omega(8) covers '%s', should be '%s'%n", + omega.getString(), right); + } + } + + // NamedRangeReferenceMark.checkFillCursor(beta); + return beta; + } + + /* + * Throw RuntimeException if the brackets are not there. + */ + public static void checkFillCursor(XTextCursor cursor) { + final String left = REFERENCE_MARK_LEFT_BRACKET; + final String right = REFERENCE_MARK_RIGHT_BRACKET; + final short leftLength = (short) left.length(); + final short rightLength = (short) right.length(); + + XTextCursor alpha = cursor.getText().createTextCursorByRange(cursor); + alpha.collapseToStart(); + + XTextCursor omega = cursor.getText().createTextCursorByRange(cursor); + omega.collapseToEnd(); + + if (leftLength > 0) { + alpha.goLeft(leftLength, true); + if (!left.equals(alpha.getString())) { + String msg = String.format("checkFillCursor:" + + " ('%s') is not prefixed with" + + " REFERENCE_MARK_LEFT_BRACKET, has '%s'", + cursor.getString(), alpha.getString()); + throw new RuntimeException(msg); + } + } + + if (rightLength > 0) { + omega.goRight(rightLength, true); + if (!right.equals(omega.getString())) { + String msg = String.format("checkFillCursor:" + + " ('%s') is not followed by" + + " REFERENCE_MARK_RIGHT_BRACKET, has '%s'", + cursor.getString(), omega.getString()); + throw new RuntimeException(msg); + } + } + } + + /** + * Remove brackets, but if the result would become empty, leave + * them; if the result would be a single characer, leave the left bracket. + * + * See: cleanFillCursorForCitationGroup + */ + @Override + public void nrCleanFillCursor(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException, + CreationException { + + // alwaysRemoveBrackets : full compatibility with JabRef 5.2: + // brackets are temporary, only exist between nrGetFillCursor + // and nrCleanFillCursor. + final boolean alwaysRemoveBrackets = false; + + // removeBracketsFromEmpty is intended to force removal if we + // are working on an "Empty citation" (INVISIBLE_CIT). + final boolean removeBracketsFromEmpty = false; + + final String left = REFERENCE_MARK_LEFT_BRACKET; + final String right = REFERENCE_MARK_RIGHT_BRACKET; + final short leftLength = (short) left.length(); + final short rightLength = (short) right.length(); + + String name = this.nrGetRangeName(); + + XTextCursor full = this.nrGetRawCursor(doc).orElseThrow(RuntimeException::new); + final String fullText = full.getString(); + final int fullTextLength = fullText.length(); + + if (!fullText.startsWith(left)) { + String msg = String.format("nrCleanFillCursor:" + + " (%s) does not start with REFERENCE_MARK_LEFT_BRACKET", + name); + throw new RuntimeException(msg); + } + + if (!fullText.endsWith(right)) { + String msg = String.format("nrCleanFillCursor:" + + " (%s) does not end with REFERENCE_MARK_RIGHT_BRACKET", + name); + throw new RuntimeException(msg); + } + + final int contentLength = (fullTextLength - (leftLength + rightLength)); + if (contentLength < 0) { + String msg = String.format("nrCleanFillCursor: length(%s) < 0", name); + throw new RuntimeException(msg); + } + + boolean removeRight = ((contentLength >= 1) + || ((contentLength == 0) && removeBracketsFromEmpty) + || alwaysRemoveBrackets); + + boolean removeLeft = ((contentLength >= 2) + || ((contentLength == 0) && removeBracketsFromEmpty) + || alwaysRemoveBrackets); + + if (removeRight) { + XTextCursor omega = full.getText().createTextCursorByRange(full); + omega.collapseToEnd(); + omega.goLeft(rightLength, true); + omega.setString(""); + } + + if (removeLeft) { + XTextCursor alpha = full.getText().createTextCursorByRange(full); + alpha.collapseToStart(); + alpha.goRight(leftLength, true); + alpha.setString(""); + } + } +} diff --git a/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java new file mode 100644 index 00000000000..e5c54773b07 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java @@ -0,0 +1,65 @@ +package org.jabref.model.openoffice.backend; + +import java.util.Optional; + +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; + +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; + +public interface NamedRange { + + public String nrGetRangeName(); + + /** + * @return Optional.empty if the mark is missing from the document. + */ + public Optional nrGetMarkRange(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException; + + /** + * Cursor for the reference marks as is, not prepared for filling, + * but does not need nrCleanFillCursor either. + */ + public Optional nrGetRawCursor(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException; + + /** + * Get a cursor for filling in text. + * + * Must be followed by nrCleanFillCursor() + */ + public XTextCursor nrGetFillCursor(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException, + CreationException; + + /** + * Remove brackets, but if the result would become empty, leave + * them; if the result would be a single characer, leave the left bracket. + * + */ + public void nrCleanFillCursor(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException, + CreationException; + + /** + * Note: create is in NamedRangeManager + */ + public void nrRemoveFromDocument(XTextDocument doc) + throws + WrappedTargetException, + NoDocumentException, + NoSuchElementException; +} diff --git a/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java b/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java new file mode 100644 index 00000000000..f53fcc72527 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java @@ -0,0 +1,31 @@ +package org.jabref.model.openoffice.backend; + +import java.util.List; +import java.util.Optional; + +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; + +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; + +public interface NamedRangeManager { + + public NamedRange nrmCreate(XTextDocument doc, + String markName, + XTextCursor position, + boolean insertSpaceAfter, + boolean withoutBrackets) + throws + CreationException; + + public List nrmGetUsedNames(XTextDocument doc) + throws + NoDocumentException; + + public Optional nrmGetFromDocument(XTextDocument doc, String markName) + throws + NoDocumentException, + WrappedTargetException; +} diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 0d5281b27a2..c2d0ea46ee7 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2295,6 +2295,7 @@ Custom\ DOI\ URI=Custom DOI URI Customization=Customization Use\ custom\ DOI\ base\ URI\ for\ article\ access=Use custom DOI base URI for article access +Cited\ on\ pages=Cited on pages Unable\ to\ find\ valid\ certification\ path\ to\ requested\ target(%0),\ download\ anyway?=Unable to find valid certification path to requested target(%0), download anyway? Download\ operation\ canceled.=Download operation canceled. From 0fed61823160b35be7d7b0e9be2e8d80863c584e Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 11:52:31 +0200 Subject: [PATCH 017/103] add frontend --- .../logic/openoffice/frontend/OOFrontend.java | 615 ++++++++++++++++++ .../frontend/RangeForOverlapCheck.java | 49 ++ .../frontend/UpdateBibliography.java | 153 +++++ .../frontend/UpdateCitationMarkers.java | 174 +++++ src/main/resources/l10n/JabRef_en.properties | 4 + 5 files changed, 995 insertions(+) create mode 100644 src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java create mode 100644 src/main/java/org/jabref/logic/openoffice/frontend/RangeForOverlapCheck.java create mode 100644 src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java create mode 100644 src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java new file mode 100644 index 00000000000..fd0523a4bf8 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java @@ -0,0 +1,615 @@ +package org.jabref.logic.openoffice.frontend; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.jabref.logic.JabRefException; +import org.jabref.logic.l10n.Localization; +import org.jabref.logic.openoffice.backend.Backend52; +import org.jabref.model.openoffice.CitationEntry; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.rangesort.FunctionalTextViewCursor; +import org.jabref.model.openoffice.rangesort.RangeOverlap; +import org.jabref.model.openoffice.rangesort.RangeOverlapBetween; +import org.jabref.model.openoffice.rangesort.RangeOverlapWithin; +import org.jabref.model.openoffice.rangesort.RangeSet; +import org.jabref.model.openoffice.rangesort.RangeSort; +import org.jabref.model.openoffice.rangesort.RangeSortEntry; +import org.jabref.model.openoffice.rangesort.RangeSortVisual; +import org.jabref.model.openoffice.rangesort.RangeSortable; +import org.jabref.model.openoffice.style.CitationGroup; +import org.jabref.model.openoffice.style.CitationGroupId; +import org.jabref.model.openoffice.style.CitationGroups; +import org.jabref.model.openoffice.style.CitationType; +import org.jabref.model.openoffice.style.OODataModel; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoCursor; +import org.jabref.model.openoffice.uno.UnoTextRange; +import org.jabref.model.openoffice.util.OOListUtil; +import org.jabref.model.openoffice.util.OOVoidResult; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OOFrontend { + private static final Logger LOGGER = LoggerFactory.getLogger(OOFrontend.class); + public final Backend52 backend; + public final CitationGroups citationGroups; + + public OOFrontend(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + + // TODO: dataModel should come from looking at the + // document and preferences. + // + this.backend = new Backend52(); + + // Get the citationGroupNames + List citationGroupNames = this.backend.getJabRefReferenceMarkNames(doc); + + Map citationGroups = + readCitationGroupsFromDocument(this.backend, doc, citationGroupNames); + this.citationGroups = new CitationGroups(citationGroups); + } + + public OODataModel getDataModel() { + return backend.dataModel; + } + + public Optional healthReport(XTextDocument doc) + throws + NoDocumentException { + return backend.healthReport(doc); + } + + private static Map + readCitationGroupsFromDocument(Backend52 backend, + XTextDocument doc, + List citationGroupNames) + throws + WrappedTargetException, + NoDocumentException { + + Map citationGroups = new HashMap<>(); + for (int i = 0; i < citationGroupNames.size(); i++) { + final String name = citationGroupNames.get(i); + CitationGroup cg = backend.readCitationGroupFromDocumentOrThrow(doc, name); + citationGroups.put(cg.cgid, cg); + } + return citationGroups; + } + + /** + * Creates a list of {@code RangeSortable} values for + * our {@code CitationGroup} values. Originally designed to be + * passed to {@code visualSort}. + * + * The elements of the returned list are actually of type + * {@code RangeSortEntry}. + * + * The result is sorted within {@code XTextRange.getText()} + * partitions of the citation groups according to their {@code XTextRange} + * (before mapping to footnote marks). + * + * In the result, RangeSortable.getIndexInPosition() contains + * unique indexes within the original partition (not after + * mapFootnotesToFootnoteMarks). + * + * @param mapFootnotesToFootnoteMarks If true, replace ranges in + * footnotes with the range of the corresponding footnote + * mark. This is used for numbering the citations. + * + */ + private List> + createVisualSortInput(XTextDocument doc, boolean mapFootnotesToFootnoteMarks) + throws + NoDocumentException, + WrappedTargetException { + + List> sortables = new ArrayList<>(); + for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { + XTextRange range = (this + .getMarkRange(doc, cg) + .orElseThrow(RuntimeException::new)); + sortables.add(new RangeSortEntry<>(range, 0, cg)); + } + + /* + * At this point we are almost ready to return sortables. + * + * But we may want to number citations in a footnote + * as if it appeared where the footnote mark is. + * + * The following code replaces ranges within footnotes with + * the range for the corresponding footnote mark. + * + * This brings further ambiguity if we have multiple + * citation groups within the same footnote: for the comparison + * they become indistinguishable. Numbering between them is + * not controlled. Also combineCiteMarkers will see them in + * the wrong order (if we use this comparison), and will not + * be able to merge. To avoid these, we sort textually within + * each .getText() partition and add indexInPosition + * accordingly. + * + */ + + // Sort within partitions + RangeSort.RangePartitions> partitions = + RangeSort.partitionAndSortRanges(sortables); + + // build final list + List> result = new ArrayList<>(); + for (List> partition : partitions.getPartitions()) { + + int indexInPartition = 0; + for (int i = 0; i < partition.size(); i++) { + RangeSortEntry sortable = partition.get(i); + XTextRange aRange = sortable.getRange(); + sortable.setIndexInPosition(indexInPartition++); + if (mapFootnotesToFootnoteMarks) { + Optional footnoteMarkRange = + UnoTextRange.getFootnoteMarkRange(sortable.getRange()); + // Adjust range if we are inside a footnote: + if (footnoteMarkRange.isPresent()) { + sortable.setRange(footnoteMarkRange.get()); + } + } + result.add(sortable); + } + } + return result.stream().map(e -> e).collect(Collectors.toList()); + } + + /** + * @param mapFootnotesToFootnoteMarks If true, sort reference + * marks in footnotes as if they appeared at the + * corresponding footnote mark. + * + * @return citation groups sorted by their visual positions. + * + * Limitation: for two column layout visual (top-down, + * left-right) order does not match the expected (textual) + * order. + * + */ + private List + getVisuallySortedCitationGroups(XTextDocument doc, + boolean mapFootnotesToFootnoteMarks, + FunctionalTextViewCursor fcursor) + throws + WrappedTargetException, + NoDocumentException, + JabRefException { + + List> sortables = + createVisualSortInput(doc, mapFootnotesToFootnoteMarks); + + List> sorted = + RangeSortVisual.visualSort(sortables, + doc, + fcursor); + + List result = + (sorted.stream().map(e -> e.getContent()).collect(Collectors.toList())); + + return result; + } + + /** + * Return citation groups in visual order within (but not across) + * XText partitions. + * + * This is (1) sufficient for combineCiteMarkers which looks for + * consecutive XTextRanges within each XText, (2) not confused by + * multicolumn layout or multipage display. + */ + public List + getCitationGroupsSortedWithinPartitions(XTextDocument doc, boolean mapFootnotesToFootnoteMarks) + throws + NoDocumentException, + WrappedTargetException { + // This is like getVisuallySortedCitationGroups, + // but we skip the visualSort part. + List> sortables = + createVisualSortInput(doc, mapFootnotesToFootnoteMarks); + + return (sortables.stream().map(e -> e.getContent()).collect(Collectors.toList())); + } + + /** + * Create a citation group for the given citation keys, at the + * end of position. + * + * On return {@code position} is collapsed, and is after the + * inserted space, or at the end of the reference mark. + * + * @param citationKeys In storage order + * @param pageInfos In storage order + * @param citationType + * @param position Collapsed to its end. + * @param insertSpaceAfter If true, we insert a space after the mark, that + * carries on format of characters from + * the original position. + */ + public CitationGroup createCitationGroup(XTextDocument doc, + List citationKeys, + List> pageInfos, + CitationType citationType, + XTextCursor position, + boolean insertSpaceAfter) + throws + CreationException, + NoDocumentException, + WrappedTargetException, + NotRemoveableException, + PropertyExistException, + PropertyVetoException, + IllegalTypeException { + + Objects.requireNonNull(pageInfos); + if (pageInfos.size() != citationKeys.size()) { + throw new RuntimeException("pageInfos.size != citationKeys.size"); + } + CitationGroup cg = backend.createCitationGroup(doc, + citationKeys, + pageInfos, + citationType, + position, + insertSpaceAfter); + + this.citationGroups.afterCreateCitationGroup(cg); + return cg; + } + + /** + * Remove {@code cg} both from the document and notify {@code citationGroups} + */ + public void removeCitationGroup(CitationGroup cg, XTextDocument doc) + throws + WrappedTargetException, + NoDocumentException, + NoSuchElementException, + NotRemoveableException, + PropertyExistException, + IllegalTypeException { + + backend.removeCitationGroup(cg, doc); + this.citationGroups.afterRemoveCitationGroup(cg); + } + + public void removeCitationGroups(List cgs, XTextDocument doc) + throws + WrappedTargetException, + NoDocumentException, + NoSuchElementException, + NotRemoveableException, + PropertyExistException, + IllegalTypeException { + + for (CitationGroup cg : cgs) { + removeCitationGroup(cg, doc); + } + } + + /** + * ranges controlled by citation groups should not overlap with each other. + * + * @return Optional.empty() if the reference mark is missing. + * + */ + public Optional getMarkRange(XTextDocument doc, CitationGroup cg) + throws + NoDocumentException, + WrappedTargetException { + return backend.getMarkRange(cg, doc); + } + + public XTextCursor getFillCursorForCitationGroup(XTextDocument doc, CitationGroup cg) + throws + NoDocumentException, + WrappedTargetException, + CreationException { + return backend.getFillCursorForCitationGroup(cg, doc); + } + + /** + * Remove brackets added by getFillCursorForCitationGroup. + */ + public void cleanFillCursorForCitationGroup(XTextDocument doc, CitationGroup cg) + throws + NoDocumentException, + WrappedTargetException, + CreationException { + + backend.cleanFillCursorForCitationGroup(cg, doc); + } + + /** + * @return A RangeForOverlapCheck for each citation group. + * + * result.size() == nRefMarks + */ + public List> citationRanges(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + + List> result = + new ArrayList<>(citationGroups.numberOfCitationGroups()); + + for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { + XTextRange range = this.getMarkRange(doc, cg).orElseThrow(RuntimeException::new); + String description = cg.cgid.citationGroupIdAsString(); // cg.cgRangeStorage.nrGetRangeName(); + result.add(new RangeForOverlapCheck<>(range, + cg.cgid, + RangeForOverlapCheck.REFERENCE_MARK_KIND, + description)); + } + return result; + } + + public List> bibliographyRanges(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + + List> result = new ArrayList<>(); + + Optional range = UpdateBibliography.getBibliographyRange(doc); + if (range.isPresent()) { + String description = "bibliography"; + result.add(new RangeForOverlapCheck<>(range.get(), + new CitationGroupId("bibliography"), + RangeForOverlapCheck.BIBLIOGRAPHY_MARK_KIND, + description)); + } + return result; + } + + public List> viewCursorRanges(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + + List> result = new ArrayList<>(); + + Optional range = UnoCursor.getViewCursor(doc).map(e -> e); + if (range.isPresent()) { + String description = "cursor"; + result.add(new RangeForOverlapCheck<>(range.get(), + new CitationGroupId("cursor"), + RangeForOverlapCheck.CURSOR_MARK_KIND, + description)); + } + return result; + } + + /** + * @return A range for each footnote mark where the footnote + * contains at least one citation group. + * + * Purpose: We do not want markers of footnotes containing + * reference marks to overlap with reference + * marks. Overwriting these footnote marks might kill our + * reference marks in the footnote. + * + * Note: Here we directly communicate to the document, not + * through the backend. This is because mapping ranges to + * footnote marks does not depend on how do we mark or + * structure those ranges. + */ + public List> + footnoteMarkRanges(XTextDocument doc, + List> citationRanges) + throws + NoDocumentException, + WrappedTargetException { + + // Avoid inserting the same mark twice. + // Could use RangeSet if we had that. + RangeSet seen = new RangeSet(); + + List> result = new ArrayList<>(); + + for (RangeForOverlapCheck citationRange : citationRanges) { + + Optional footnoteMarkRange = + UnoTextRange.getFootnoteMarkRange(citationRange.range); + + if (footnoteMarkRange.isEmpty()) { + // not in footnote + continue; + } + + boolean seenContains = seen.contains(footnoteMarkRange.get()); + if (!seenContains) { + seen.add(footnoteMarkRange.get()); + result.add(new RangeForOverlapCheck<>(footnoteMarkRange.get(), + citationRange.idWithinKind, + RangeForOverlapCheck.FOOTNOTE_MARK_KIND, + "FootnoteMark for " + citationRange.format())); + } + } + return result; + } + + static String + rangeOverlapsToMessage(List>> overlaps) { + + if (overlaps.size() == 0) { + return "(*no overlaps*)"; + } + + StringBuilder msg = new StringBuilder(); + for (RangeOverlap> overlap : overlaps) { + String listOfRanges = (overlap.valuesForOverlappingRanges.stream() + .map(v -> String.format("'%s'", v.format())) + .collect(Collectors.joining(", "))); + msg.append( + switch (overlap.kind) { + case EQUAL_RANGE -> Localization.lang("Found identical ranges"); + case OVERLAP -> Localization.lang("Found overlapping ranges"); + case TOUCH -> Localization.lang("Found touching ranges"); + }); + msg.append(": "); + msg.append(listOfRanges); + msg.append("\n"); + } + return msg.toString(); + } + + /** + * Check for any overlap between userRanges and protected ranges. + * + * Assume userRanges is small (usually 1 elements for checking the cursor) + * Returns on first problem found. + */ + public OOVoidResult + checkRangeOverlapsWithCursor(XTextDocument doc, + List> userRanges, + boolean requireSeparation) + throws + NoDocumentException, + WrappedTargetException { + + List> citationRanges = citationRanges(doc); + List> ranges = new ArrayList<>(); + + // ranges.addAll(userRanges); + ranges.addAll(bibliographyRanges(doc)); + ranges.addAll(citationRanges); + ranges.addAll(footnoteMarkRanges(doc, citationRanges)); + + List>> overlaps = + RangeOverlapBetween.findFirst( + doc, + userRanges, + ranges, + requireSeparation); + + if (overlaps.size() == 0) { + return OOVoidResult.ok(); + } + return OOVoidResult.error(new JabRefException("Found overlapping or touching ranges", + rangeOverlapsToMessage(overlaps))); + } + + /** + * @param requireSeparation Report range pairs that only share a boundary. + * @param reportAtMost Limit number of overlaps reported (0 for no limit) + * + */ + public OOVoidResult + checkRangeOverlaps(XTextDocument doc, + List> userRanges, + boolean requireSeparation, + int reportAtMost) + throws + NoDocumentException, + WrappedTargetException { + + List> citationRanges = citationRanges(doc); + List> ranges = new ArrayList<>(); + ranges.addAll(userRanges); + ranges.addAll(bibliographyRanges(doc)); + ranges.addAll(citationRanges); + ranges.addAll(footnoteMarkRanges(doc, citationRanges)); + + List>> overlaps = + RangeOverlapWithin.findOverlappingRanges(doc, ranges, requireSeparation, reportAtMost); + + if (overlaps.size() == 0) { + return OOVoidResult.ok(); + } + return OOVoidResult.error(new JabRefException("Found overlapping or touching ranges", + rangeOverlapsToMessage(overlaps))); + } + + /** + * GUI: Get a list of CitationEntry objects corresponding to citations + * in the document. + * + * Called from: ManageCitationsDialogViewModel constructor. + * + * @return A list with entries corresponding to citations in the + * text, in arbitrary order (same order as from + * getJabRefReferenceMarkNames). + * + * Note: visual or alphabetic order could be more + * manageable for the user. We could provide these + * here, but switching between them needs change on + * GUI (adding a toggle or selector). + * + * Note: CitationEntry implements Comparable, where + * compareTo() and equals() are based on refMarkName. + * The order used in the "Manage citations" dialog + * does not seem to use that. + * + * The 1st is labeled "Citation" (show citation in bold, + * and some context around it). + * + * The columns can be sorted by clicking on the column title. + * For the "Citation" column, the sorting is based on the content, + * (the context before the citation), not on the citation itself. + * + * In the "Extra information ..." column some visual indication + * of the editable part could be helpful. + * + * Wish: selecting an entry (or a button in the line) in + * the GUI could move the cursor in the document to + * the entry. + */ + public List getCitationEntries(XTextDocument doc) + throws + UnknownPropertyException, + WrappedTargetException, + NoDocumentException { + return this.backend.getCitationEntries(doc, citationGroups); + } + + public void applyCitationEntries(XTextDocument doc, List citationEntries) + throws + UnknownPropertyException, + NotRemoveableException, + PropertyExistException, + PropertyVetoException, + IllegalTypeException, + IllegalArgumentException, + NoDocumentException, + WrappedTargetException { + this.backend.applyCitationEntries(doc, citationEntries); + } + + public void imposeGlobalOrder(XTextDocument doc, FunctionalTextViewCursor fcursor) + throws + WrappedTargetException, + NoDocumentException, + JabRefException { + + boolean mapFootnotesToFootnoteMarks = true; + List sortedCitationGroups = + getVisuallySortedCitationGroups(doc, mapFootnotesToFootnoteMarks, fcursor); + List sortedCitationGroupIds = + OOListUtil.map(sortedCitationGroups, cg -> cg.cgid); + citationGroups.setGlobalOrder(sortedCitationGroupIds); + } +} diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/RangeForOverlapCheck.java b/src/main/java/org/jabref/logic/openoffice/frontend/RangeForOverlapCheck.java new file mode 100644 index 00000000000..6cbf560ec62 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/frontend/RangeForOverlapCheck.java @@ -0,0 +1,49 @@ +package org.jabref.logic.openoffice.frontend; + +import org.jabref.model.openoffice.rangesort.RangeHolder; + +import com.sun.star.text.XTextRange; + +/** + * Describe a protected range for overlap checking and reporting. + * + * To check that our protected ranges do not overlap, we collect + * these ranges. To check for overlaps between these, we need the + * {@code range} itself. To report the results of overlap + * checking, we need a {@code description} that can be understood + * by the user. + * + * To be able to refer back to more extended data, we might need to + * identify its {@code kind}, and its index in the corresponding + * tables or other identifier within its kind ({@code idWithinKind}) + * + */ +public class RangeForOverlapCheck implements RangeHolder { + + public final static int REFERENCE_MARK_KIND = 0; + public final static int FOOTNOTE_MARK_KIND = 1; + public final static int CURSOR_MARK_KIND = 2; + public final static int BIBLIOGRAPHY_MARK_KIND = 3; + + public final XTextRange range; + + public final int kind; + public final T idWithinKind; + private final String description; + + public RangeForOverlapCheck(XTextRange range, T idWithinKind, int kind, String description) { + this.range = range; + this.kind = kind; + this.idWithinKind = idWithinKind; + this.description = description; + } + + public String format() { + return description; + } + + @Override + public XTextRange getRange() { + return range; + } +} diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java new file mode 100644 index 00000000000..ef1a4c42dc5 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java @@ -0,0 +1,153 @@ +package org.jabref.logic.openoffice.frontend; + +import java.util.Optional; + +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.logic.openoffice.style.OOFormatBibliography; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.ootext.OOTextIntoOO; +import org.jabref.model.openoffice.style.CitedKeys; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoBookmark; +import org.jabref.model.openoffice.uno.UnoTextSection; + +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; + +/* + * Update document: citation marks and bibliography + */ +public class UpdateBibliography { + + private static final String BIB_SECTION_NAME = "JR_bib"; + private static final String BIB_SECTION_END_NAME = "JR_bib_end"; + + public static Optional getBibliographyRange(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + Optional sectionRange = UnoTextSection.getAnchor(doc, BIB_SECTION_NAME); + return sectionRange; + } + + /** + * Rebuilds the bibliography. + */ + public static void rebuildBibTextSection(XTextDocument doc, + OOFrontend fr, + CitedKeys bibliography, + OOBibStyle style, + boolean alwaysAddCitedOnPages) + throws + NoSuchElementException, + WrappedTargetException, + IllegalArgumentException, + CreationException, + PropertyVetoException, + UnknownPropertyException, + NoDocumentException { + + clearBibTextSectionContent2(doc); + + populateBibTextSection(doc, + fr, + bibliography, + style, + alwaysAddCitedOnPages); + } + + /** + * Insert a paragraph break and create a text section for the bibliography. + * + * Only called from `clearBibTextSectionContent2` + */ + private static void createBibTextSection2(XTextDocument doc) + throws + CreationException, + IllegalArgumentException { + + // Always creating at the end of the document. + // Alternatively, we could receive a cursor. + XTextCursor textCursor = doc.getText().createTextCursor(); + textCursor.gotoEnd(false); + UnoTextSection.create(doc, BIB_SECTION_NAME, textCursor, false); + } + + /** + * Find and clear the text section BIB_SECTION_NAME to "", + * or create it. + * + * Only called from: `rebuildBibTextSection` + * + */ + private static void clearBibTextSectionContent2(XTextDocument doc) + throws + CreationException, + IllegalArgumentException, + NoDocumentException, + WrappedTargetException { + + // Optional sectionRange = UnoTextSection.getAnchor(doc, BIB_SECTION_NAME); + Optional sectionRange = getBibliographyRange(doc); + if (sectionRange.isEmpty()) { + createBibTextSection2(doc); + return; + } else { + // Clear it + XTextCursor cursor = doc.getText().createTextCursorByRange(sectionRange.get()); + cursor.setString(""); + } + } + + /** + * Only called from: `rebuildBibTextSection` + * + * Assumes the section named BIB_SECTION_NAME exists. + */ + private static void populateBibTextSection(XTextDocument doc, + OOFrontend fr, + CitedKeys bibliography, + OOBibStyle style, + boolean alwaysAddCitedOnPages) + throws + CreationException, + IllegalArgumentException, + NoDocumentException, + NoSuchElementException, + PropertyVetoException, + UnknownPropertyException, + WrappedTargetException { + + XTextRange sectionRange = getBibliographyRange(doc).orElseThrow(RuntimeException::new); + + XTextCursor cursor = doc.getText().createTextCursorByRange(sectionRange); + + // emit the title of the bibliography + OOTextIntoOO.removeDirectFormatting(cursor); + OOText bibliographyText = OOFormatBibliography.formatBibliography(fr.citationGroups, + bibliography, + style, + alwaysAddCitedOnPages); + OOTextIntoOO.write(doc, cursor, bibliographyText); + cursor.collapseToEnd(); + + // remove the inital empty paragraph from the section. + sectionRange = getBibliographyRange(doc).orElseThrow(RuntimeException::new); + XTextCursor initialParagraph = doc.getText().createTextCursorByRange(sectionRange); + initialParagraph.collapseToStart(); + initialParagraph.goRight((short) 1, true); + initialParagraph.setString(""); + + UnoBookmark.remove(doc, BIB_SECTION_END_NAME); + UnoBookmark.create(doc, BIB_SECTION_END_NAME, cursor, true); + + cursor.collapseToEnd(); + } + +} diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java new file mode 100644 index 00000000000..7d864ab1063 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java @@ -0,0 +1,174 @@ +package org.jabref.logic.openoffice.frontend; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import org.jabref.logic.JabRefException; +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.ootext.OOTextIntoOO; +import org.jabref.model.openoffice.style.CitationGroup; +import org.jabref.model.openoffice.style.CitationGroups; +import org.jabref.model.openoffice.style.CitationType; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/* + * Update document: citation marks and bibliography + */ +public class UpdateCitationMarkers { + + private static final Logger LOGGER = LoggerFactory.getLogger(UpdateCitationMarkers.class); + + /** + * Visit each reference mark in referenceMarkNames, overwrite its + * text content. + * + * After each fillCitationMarkInCursor call check if we lost the + * BIB_SECTION_NAME bookmark and recreate it if we did. + * + * @param fr + * + * @param style Bibliography style to use. + * + */ + public static void applyNewCitationMarkers(XTextDocument doc, OOFrontend fr, OOBibStyle style) + throws + NoDocumentException, + UnknownPropertyException, + CreationException, + WrappedTargetException, + PropertyVetoException, + NoSuchElementException, + JabRefException { + + CitationGroups citationGroups = fr.citationGroups; + + for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { + + boolean withText = (cg.citationType != CitationType.INVISIBLE_CIT); + Optional marker = cg.getCitationMarker(); + + if (!marker.isPresent()) { + String msg = String.format("applyNewCitationMarkers: no marker for %s", + cg.cgid.citationGroupIdAsString()); + LOGGER.warn(msg); + continue; + } + + if (withText && marker.isPresent()) { + + XTextCursor cursor = fr.getFillCursorForCitationGroup(doc, cg); + + fillCitationMarkInCursor(doc, cursor, marker.get(), withText, style); + + fr.cleanFillCursorForCitationGroup(doc, cg); + } + + } + } + + public static void fillCitationMarkInCursor(XTextDocument doc, + XTextCursor cursor, + OOText citationText, + boolean withText, + OOBibStyle style) + throws + UnknownPropertyException, + PropertyVetoException, + WrappedTargetException, + NoSuchElementException, + CreationException, + IllegalArgumentException { + + Objects.requireNonNull(cursor); + Objects.requireNonNull(citationText); + Objects.requireNonNull(style); + + if (withText) { + OOText citationText2 = style.decorateCitationMarker(citationText); + // inject a ZERO_WIDTH_SPACE to hold the initial character format + final String ZERO_WIDTH_SPACE = "\u200b"; + citationText2 = OOText.fromString(ZERO_WIDTH_SPACE + citationText2.asString()); + OOTextIntoOO.write(doc, cursor, citationText2); + } else { + cursor.setString(""); + } + } + + /** + * Inserts a citation group in the document: creates and fills it. + * + * @param citationKeys BibTeX keys of + * @param pageInfos + * @param citationType + * + * @param citationText Text for the citation. A citation mark or + * placeholder if not yet available. + * + * @param position Location to insert at. + * @param style + * @param insertSpaceAfter A space inserted after the reference + * mark makes it easier to separate from the text + * coming after. But is not wanted when we recreate a + * reference mark. + */ + public static void createAndFillCitationGroup(OOFrontend fr, + XTextDocument doc, + List citationKeys, + List> pageInfos, + CitationType citationType, + OOText citationText, + XTextCursor position, + OOBibStyle style, + boolean insertSpaceAfter) + throws + UnknownPropertyException, + NotRemoveableException, + PropertyExistException, + PropertyVetoException, + WrappedTargetException, + PropertyVetoException, + IllegalArgumentException, + CreationException, + NoDocumentException, + IllegalTypeException, + NoSuchElementException { + + Objects.requireNonNull(pageInfos); + if (pageInfos.size() != citationKeys.size()) { + throw new RuntimeException("pageInfos.size != citationKeys.size"); + } + CitationGroup cg = fr.createCitationGroup(doc, + citationKeys, + pageInfos, + citationType, + position, + insertSpaceAfter); + + final boolean withText = citationType.withText(); + + if (withText) { + XTextCursor c2 = fr.getFillCursorForCitationGroup(doc, cg); + + UpdateCitationMarkers.fillCitationMarkInCursor(doc, c2, citationText, withText, style); + + fr.cleanFillCursorForCitationGroup(doc, cg); + } + position.collapseToEnd(); + } + +} diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index c2d0ea46ee7..dc2fd8df58a 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -1529,6 +1529,10 @@ Custom=Custom Export\ cited=Export cited Unable\ to\ generate\ new\ library=Unable to generate new library +Found\ identical\ ranges=Found identical ranges +Found\ overlapping\ ranges=Found overlapping ranges +Found\ touching\ ranges=Found touching ranges + Note\:\ Use\ the\ placeholder\ %DIR%\ for\ the\ location\ of\ the\ opened\ library\ file.=Note: Use the placeholder %DIR% for the location of the opened library file. Error\ occured\ while\ executing\ the\ command\ \"%0\".=Error occured while executing the command \"%0\". Reformat\ ISSN=Reformat ISSN From 3632d00fa02dd12a86819c96c73c6133c748cec9 Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 11:58:32 +0200 Subject: [PATCH 018/103] add actions --- .../logic/openoffice/action/EditInsert.java | 130 ++++++ .../logic/openoffice/action/EditMerge.java | 372 ++++++++++++++++++ .../logic/openoffice/action/EditSeparate.java | 106 +++++ .../logic/openoffice/action/ExportCited.java | 98 +++++ .../openoffice/action/ManageCitations.java | 41 ++ .../logic/openoffice/action/Update.java | 145 +++++++ 6 files changed, 892 insertions(+) create mode 100644 src/main/java/org/jabref/logic/openoffice/action/EditInsert.java create mode 100644 src/main/java/org/jabref/logic/openoffice/action/EditMerge.java create mode 100644 src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java create mode 100644 src/main/java/org/jabref/logic/openoffice/action/ExportCited.java create mode 100644 src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java create mode 100644 src/main/java/org/jabref/logic/openoffice/action/Update.java diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java new file mode 100644 index 00000000000..277b92bec76 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java @@ -0,0 +1,130 @@ +package org.jabref.logic.openoffice.action; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import org.jabref.logic.JabRefException; +import org.jabref.logic.openoffice.frontend.OOFrontend; +import org.jabref.logic.openoffice.frontend.UpdateCitationMarkers; +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.Citation; +import org.jabref.model.openoffice.style.CitationMarkerEntry; +import org.jabref.model.openoffice.style.CitationType; +import org.jabref.model.openoffice.style.NonUniqueCitationMarker; +import org.jabref.model.openoffice.style.OODataModel; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoScreenRefresh; +import org.jabref.model.openoffice.util.OOListUtil; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EditInsert { + + private static final Logger LOGGER = LoggerFactory.getLogger(EditInsert.class); + + /** + * In insertEntry we receive BibEntry values from the GUI. + * + * In the document we store citations by their citation key. + * + * If the citation key is missing, the best we can do is to notify + * the user. Or the programmer, that we cannot accept such input. + * + */ + private static String insertEntryGetCitationKey(BibEntry entry) { + Optional key = entry.getCitationKey(); + if (key.isEmpty()) { + throw new RuntimeException("insertEntryGetCitationKey:" + + " cannot cite entries without citation key"); + } + return key.get(); + } + + /* + * @param cursor Where to insert. + * + * @param sync If not empty, update citation markers and, + * depending on the embedded options, the + * bibliography. + * + * @param fcursor If sync.isPresent(), it must provide a + * FunctionalTextViewCursor. Otherwise not used. + */ + public static void insertCitationGroup(XTextDocument doc, + OOFrontend fr, + XTextCursor cursor, + List entries, + BibDatabase database, + OOBibStyle style, + CitationType citationType, + String pageInfo) + throws + UnknownPropertyException, + NoDocumentException, + NotRemoveableException, + WrappedTargetException, + PropertyVetoException, + PropertyExistException, + NoSuchElementException, + CreationException, + IllegalTypeException, + JabRefException { + + List citationKeys = OOListUtil.map(entries, EditInsert::insertEntryGetCitationKey); + + final int nEntries = entries.size(); + List> pageInfos = OODataModel.fakePageInfos(pageInfo, nEntries); + + List citations = new ArrayList<>(nEntries); + for (int i = 0; i < nEntries; i++) { + Citation cit = new Citation(citationKeys.get(i)); + cit.lookupInDatabases(Collections.singletonList(database)); + cit.setPageInfo(pageInfos.get(i)); + citations.add(cit); + } + + // The text we insert + OOText citeText = + (style.isNumberEntries() + ? OOText.fromString("[-]") // A dash only. Only refresh later. + : style.createCitationMarker(citations, + citationType.inParenthesis(), + NonUniqueCitationMarker.FORGIVEN)); + + if ("".equals(OOText.toString(citeText))) { + citeText = OOText.fromString("[?]"); + } + + try { + UnoScreenRefresh.lockControllers(doc); + UpdateCitationMarkers.createAndFillCitationGroup(fr, + doc, + citationKeys, + pageInfos, + citationType, + citeText, + cursor, + style, + true /* insertSpaceAfter */); + } finally { + UnoScreenRefresh.unlockControllers(doc); + } + + } +} diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java new file mode 100644 index 00000000000..823610c51cf --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java @@ -0,0 +1,372 @@ +package org.jabref.logic.openoffice.action; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.jabref.logic.JabRefException; +import org.jabref.logic.openoffice.frontend.OOFrontend; +import org.jabref.logic.openoffice.frontend.UpdateCitationMarkers; +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.Citation; +import org.jabref.model.openoffice.style.CitationGroup; +import org.jabref.model.openoffice.style.CitationType; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoScreenRefresh; +import org.jabref.model.openoffice.uno.UnoTextRange; +import org.jabref.model.openoffice.util.OOListUtil; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import com.sun.star.util.InvalidStateException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EditMerge { + + private static final Logger LOGGER = LoggerFactory.getLogger(EditMerge.class); + + private EditMerge() { + // hide constructor + } + + /* + * @return true if modified document + */ + public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend fr, OOBibStyle style) + throws + CreationException, + IllegalArgumentException, + IllegalTypeException, + InvalidStateException, + JabRefException, + NoDocumentException, + NoSuchElementException, + NotRemoveableException, + PropertyExistException, + PropertyVetoException, + UnknownPropertyException, + WrappedTargetException { + + boolean madeModifications = false; + + try { + UnoScreenRefresh.lockControllers(doc); + + List joinableGroups = EditMerge.scan(doc, fr); + + for (JoinableGroupData joinableGroupData : joinableGroups) { + + List cgs = joinableGroupData.group; + + List newCitations = (cgs.stream() + .flatMap(cg -> cg.citationsInStorageOrder.stream()) + .collect(Collectors.toList())); + + CitationType citationType = cgs.get(0).citationType; + List> pageInfos = fr.backend.combinePageInfos(cgs); + + fr.removeCitationGroups(cgs, doc); + XTextCursor textCursor = joinableGroupData.groupCursor; + textCursor.setString(""); // Also remove the spaces between. + + List citationKeys = OOListUtil.map(newCitations, Citation::getCitationKey); + + /* insertSpaceAfter: no, it is already there (or could be) */ + boolean insertSpaceAfter = false; + UpdateCitationMarkers.createAndFillCitationGroup(fr, + doc, + citationKeys, + pageInfos, + citationType, + OOText.fromString("tmp"), + textCursor, + style, + insertSpaceAfter); + } + + madeModifications = !joinableGroups.isEmpty(); + + } finally { + UnoScreenRefresh.unlockControllers(doc); + } + + return madeModifications; + } + + private static class JoinableGroupData { + /* + * A list of consecutive citation groups only separated by spaces. + */ + List group; + /* + * A cursor covering the XTextRange of each entry in group + * (and the spaces between them) + */ + XTextCursor groupCursor; + + JoinableGroupData(List group, XTextCursor groupCursor) { + this.group = group; + this.groupCursor = groupCursor; + } + } + + private static class ScanState { + + // Citation groups in the current group + List currentGroup; + + // A cursor that covers the Citation groups in currentGroup, + // including the space between them. + // Null if currentGroup.isEmpty() + XTextCursor currentGroupCursor; + + // A cursor starting at the end of the last CitationGroup in + // currentGroup. Null if currentGroup.isEmpty() + XTextCursor cursorBetween; + + // The last element of currentGroup. + // Null if currentGroup.isEmpty() + CitationGroup prev; + + // The XTextRange for prev. + // Null if currentGroup.isEmpty() + XTextRange prevRange; + + ScanState() { + reset(); + } + + void reset() { + currentGroup = new ArrayList<>(); + currentGroupCursor = null; + cursorBetween = null; + prev = null; + prevRange = null; + } + } + + /** + * Decide if cg could be added to state.currentGroup + * + * @param cg The CitationGroup to test + * @param currentRange The XTextRange corresponding to cg. + * + * @return false if cannot add, true if can. If returned true, + * then state.cursorBetween and state.currentGroupCursor are + * expanded to end at the start of currentRange. + */ + private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextRange currentRange) { + + if (state.currentGroup.isEmpty()) { + return false; + } + + Objects.requireNonNull(state.currentGroupCursor); + Objects.requireNonNull(state.cursorBetween); + Objects.requireNonNull(state.prev); + Objects.requireNonNull(state.prevRange); + + // Only combine (Author 2000) type citations + if (cg.citationType != CitationType.AUTHORYEAR_PAR) { + return false; + } + + if (state.prev != null) { + + // Even if we combine AUTHORYEAR_INTEXT citations, we + // would not mix them with AUTHORYEAR_PAR + if (cg.citationType != state.prev.citationType) { + return false; + } + + if (!UnoTextRange.comparables(state.prevRange, currentRange)) { + return false; + } + + // Sanity check: the current range should start later than + // the previous. + int textOrder = UnoTextRange.compareStarts(state.prevRange, currentRange); + if (textOrder != (-1)) { + String msg = + String.format("MergeCitationGroups:" + + " \"%s\" supposed to be followed by \"%s\"," + + " but %s", + state.prevRange.getString(), + currentRange.getString(), + ((textOrder == 0) + ? "they start at the same position" + : ("the start of the latter precedes" + + " the start of the first"))); + LOGGER.warn(msg); + return false; + } + } + + if (state.cursorBetween == null) { + return false; + } + + Objects.requireNonNull(state.cursorBetween); + Objects.requireNonNull(state.currentGroupCursor); + + // assume: currentGroupCursor.getEnd() == cursorBetween.getEnd() + if (UnoTextRange.compareEnds(state.cursorBetween, state.currentGroupCursor) != 0) { + String msg = ("MergeCitationGroups:" + + " cursorBetween.end != currentGroupCursor.end"); + throw new RuntimeException(msg); + } + + /* + * Try to expand state.currentGroupCursor and state.cursorBetween by going right + * to reach rangeStart. + */ + XTextRange rangeStart = currentRange.getStart(); + boolean couldExpand = true; + XTextCursor thisCharCursor = + (currentRange.getText().createTextCursorByRange(state.cursorBetween.getEnd())); + + while (couldExpand && (UnoTextRange.compareEnds(state.cursorBetween, rangeStart) < 0)) { + // + // Check that we only walk through inline whitespace. + // + couldExpand = thisCharCursor.goRight((short) 1, true); + String thisChar = thisCharCursor.getString(); + thisCharCursor.collapseToEnd(); + if (thisChar.isEmpty() || thisChar.equals("\n") || !thisChar.trim().isEmpty()) { + couldExpand = false; + if (!thisChar.isEmpty()) { + thisCharCursor.goLeft((short) 1, false); + } + break; + } + state.cursorBetween.goRight((short) 1, true); + state.currentGroupCursor.goRight((short) 1, true); + + // These two should move in sync: + if (UnoTextRange.compareEnds(state.cursorBetween, state.currentGroupCursor) != 0) { + String msg = ("MergeCitationGroups:" + + " cursorBetween.end != currentGroupCursor.end" + + " (during expand)"); + throw new RuntimeException(msg); + } + } // while + + if (!couldExpand) { + return false; + } + + return true; + } + + /** + * Add cg to state.currentGroup + * Set state.cursorBetween to start at currentRange.getEnd() + * Expand state.currentGroupCursor to also cover currentRange + * Set state.prev to cg, state.prevRange to currentRange + */ + private static void addToCurrentGroup(ScanState state, CitationGroup cg, XTextRange currentRange) { + final boolean isNewGroup = state.currentGroup.isEmpty(); + if (!isNewGroup) { + Objects.requireNonNull(state.currentGroupCursor); + Objects.requireNonNull(state.cursorBetween); + Objects.requireNonNull(state.prev); + Objects.requireNonNull(state.prevRange); + } + + // Add the current entry to a group. + state.currentGroup.add(cg); + + // Set up cursorBetween to start at currentRange.getEnd() + XTextRange rangeEnd = currentRange.getEnd(); + state.cursorBetween = currentRange.getText().createTextCursorByRange(rangeEnd); + + // If new group, create currentGroupCursor + if (isNewGroup) { + state.currentGroupCursor = (currentRange.getText() + .createTextCursorByRange(currentRange.getStart())); + } + + // include currentRange in currentGroupCursor + state.currentGroupCursor.goRight((short) (currentRange.getString().length()), true); + + if (UnoTextRange.compareEnds(state.cursorBetween, state.currentGroupCursor) != 0) { + String msg = ("MergeCitationGroups: cursorBetween.end != currentGroupCursor.end"); + throw new RuntimeException(msg); + } + + /* Store data about last entry in currentGroup */ + state.prev = cg; + state.prevRange = currentRange; + } + + /** + * Scan the document for joinable groups. Return those found. + */ + private static List scan(XTextDocument doc, OOFrontend fr) + throws + NoDocumentException, + WrappedTargetException { + List result = new ArrayList<>(); + + List cgs = + fr.getCitationGroupsSortedWithinPartitions(doc, + false /* mapFootnotesToFootnoteMarks */); + if (cgs.isEmpty()) { + return result; + } + + ScanState state = new ScanState(); + + for (CitationGroup cg : cgs) { + + XTextRange currentRange = (fr.getMarkRange(doc, cg) + .orElseThrow(RuntimeException::new)); + + /* + * Decide if we add cg to the group. False when the group is empty. + */ + boolean addToGroup = checkAddToGroup(state, cg, currentRange); + + /* + * Even if we do not add it to an existing group, + * we might use it to start a new group. + * + * Can it start a new group? + */ + boolean canStartGroup = (cg.citationType == CitationType.AUTHORYEAR_PAR); + + if (!addToGroup) { + // close currentGroup + if (state.currentGroup.size() > 1) { + result.add(new JoinableGroupData(state.currentGroup, state.currentGroupCursor)); + } + // Start a new, empty group + state.reset(); + } + + if (addToGroup || canStartGroup) { + addToCurrentGroup(state, cg, currentRange); + } + } + + // close currentGroup + if (state.currentGroup.size() > 1) { + result.add(new JoinableGroupData(state.currentGroup, state.currentGroupCursor)); + } + return result; + } + +} diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java new file mode 100644 index 00000000000..31c23ed52d0 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java @@ -0,0 +1,106 @@ +package org.jabref.logic.openoffice.action; + +import java.util.List; + +import org.jabref.logic.JabRefException; +import org.jabref.logic.openoffice.frontend.OOFrontend; +import org.jabref.logic.openoffice.frontend.UpdateCitationMarkers; +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.logic.openoffice.style.OOProcess; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.Citation; +import org.jabref.model.openoffice.style.CitationGroup; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoScreenRefresh; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import com.sun.star.util.InvalidStateException; + +public class EditSeparate { + + public static boolean separateCitations(XTextDocument doc, + OOFrontend fr, + List databases, + OOBibStyle style) + throws + CreationException, + IllegalTypeException, + InvalidStateException, + JabRefException, + NoDocumentException, + NoSuchElementException, + NotRemoveableException, + PropertyExistException, + PropertyVetoException, + UnknownPropertyException, + WrappedTargetException, + com.sun.star.lang.IllegalArgumentException { + + boolean madeModifications = false; + + // To reduce surprises in JabRef52 mode, impose localOrder to + // decide the visually last Citation in the group. Unless the + // style changed since refresh this is the last on the screen + // as well. + fr.citationGroups.lookupCitations(databases); + fr.citationGroups.imposeLocalOrder(OOProcess.comparatorForMulticite(style)); + + List cgs = fr.citationGroups.getCitationGroupsUnordered(); + + try { + UnoScreenRefresh.lockControllers(doc); + + for (CitationGroup cg : cgs) { + + XTextRange range1 = (fr + .getMarkRange(doc, cg) + .orElseThrow(RuntimeException::new)); + XTextCursor textCursor = range1.getText().createTextCursorByRange(range1); + + List cits = cg.citationsInStorageOrder; + if (cits.size() <= 1) { + continue; + } + + fr.removeCitationGroup(cg, doc); + // Now we own the content of cits + + // Create a citation group for each citation. + final int last = cits.size() - 1; + for (int i = 0; i < cits.size(); i++) { + boolean insertSpaceAfter = (i != last); + Citation cit = cits.get(i); + + UpdateCitationMarkers.createAndFillCitationGroup( + fr, + doc, + List.of(cit.citationKey), + List.of(cit.getPageInfo()), + cg.citationType, + OOText.fromString(cit.citationKey), + textCursor, + style, + insertSpaceAfter); + + textCursor.collapseToEnd(); + } + + madeModifications = true; + } + } finally { + UnoScreenRefresh.unlockControllers(doc); + } + return madeModifications; + } +} diff --git a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java new file mode 100644 index 00000000000..8d344688c68 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java @@ -0,0 +1,98 @@ +package org.jabref.logic.openoffice.action; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.jabref.logic.openoffice.frontend.OOFrontend; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.StandardField; +import org.jabref.model.openoffice.style.CitedKey; +import org.jabref.model.openoffice.style.CitedKeys; +import org.jabref.model.openoffice.uno.NoDocumentException; + +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextDocument; + +public class ExportCited { + + public static class GenerateDatabaseResult { + /** + * null: not done; isEmpty: no unresolved + */ + public final List unresolvedKeys; + public final BibDatabase newDatabase; + + GenerateDatabaseResult(List unresolvedKeys, BibDatabase newDatabase) { + this.unresolvedKeys = unresolvedKeys; + this.newDatabase = newDatabase; + } + } + + /** + * + * @param databases The databases to look up the citation keys in the document from. + * @return A new database, with cloned entries. + * + * If a key is not found, it is added to result.unresolvedKeys + * + * Cross references (in StandardField.CROSSREF) are followed (not recursively): + * if the referenced entry is found, it is included in the result. + * If it is not found, it is silently ignored. + */ + public static GenerateDatabaseResult generateDatabase(XTextDocument doc, List databases) + throws + NoDocumentException, + NoSuchElementException, + UnknownPropertyException, + WrappedTargetException { + + OOFrontend fr = new OOFrontend(doc); + CitedKeys cks = fr.citationGroups.getCitedKeysUnordered(); + cks.lookupInDatabases(databases); + + List unresolvedKeys = new ArrayList<>(); + BibDatabase resultDatabase = new BibDatabase(); + + List entriesToInsert = new ArrayList<>(); + Set seen = new HashSet<>(); // Only add crossReference once. + + for (CitedKey ck : cks.values()) { + if (ck.getLookupResult().isEmpty()) { + unresolvedKeys.add(ck.citationKey); + continue; + } else { + BibEntry entry = ck.getLookupResult().get().entry; + BibDatabase loopDatabase = ck.getLookupResult().get().database; + + // If entry found + BibEntry clonedEntry = (BibEntry) entry.clone(); + + // Insert a copy of the entry + entriesToInsert.add(clonedEntry); + + // Check if the cloned entry has a cross-reference field + clonedEntry + .getField(StandardField.CROSSREF) + .ifPresent(crossReference -> { + boolean isNew = !seen.contains(crossReference); + if (isNew) { + // Add it if it is in the current library + loopDatabase + .getEntryByCitationKey(crossReference) + .ifPresent(entriesToInsert::add); + seen.add(crossReference); + } + }); + } + } + + resultDatabase.insertEntries(entriesToInsert); + return new GenerateDatabaseResult(unresolvedKeys, resultDatabase); + } + +} diff --git a/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java b/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java new file mode 100644 index 00000000000..4046cbbe11b --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java @@ -0,0 +1,41 @@ +package org.jabref.logic.openoffice.action; + +import java.util.List; + +import org.jabref.logic.openoffice.frontend.OOFrontend; +import org.jabref.model.openoffice.CitationEntry; +import org.jabref.model.openoffice.uno.NoDocumentException; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextDocument; + +public class ManageCitations { + + public static List getCitationEntries(XTextDocument doc) + throws + NoDocumentException, + UnknownPropertyException, + WrappedTargetException { + OOFrontend fr = new OOFrontend(doc); + return fr.getCitationEntries(doc); + } + + public static void applyCitationEntries(XTextDocument doc, List citationEntries) + throws + NoDocumentException, + UnknownPropertyException, + NotRemoveableException, + PropertyExistException, + PropertyVetoException, + IllegalTypeException, + WrappedTargetException, + IllegalArgumentException { + OOFrontend fr = new OOFrontend(doc); + fr.applyCitationEntries(doc, citationEntries); + } +} diff --git a/src/main/java/org/jabref/logic/openoffice/action/Update.java b/src/main/java/org/jabref/logic/openoffice/action/Update.java new file mode 100644 index 00000000000..151e4b6575b --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/action/Update.java @@ -0,0 +1,145 @@ +package org.jabref.logic.openoffice.action; + +import java.util.List; + +import org.jabref.logic.JabRefException; +import org.jabref.logic.openoffice.frontend.OOFrontend; +import org.jabref.logic.openoffice.frontend.UpdateBibliography; +import org.jabref.logic.openoffice.frontend.UpdateCitationMarkers; +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.logic.openoffice.style.OOProcess; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.openoffice.rangesort.FunctionalTextViewCursor; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoScreenRefresh; + +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextDocument; + +/* + * Update document: citation marks and bibliography + */ +public class Update { + + /* + * @return unresolvedKeys + */ + private static List updateDocument(XTextDocument doc, + OOFrontend fr, + List databases, + OOBibStyle style, + FunctionalTextViewCursor fcursor, + boolean doUpdateBibliography, + boolean alwaysAddCitedOnPages) + throws + CreationException, + JabRefException, + NoDocumentException, + NoSuchElementException, + PropertyVetoException, + UnknownPropertyException, + WrappedTargetException, + com.sun.star.lang.IllegalArgumentException { + + final boolean useLockControllers = true; + + fr.imposeGlobalOrder(doc, fcursor); + OOProcess.produceCitationMarkers(fr.citationGroups, databases, style); + + try { + if (useLockControllers) { + UnoScreenRefresh.lockControllers(doc); + } + + UpdateCitationMarkers.applyNewCitationMarkers(doc, fr, style); + + if (doUpdateBibliography) { + UpdateBibliography.rebuildBibTextSection(doc, + fr, + fr.citationGroups.getBibliography().get(), + style, + alwaysAddCitedOnPages); + } + List result = fr.citationGroups.getUnresolvedKeys(); + return result; + } finally { + if (useLockControllers && UnoScreenRefresh.hasControllersLocked(doc)) { + UnoScreenRefresh.unlockControllers(doc); + } + } + } + + public static class SyncOptions { + + public final List databases; + boolean updateBibliography; + boolean alwaysAddCitedOnPages; + + public SyncOptions(List databases) { + this.databases = databases; + this.updateBibliography = false; + this.alwaysAddCitedOnPages = false; + } + + public SyncOptions setUpdateBibliography(boolean value) { + this.updateBibliography = value; + return this; + } + + public SyncOptions setAlwaysAddCitedOnPages(boolean value) { + this.alwaysAddCitedOnPages = value; + return this; + } + } + + public static List synchronizeDocument(XTextDocument doc, + OOFrontend fr, + OOBibStyle style, + FunctionalTextViewCursor fcursor, + SyncOptions syncOptions) + throws + CreationException, + JabRefException, + NoDocumentException, + NoSuchElementException, + PropertyVetoException, + UnknownPropertyException, + WrappedTargetException, + com.sun.star.lang.IllegalArgumentException { + + return Update.updateDocument(doc, + fr, + syncOptions.databases, + style, + fcursor, + syncOptions.updateBibliography, + syncOptions.alwaysAddCitedOnPages); + } + + /* + * Reread document before sync + */ + public static List resyncDocument(XTextDocument doc, + OOBibStyle style, + FunctionalTextViewCursor fcursor, + SyncOptions syncOptions) + throws + CreationException, + JabRefException, + NoDocumentException, + NoSuchElementException, + PropertyVetoException, + UnknownPropertyException, + WrappedTargetException, + com.sun.star.lang.IllegalArgumentException { + + OOFrontend fr = new OOFrontend(doc); + + return Update.synchronizeDocument(doc, fr, style, fcursor, syncOptions); + } + +} From fc534c18548b5e17c8cf63f4f820e52e8d2c71f3 Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 12:16:34 +0200 Subject: [PATCH 019/103] add gui stuff --- .../org/jabref/gui/openoffice/OOBibBase2.java | 973 ++++++++++++++++++ .../gui/openoffice/OOBibBaseConnect.java | 259 +++++ .../org/jabref/gui/openoffice/OOError.java | 141 +++ .../openoffice/NoDocumentFoundException.java | 12 + src/main/resources/l10n/JabRef_en.properties | 72 ++ 5 files changed, 1457 insertions(+) create mode 100644 src/main/java/org/jabref/gui/openoffice/OOBibBase2.java create mode 100644 src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java create mode 100644 src/main/java/org/jabref/gui/openoffice/OOError.java create mode 100644 src/main/java/org/jabref/logic/openoffice/NoDocumentFoundException.java diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java new file mode 100644 index 00000000000..ca8324cda2a --- /dev/null +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java @@ -0,0 +1,973 @@ +package org.jabref.gui.openoffice; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import org.jabref.gui.DialogService; +import org.jabref.logic.JabRefException; +import org.jabref.logic.l10n.Localization; +import org.jabref.logic.openoffice.NoDocumentFoundException; +import org.jabref.logic.openoffice.action.EditInsert; +import org.jabref.logic.openoffice.action.EditMerge; +import org.jabref.logic.openoffice.action.EditSeparate; +import org.jabref.logic.openoffice.action.ExportCited; +import org.jabref.logic.openoffice.action.ManageCitations; +import org.jabref.logic.openoffice.action.Update; +import org.jabref.logic.openoffice.frontend.OOFrontend; +import org.jabref.logic.openoffice.frontend.RangeForOverlapCheck; +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.openoffice.CitationEntry; +import org.jabref.model.openoffice.rangesort.FunctionalTextViewCursor; +import org.jabref.model.openoffice.style.CitationGroupId; +import org.jabref.model.openoffice.style.CitationType; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoCrossRef; +import org.jabref.model.openoffice.uno.UnoCursor; +import org.jabref.model.openoffice.uno.UnoRedlines; +import org.jabref.model.openoffice.uno.UnoStyle; +import org.jabref.model.openoffice.uno.UnoUndo; +import org.jabref.model.openoffice.util.OOResult; +import org.jabref.model.openoffice.util.OOVoidResult; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.comp.helper.BootstrapException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.DisposedException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import com.sun.star.util.InvalidStateException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class for manipulating the Bibliography of the currently started + * document in OpenOffice. + */ +class OOBibBase2 { + + private static final Logger LOGGER = LoggerFactory.getLogger(OOBibBase2.class); + + /* variables */ + private final DialogService dialogService; + + /* + * After inserting a citation, if ooPrefs.getSyncWhenCiting() returns true, + * shall we also update the bibliography? + */ + private final boolean refreshBibliographyDuringSyncWhenCiting; + + /* + * Shall we add "Cited on pages: ..." to resolved bibliography entries? + */ + private final boolean alwaysAddCitedOnPages; + + private final OOBibBaseConnect connection; + + /* + * Constructor + */ + public OOBibBase2(Path loPath, DialogService dialogService) + throws + BootstrapException, + CreationException { + + this.dialogService = dialogService; + this.connection = new OOBibBaseConnect(loPath, dialogService); + + this.refreshBibliographyDuringSyncWhenCiting = false; + this.alwaysAddCitedOnPages = false; + } + + public void guiActionSelectDocument(boolean autoSelectForSingle) { + final String title = Localization.lang("Problem connecting"); + + try { + + this.connection.selectDocument(autoSelectForSingle); + + } catch (NoDocumentFoundException ex) { + OOError.from(ex).showErrorDialog(dialogService); + } catch (DisposedException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (WrappedTargetException + | IndexOutOfBoundsException + | NoSuchElementException ex) { + LOGGER.warn("Problem connecting", ex); + OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + } + + if (this.isConnectedToDocument()) { + dialogService.notify(Localization.lang("Connected to document") + ": " + + this.getCurrentDocumentTitle().orElse("")); + } + } + + /** + * A simple test for document availability. + * + * See also `isDocumentConnectionMissing` for a test + * actually attempting to use the connection. + * + */ + public boolean isConnectedToDocument() { + return this.connection.isConnectedToDocument(); + } + + /** + * @return true if we are connected to a document + */ + public boolean isDocumentConnectionMissing() { + return this.connection.isDocumentConnectionMissing(); + } + + /** + * Either return an XTextDocument or return JabRefException. + */ + public OOResult getXTextDocument() { + return this.connection.getXTextDocument(); + } + + /** + * The title of the current document, or Optional.empty() + */ + public Optional getCurrentDocumentTitle() { + return this.connection.getCurrentDocumentTitle(); + } + + /* ****************************************************** + * + * Tools to collect and show precondition test results + * + * ******************************************************/ + + void showDialog(OOError ex) { + ex.showErrorDialog(dialogService); + } + + void showDialog(String title, OOError ex) { + ex.setTitle(title).showErrorDialog(dialogService); + } + + OOVoidResult collectResults(String title, List> results) { + String msg = (results.stream() + .filter(e -> e.isError()) + .map(e -> e.getError().getLocalizedMessage()) + .collect(Collectors.joining("\n\n"))); + if (msg.isEmpty()) { + return OOVoidResult.ok(); + } else { + return OOVoidResult.error(new OOError(title, msg)); + } + } + + boolean testDialog(OOVoidResult res) { + return res.ifError(ex -> ex.showErrorDialog(dialogService)).isError(); + } + + boolean testDialog(String title, OOVoidResult res) { + return res.ifError(e -> showDialog(e.setTitle(title))).isError(); + } + + boolean testDialog(String title, List> results) { + return testDialog(title, collectResults(title, results)); + } + + @SafeVarargs + final boolean testDialog(String title, OOVoidResult... results) { + List> rs = Arrays.asList(results); + return testDialog(collectResults(title, rs)); + } + + /* + * + * Get the cursor positioned by the user for inserting text. + * + */ + OOResult getUserCursorForTextInsertion(XTextDocument doc, String title) { + + XTextCursor cursor; + // Get the cursor positioned by the user. + try { + cursor = UnoCursor.getViewCursor(doc).orElse(null); + } catch (RuntimeException ex) { + return OOResult.error(new OOError(title, + Localization.lang("Could not get the cursor."), + ex)); + } + + // Check for crippled XTextViewCursor + Objects.requireNonNull(cursor); + try { + cursor.getStart(); + } catch (com.sun.star.uno.RuntimeException ex) { + String msg = + Localization.lang("Please move the cursor" + + " to the location for the new citation.") + + "\n" + + Localization.lang("I cannot insert to the cursors current location."); + return OOResult.error(new OOError(title, msg, ex)); + } + return OOResult.ok(cursor); + } + + /** + * This may move the view cursor. + */ + OOResult getFunctionalTextViewCursor(XTextDocument doc, + String title) { + String messageOnFailureToObtain = + Localization.lang("Please move the cursor into the document text.") + + "\n" + + Localization.lang("To get the visual positions of your citations" + + " I need to move the cursor around," + + " but could not get it."); + OOResult result = FunctionalTextViewCursor.get(doc); + if (result.isError()) { + LOGGER.warn(result.getError()); + } + return result.mapError(detail -> new OOError(title, messageOnFailureToObtain)); + } + + private static OOVoidResult checkRangeOverlaps(XTextDocument doc, OOFrontend fr) { + final String title = "checkRangeOverlaps"; + boolean requireSeparation = false; + int maxReportedOverlaps = 10; + try { + return (fr.checkRangeOverlaps(doc, + new ArrayList<>(), + requireSeparation, + maxReportedOverlaps) + .mapError(OOError::from)); + } catch (NoDocumentException ex) { + return OOVoidResult.error(OOError.from(ex).setTitle(title)); + } catch (WrappedTargetException ex) { + return OOVoidResult.error(OOError.fromMisc(ex).setTitle(title)); + } + } + + private static OOVoidResult checkRangeOverlapsWithCursor(XTextDocument doc, OOFrontend fr) { + final String title = "checkRangeOverlapsWithCursor"; + + List> userRanges; + try { + userRanges = fr.viewCursorRanges(doc); + } catch (NoDocumentException ex) { + return OOVoidResult.error(OOError.from(ex).setTitle(title)); + } catch (WrappedTargetException ex) { + return OOVoidResult.error(OOError.fromMisc(ex).setTitle(title)); + } + + boolean requireSeparation = false; + OOVoidResult res; + try { + res = fr.checkRangeOverlapsWithCursor(doc, + userRanges, + requireSeparation); + } catch (NoDocumentException ex) { + return OOVoidResult.error(OOError.from(ex).setTitle(title)); + } catch (WrappedTargetException ex) { + return OOVoidResult.error(OOError.fromMisc(ex).setTitle(title)); + } + + if (res.isError()) { + final String xtitle = Localization.lang("The cursor is in protected area."); + return OOVoidResult.error(new OOError(xtitle, + xtitle + "\n" + + res.getError().getLocalizedMessage() + "\n")); + } + return res.mapError(OOError::from); + } + + /* + * + * Tests for preconditions. + * + */ + + private static OOVoidResult checkIfOpenOfficeIsRecordingChanges(XTextDocument doc) { + + String title = Localization.lang("Recording and/or Recorded changes"); + try { + boolean recordingChanges = UnoRedlines.getRecordChanges(doc); + int nRedlines = UnoRedlines.countRedlines(doc); + if (recordingChanges || nRedlines > 0) { + String msg = ""; + if (recordingChanges) { + msg += Localization.lang("Cannot work with" + + " [Edit]/[Track Changes]/[Record] turned on."); + } + if (nRedlines > 0) { + if (recordingChanges) { + msg += "\n"; + } + msg += Localization.lang("Changes by JabRef" + + " could result in unexpected interactions with" + + " recorded changes."); + msg += "\n"; + msg += Localization.lang("Use [Edit]/[Track Changes]/[Manage] to resolve them first."); + } + return OOVoidResult.error(new OOError(title, msg)); + } + } catch (UnknownPropertyException | WrappedTargetException ex) { + String msg = Localization.lang("Error while checking if Writer" + + " is recording changes or has recorded changes."); + return OOVoidResult.error(new OOError(title, msg, ex)); + } + return OOVoidResult.ok(); + } + + OOVoidResult styleIsRequired(OOBibStyle style) { + if (style == null) { + return OOVoidResult.error(OOError.noValidStyleSelected()); + } else { + return OOVoidResult.ok(); + } + } + + OOResult getFrontend(XTextDocument doc) { + final String title = "getFrontend"; + try { + return OOResult.ok(new OOFrontend(doc)); + } catch (NoDocumentException ex) { + return OOResult.error(OOError.from(ex).setTitle(title)); + } catch (WrappedTargetException + | RuntimeException ex) { + return OOResult.error(OOError.fromMisc(ex).setTitle(title)); + } + } + + OOVoidResult databaseIsRequired(List databases, + Supplier fun) { + if (databases == null || databases.isEmpty()) { + return OOVoidResult.error(fun.get()); + } else { + return OOVoidResult.ok(); + } + } + + OOVoidResult selectedBibEntryIsRequired(List entries, + Supplier fun) { + if (entries == null || entries.isEmpty()) { + return OOVoidResult.error(fun.get()); + } else { + return OOVoidResult.ok(); + } + } + + /* + * Checks existence and also checks if it is not an internal name. + */ + private OOVoidResult checkStyleExistsInTheDocument(String familyName, + String styleName, + XTextDocument doc, + String labelInJstyleFile, + String pathToStyleFile) + throws + NoSuchElementException, + WrappedTargetException { + + Optional internalName = UnoStyle.getInternalNameOfStyle(doc, familyName, styleName); + + if (internalName.isEmpty()) { + String msg = + switch (familyName) { + case UnoStyle.PARAGRAPH_STYLES -> + Localization.lang("The %0 paragraph style '%1' is missing from the document", + labelInJstyleFile, + styleName); + case UnoStyle.CHARACTER_STYLES -> + Localization.lang("The %0 character style '%1' is missing from the document", + labelInJstyleFile, + styleName); + default -> + throw new RuntimeException("Expected " + UnoStyle.CHARACTER_STYLES + + " or " + UnoStyle.PARAGRAPH_STYLES + + " for familyName"); + } + + "\n" + + Localization.lang("Please create it in the document or change in the file:") + + "\n" + + pathToStyleFile; + return OOVoidResult.error(new OOError("StyleIsNotKnown", msg)); + } + + if (!internalName.get().equals(styleName)) { + String msg = + switch (familyName) { + case UnoStyle.PARAGRAPH_STYLES -> + Localization.lang("The %0 paragraph style '%1' is a display name for '%2'.", + labelInJstyleFile, + styleName, + internalName.get()); + case UnoStyle.CHARACTER_STYLES -> + Localization.lang("The %0 character style '%1' is a display name for '%2'.", + labelInJstyleFile, + styleName, + internalName.get()); + default -> + throw new RuntimeException("Expected " + UnoStyle.CHARACTER_STYLES + + " or " + UnoStyle.PARAGRAPH_STYLES + + " for familyName"); + } + + "\n" + + Localization.lang("Please use the latter in the style file below" + + " to avoid localization problems.") + + "\n" + + pathToStyleFile; + return OOVoidResult.error(new OOError("StyleNameIsNotInternal", msg)); + } + return OOVoidResult.ok(); + } + + public OOVoidResult checkStylesExistInTheDocument(OOBibStyle style, XTextDocument doc) { + + String pathToStyleFile = style.getPath(); + + List> results = new ArrayList<>(); + try { + results.add(checkStyleExistsInTheDocument(UnoStyle.PARAGRAPH_STYLES, + style.getReferenceHeaderParagraphFormat(), + doc, + "ReferenceHeaderParagraphFormat", + pathToStyleFile)); + results.add(checkStyleExistsInTheDocument(UnoStyle.PARAGRAPH_STYLES, + style.getReferenceParagraphFormat(), + doc, + "ReferenceParagraphFormat", + pathToStyleFile)); + if (style.isFormatCitations()) { + results.add(checkStyleExistsInTheDocument(UnoStyle.CHARACTER_STYLES, + style.getCitationCharacterFormat(), + doc, + "CitationCharacterFormat", + pathToStyleFile)); + } + } catch (NoSuchElementException + | WrappedTargetException ex) { + results.add(OOVoidResult.error(new OOError("Other error in checkStyleExistsInTheDocument", + ex.getMessage(), + ex))); + } + + return collectResults("checkStyleExistsInTheDocument failed", results); + } + + /* + * + * ManageCitationsDialogView + * + */ + public Optional> guiActionGetCitationEntries() { + + final Optional> FAIL = Optional.empty(); + final String title = Localization.lang("Problem collecting citations"); + + OOResult odoc = getXTextDocument(); + if (testDialog(title, odoc.asVoidResult())) { + return FAIL; + } + XTextDocument doc = odoc.get(); + + if (testDialog(title, checkIfOpenOfficeIsRecordingChanges(doc))) { + LOGGER.warn(title); + return FAIL; + } + + try { + + return Optional.of(ManageCitations.getCitationEntries(doc)); + + } catch (NoDocumentException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + return FAIL; + } catch (DisposedException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + return FAIL; + } catch (UnknownPropertyException + | WrappedTargetException ex) { + LOGGER.warn(title, ex); + OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + return FAIL; + } + } + + /** + * Apply editable parts of citationEntries to the document: store + * pageInfo. + * + * Does not change presentation. + * + * Note: we use no undo context here, because only + * DocumentConnection.setUserDefinedStringPropertyValue() is called, + * and Undo in LO will not undo that. + * + * GUI: "Manage citations" dialog "OK" button. + * Called from: ManageCitationsDialogViewModel.storeSettings + * + *

+ * Currently the only editable part is pageInfo. + *

+ * Since the only call to applyCitationEntries() only changes + * pageInfo w.r.t those returned by getCitationEntries(), we can + * do with the following restrictions: + *

    + *
  • Missing pageInfo means no action.
  • + *
  • Missing CitationEntry means no action (no attempt to remove + * citation from the text).
  • + *
+ */ + public void guiActionApplyCitationEntries(List citationEntries) { + + final String title = Localization.lang("Problem modifying citation"); + + OOResult odoc = getXTextDocument(); + if (testDialog(title, odoc.asVoidResult())) { + return; + } + XTextDocument doc = odoc.get(); + + try { + + ManageCitations.applyCitationEntries(doc, citationEntries); + + } catch (NoDocumentException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (DisposedException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (UnknownPropertyException + | NotRemoveableException + | PropertyExistException + | PropertyVetoException + | IllegalTypeException + | WrappedTargetException + | com.sun.star.lang.IllegalArgumentException ex) { + LOGGER.warn(title, ex); + OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + } + } + + /** + * + * Creates a citation group from {@code entries} at the cursor. + * + * Uses LO undo context "Insert citation". + * + * Note: Undo does not remove or reestablish custom properties. + * + * @param entries The entries to cite. + * + * @param database The database the entries belong to (all of them). + * Used when creating the citation mark. + * + * Consistency: for each entry in {@entries}: looking it up in + * {@code syncOptions.get().databases} (if present) + * should yield {@code database}. + * + * @param style The bibliography style we are using. + * + * @param citationType Indicates whether it is an in-text + * citation, a citation in parenthesis or + * an invisible citation. + * + * @param pageInfo A single page-info for these entries. + * Attributed to the last entry. + * + * @param syncOptions Indicates whether in-text citations + * should be refreshed in the document. + * Optional.empty() indicates no refresh. + * Otherwise provides options for refreshing + * the reference list. + */ + public void guiActionInsertEntry(List entries, + BibDatabase database, + OOBibStyle style, + CitationType citationType, + String pageInfo, + Optional syncOptions) { + + final String title = "Could not insert citation"; + + OOResult odoc = getXTextDocument(); + if (testDialog(title, + odoc.asVoidResult(), + styleIsRequired(style), + selectedBibEntryIsRequired(entries, OOError::noEntriesSelectedForCitation))) { + return; + } + XTextDocument doc = odoc.get(); + + OOResult ofr = getFrontend(doc); + if (testDialog(title, ofr.asVoidResult())) { + return; + } + OOFrontend fr = ofr.get(); + + OOResult cursor = getUserCursorForTextInsertion(doc, title); + if (testDialog(title, cursor.asVoidResult())) { + return; + } + + if (testDialog(title, checkRangeOverlapsWithCursor(doc, fr))) { + return; + } + + if (testDialog(title, + checkStylesExistInTheDocument(style, doc), + checkIfOpenOfficeIsRecordingChanges(doc))) { + return; + } + + /* + * For sync we need a FunctionalTextViewCursor. + */ + OOResult fcursor = null; + if (syncOptions.isPresent()) { + fcursor = getFunctionalTextViewCursor(doc, title); + if (testDialog(title, fcursor.asVoidResult())) { + return; + } + } + + syncOptions + .map(e -> e.setUpdateBibliography(this.refreshBibliographyDuringSyncWhenCiting)) + .map(e -> e.setAlwaysAddCitedOnPages(this.alwaysAddCitedOnPages)); + + if (syncOptions.isPresent()) { + if (testDialog(databaseIsRequired(syncOptions.get().databases, + OOError::noDataBaseIsOpenForSyncingAfterCitation))) { + return; + } + } + + try { + UnoUndo.enterUndoContext(doc, "Insert citation"); + + EditInsert.insertCitationGroup(doc, + fr, + cursor.get(), + entries, + database, + style, + citationType, + pageInfo); + + if (syncOptions.isPresent()) { + Update.resyncDocument(doc, style, fcursor.get(), syncOptions.get()); + } + + } catch (NoDocumentException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + return; + } catch (DisposedException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + return; + } catch (JabRefException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + return; + } catch (CreationException + | IllegalTypeException + | NoSuchElementException + | NotRemoveableException + | PropertyExistException + | PropertyVetoException + | UnknownPropertyException + | WrappedTargetException ex) { + LOGGER.warn("Could not insert entry", ex); + OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + return; + } finally { + UnoUndo.leaveUndoContext(doc); + } + } + + /** + * GUI action "Merge citations" + * + */ + public void guiActionMergeCitationGroups(List databases, OOBibStyle style) { + + final String title = Localization.lang("Problem combining cite markers"); + + OOResult odoc = getXTextDocument(); + if (testDialog(title, + odoc.asVoidResult(), + styleIsRequired(style), + databaseIsRequired(databases, OOError::noDataBaseIsOpen))) { + return; + } + XTextDocument doc = odoc.get(); + + OOResult fcursor = getFunctionalTextViewCursor(doc, title); + + if (testDialog(title, + fcursor.asVoidResult(), + checkStylesExistInTheDocument(style, doc), + checkIfOpenOfficeIsRecordingChanges(doc))) { + return; + } + + try { + UnoUndo.enterUndoContext(doc, "Merge citations"); + + OOFrontend fr = new OOFrontend(doc); + boolean madeModifications = EditMerge.mergeCitationGroups(doc, fr, style); + if (madeModifications) { + UnoCrossRef.refresh(doc); + Update.SyncOptions syncOptions = new Update.SyncOptions(databases); + Update.resyncDocument(doc, style, fcursor.get(), syncOptions); + } + + } catch (NoDocumentException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (DisposedException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (JabRefException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (CreationException + | IllegalTypeException + | InvalidStateException + | NoSuchElementException + | NotRemoveableException + | PropertyExistException + | PropertyVetoException + | UnknownPropertyException + | WrappedTargetException + | com.sun.star.lang.IllegalArgumentException ex) { + LOGGER.warn("Problem combining cite markers", ex); + OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + } finally { + UnoUndo.leaveUndoContext(doc); + fcursor.get().restore(doc); + } + } // MergeCitationGroups + + /** + * GUI action "Separate citations". + * + * Do the opposite of MergeCitationGroups. + * Combined markers are split, with a space inserted between. + */ + public void guiActionSeparateCitations(List databases, OOBibStyle style) { + + final String title = Localization.lang("Problem during separating cite markers"); + + OOResult odoc = getXTextDocument(); + if (testDialog(title, + odoc.asVoidResult(), + styleIsRequired(style), + databaseIsRequired(databases, OOError::noDataBaseIsOpen))) { + return; + } + + XTextDocument doc = odoc.get(); + OOResult fcursor = getFunctionalTextViewCursor(doc, title); + + if (testDialog(title, + fcursor.asVoidResult(), + checkStylesExistInTheDocument(style, doc), + checkIfOpenOfficeIsRecordingChanges(doc))) { + return; + } + + try { + UnoUndo.enterUndoContext(doc, "Separate citations"); + + OOFrontend fr = new OOFrontend(doc); + boolean madeModifications = EditSeparate.separateCitations(doc, fr, databases, style); + if (madeModifications) { + UnoCrossRef.refresh(doc); + Update.SyncOptions syncOptions = new Update.SyncOptions(databases); + Update.resyncDocument(doc, style, fcursor.get(), syncOptions); + } + + } catch (NoDocumentException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (DisposedException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (JabRefException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (CreationException + | IllegalTypeException + | InvalidStateException + | NoSuchElementException + | NotRemoveableException + | PropertyExistException + | PropertyVetoException + | UnknownPropertyException + | WrappedTargetException + | com.sun.star.lang.IllegalArgumentException ex) { + LOGGER.warn("Problem during separating cite markers", ex); + OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + } finally { + UnoUndo.leaveUndoContext(doc); + fcursor.get().restore(doc); + } + } + + /** + * GUI action for "Export cited" + * + * Does not refresh the bibliography. + * + * @param returnPartialResult If there are some unresolved keys, + * shall we return an otherwise nonempty result, or Optional.empty()? + */ + public Optional exportCitedHelper(List databases, + boolean returnPartialResult) { + + final Optional FAIL = Optional.empty(); + final String title = Localization.lang("Unable to generate new library"); + + OOResult odoc = getXTextDocument(); + if (testDialog(title, + odoc.asVoidResult(), + databaseIsRequired(databases, OOError::noDataBaseIsOpenForExport))) { + return FAIL; + } + XTextDocument doc = odoc.get(); + + try { + + ExportCited.GenerateDatabaseResult result; + try { + UnoUndo.enterUndoContext(doc, "Changes during \"Export cited\""); + result = ExportCited.generateDatabase(doc, databases); + } finally { + // There should be no changes, thus no Undo entry should appear + // in LibreOffice. + UnoUndo.leaveUndoContext(doc); + } + + if (!result.newDatabase.hasEntries()) { + dialogService.showErrorDialogAndWait( + Localization.lang("Unable to generate new library"), + Localization.lang("Your OpenOffice/LibreOffice document references" + + " no citation keys" + + " which could also be found in your current library.")); + return FAIL; + } + + List unresolvedKeys = result.unresolvedKeys; + if (!unresolvedKeys.isEmpty()) { + dialogService.showErrorDialogAndWait( + Localization.lang("Unable to generate new library"), + Localization.lang("Your OpenOffice/LibreOffice document references" + + " at least %0 citation keys" + + " which could not be found in your current library." + + " Some of these are %1.", + String.valueOf(unresolvedKeys.size()), + String.join(", ", unresolvedKeys))); + if (returnPartialResult) { + return Optional.of(result.newDatabase); + } else { + return FAIL; + } + } + return Optional.of(result.newDatabase); + } catch (NoDocumentException ex) { + OOError.from(ex).showErrorDialog(dialogService); + } catch (DisposedException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (NoSuchElementException + | UnknownPropertyException + | WrappedTargetException + | com.sun.star.lang.IllegalArgumentException ex) { + LOGGER.warn("Problem generating new database.", ex); + OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + } + return FAIL; + } + + /** + * GUI action, refreshes citation markers and bibliography. + * + * @param databases Must have at least one. + * @param style Style. + * + */ + public void guiActionUpdateDocument(List databases, OOBibStyle style) { + + final String title = Localization.lang("Unable to synchronize bibliography"); + + try { + + OOResult odoc = getXTextDocument(); + if (testDialog(title, + odoc.asVoidResult(), + styleIsRequired(style))) { + return; + } + + XTextDocument doc = odoc.get(); + + OOResult fcursor = getFunctionalTextViewCursor(doc, title); + + if (testDialog(title, + fcursor.asVoidResult(), + checkStylesExistInTheDocument(style, doc), + checkIfOpenOfficeIsRecordingChanges(doc))) { + return; + } + + OOFrontend fr = new OOFrontend(doc); + if (testDialog(title, checkRangeOverlaps(doc, fr))) { + return; + } + + List unresolvedKeys; + try { + UnoUndo.enterUndoContext(doc, "Refresh bibliography"); + + Update.SyncOptions syncOptions = new Update.SyncOptions(databases); + syncOptions + .setUpdateBibliography(true) + .setAlwaysAddCitedOnPages(this.alwaysAddCitedOnPages); + + unresolvedKeys = Update.synchronizeDocument(doc, fr, style, fcursor.get(), syncOptions); + + } finally { + UnoUndo.leaveUndoContext(doc); + fcursor.get().restore(doc); + } + + if (!unresolvedKeys.isEmpty()) { + String msg = Localization.lang( + "Your OpenOffice/LibreOffice document references the citation key '%0'," + + " which could not be found in your current library.", + unresolvedKeys.get(0)); + dialogService.showErrorDialogAndWait(title, msg); + return; + } + + } catch (JabRefException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (NoDocumentException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (DisposedException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (CreationException + | NoSuchElementException + | PropertyVetoException + | UnknownPropertyException + | WrappedTargetException + | com.sun.star.lang.IllegalArgumentException ex) { + LOGGER.warn("Could not update bibliography", ex); + OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + } + } + +} diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java b/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java new file mode 100644 index 00000000000..03765f8ffd8 --- /dev/null +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java @@ -0,0 +1,259 @@ +package org.jabref.gui.openoffice; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.jabref.gui.DialogService; +import org.jabref.logic.l10n.Localization; +import org.jabref.logic.openoffice.NoDocumentFoundException; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoCast; +import org.jabref.model.openoffice.uno.UnoTextDocument; +import org.jabref.model.openoffice.util.OOResult; + +import com.sun.star.comp.helper.BootstrapException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.container.XEnumeration; +import com.sun.star.container.XEnumerationAccess; +import com.sun.star.frame.XDesktop; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.lang.XComponent; +import com.sun.star.lang.XMultiComponentFactory; +import com.sun.star.text.XTextDocument; +import com.sun.star.uno.XComponentContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Establish connection to a document opened in OpenOffice or LibreOffice. + */ +class OOBibBaseConnect { + + private static final Logger LOGGER = LoggerFactory.getLogger(OOBibBaseConnect.class); + + /* variables */ + private final DialogService dialogService; + private final XDesktop xDesktop; + + /** + * Created when connected to a document. + * + * Cleared (to null) when we discover we lost the connection. + */ + private XTextDocument xTextDocument; + + /* + * Constructor + */ + public OOBibBaseConnect(Path loPath, DialogService dialogService) + throws + BootstrapException, + CreationException { + + this.dialogService = dialogService; + this.xDesktop = simpleBootstrap(loPath); + } + + private XDesktop simpleBootstrap(Path loPath) + throws + CreationException, + BootstrapException { + + // Get the office component context: + XComponentContext context = org.jabref.gui.openoffice.Bootstrap.bootstrap(loPath); + XMultiComponentFactory sem = context.getServiceManager(); + + // Create the desktop, which is the root frame of the + // hierarchy of frames that contain viewable components: + Object desktop; + try { + desktop = sem.createInstanceWithContext("com.sun.star.frame.Desktop", context); + } catch (Exception e) { + throw new CreationException(e.getMessage()); + } + return UnoCast.unoQI(XDesktop.class, desktop); + } + + private static List getTextDocuments(XDesktop desktop) + throws + NoSuchElementException, + WrappedTargetException { + + List result = new ArrayList<>(); + + XEnumerationAccess enumAccess = desktop.getComponents(); + XEnumeration compEnum = enumAccess.createEnumeration(); + + while (compEnum.hasMoreElements()) { + Object next = compEnum.nextElement(); + XComponent comp = UnoCast.unoQI(XComponent.class, next); + XTextDocument doc = UnoCast.unoQI(XTextDocument.class, comp); + if (doc != null) { + result.add(doc); + } + } + return result; + } + + /** + * Run a dialog allowing the user to choose among the documents in `list`. + * + * @return Null if no document was selected. Otherwise the + * document selected. + * + */ + private static XTextDocument selectDocumentDialog(List list, + DialogService dialogService) { + + class DocumentTitleViewModel { + + private final XTextDocument xTextDocument; + private final String description; + + public DocumentTitleViewModel(XTextDocument xTextDocument) { + this.xTextDocument = xTextDocument; + this.description = UnoTextDocument.getFrameTitle(xTextDocument).orElse(""); + } + + public XTextDocument getXtextDocument() { + return xTextDocument; + } + + @Override + public String toString() { + return description; + } + } + + List viewModel = (list.stream() + .map(DocumentTitleViewModel::new) + .collect(Collectors.toList())); + + // This whole method is part of a background task when + // auto-detecting instances, so we need to show dialog in FX + // thread + Optional selectedDocument = + (dialogService + .showChoiceDialogAndWait(Localization.lang("Select document"), + Localization.lang("Found documents:"), + Localization.lang("Use selected document"), + viewModel)); + + return (selectedDocument + .map(DocumentTitleViewModel::getXtextDocument) + .orElse(null)); + } + + /** + * Choose a document to work with. + * + * Assumes we have already connected to LibreOffice or OpenOffice. + * + * If there is a single document to choose from, selects that. + * If there are more than one, shows selection dialog. + * If there are none, throws NoDocumentFoundException + * + * After successful selection connects to the selected document + * and extracts some frequently used parts (starting points for + * managing its content). + * + * Finally initializes this.xTextDocument with the selected + * document and parts extracted. + * + */ + public void selectDocument(boolean autoSelectForSingle) + throws + NoDocumentFoundException, + NoSuchElementException, + WrappedTargetException { + + XTextDocument selected; + List textDocumentList = getTextDocuments(this.xDesktop); + if (textDocumentList.isEmpty()) { + throw new NoDocumentFoundException("No Writer documents found"); + } else if (textDocumentList.size() == 1 && autoSelectForSingle) { + selected = textDocumentList.get(0); // Get the only one + } else { // Bring up a dialog + selected = OOBibBaseConnect.selectDocumentDialog(textDocumentList, + this.dialogService); + } + + if (selected == null) { + return; + } + + this.xTextDocument = selected; + } + + /** + * Mark the current document as missing. + * + */ + private void forgetDocument() { + this.xTextDocument = null; + } + + /** + * A simple test for document availability. + * + * See also `isDocumentConnectionMissing` for a test + * actually attempting to use teh connection. + * + */ + public boolean isConnectedToDocument() { + return this.xTextDocument != null; + } + + /** + * @return true if we are connected to a document + */ + public boolean isDocumentConnectionMissing() { + XTextDocument doc = this.xTextDocument; + + if (doc == null) { + return true; + } + + if (UnoTextDocument.isDocumentConnectionMissing(doc)) { + forgetDocument(); + return true; + } + return false; + } + + /** + * Either return a valid XTextDocument or throw + * NoDocumentException. + */ + public XTextDocument getXTextDocumentOrThrow() + throws + NoDocumentException { + if (isDocumentConnectionMissing()) { + throw new NoDocumentException("Not connected to document"); + } + return this.xTextDocument; + } + + public OOResult getXTextDocument() { + if (isDocumentConnectionMissing()) { + return OOResult.error(OOError.from(new NoDocumentException())); + } + return OOResult.ok(this.xTextDocument); + } + + /** + * The title of the current document, or Optional.empty() + */ + public Optional getCurrentDocumentTitle() { + if (isDocumentConnectionMissing()) { + return Optional.empty(); + } else { + return UnoTextDocument.getFrameTitle(this.xTextDocument); + } + } + +} // end of OOBibBaseConnect diff --git a/src/main/java/org/jabref/gui/openoffice/OOError.java b/src/main/java/org/jabref/gui/openoffice/OOError.java new file mode 100644 index 00000000000..44e70b3e975 --- /dev/null +++ b/src/main/java/org/jabref/gui/openoffice/OOError.java @@ -0,0 +1,141 @@ +package org.jabref.gui.openoffice; + +import org.jabref.gui.DialogService; +import org.jabref.logic.JabRefException; +import org.jabref.logic.l10n.Localization; +import org.jabref.logic.openoffice.NoDocumentFoundException; +import org.jabref.model.openoffice.uno.NoDocumentException; + +import com.sun.star.lang.DisposedException; + +class OOError extends JabRefException { + + private String localizedTitle; + + public OOError(String title, String localizedMessage) { + super(localizedMessage, localizedMessage); + this.localizedTitle = title; + } + + public OOError(String title, String localizedMessage, Throwable cause) { + super(localizedMessage, localizedMessage, cause); + this.localizedTitle = title; + } + + public String getTitle() { + return localizedTitle; + } + + public OOError setTitle(String title) { + localizedTitle = title; + return this; + } + + public void showErrorDialog(DialogService dialogService) { + dialogService.showErrorDialogAndWait(getTitle(), getLocalizedMessage()); + } + + /* + * Conversions from exception caught + */ + + public static OOError from(JabRefException ex) { + return new OOError( + Localization.lang("JabRefException"), + ex.getLocalizedMessage(), + ex); + } + + // For DisposedException + public static OOError from(DisposedException ex) { + return new OOError( + Localization.lang("Connection lost"), + Localization.lang("Connection to OpenOffice/LibreOffice has been lost." + + " Please make sure OpenOffice/LibreOffice is running," + + " and try to reconnect."), + ex); + } + + // For NoDocumentException + public static OOError from(NoDocumentException ex) { + return new OOError( + Localization.lang("Not connected to document"), + Localization.lang("Not connected to any Writer document." + + " Please make sure a document is open," + + " and use the 'Select Writer document' button" + + " to connect to it."), + ex); + } + + // For NoDocumentFoundException + public static OOError from(NoDocumentFoundException ex) { + return new OOError( + Localization.lang("No Writer documents found"), + Localization.lang("Could not connect to any Writer document." + + " Please make sure a document is open" + + " before using the 'Select Writer document' button" + + " to connect to it."), + ex); + } + + public static OOError fromMisc(Exception ex) { + return new OOError( + "Exception", + ex.getMessage(), + ex); + } + + /* + * Messages for error dialog. These are not thrown. + */ + + // noDataBaseIsOpenForCiting + public static OOError noDataBaseIsOpenForCiting() { + return new OOError( + Localization.lang("No database"), + Localization.lang("No bibliography database is open for citation.") + + "\n" + + Localization.lang("Open one before citing.")); + } + + public static OOError noDataBaseIsOpenForSyncingAfterCitation() { + return new OOError( + Localization.lang("No database"), + Localization.lang("No database is open for updating citation markers after citing.") + + "\n" + + Localization.lang("Open one before citing.")); + } + + // noDataBaseIsOpenForExport + public static OOError noDataBaseIsOpenForExport() { + return new OOError( + Localization.lang("No database is open"), + Localization.lang("We need a database to export from. Open one.")); + } + + // noDataBaseIsOpenForExport + public static OOError noDataBaseIsOpen() { + return new OOError( + Localization.lang("No database is open"), + Localization.lang("This operation requires a bibliography database.")); + } + + // noValidStyleSelected + public static OOError noValidStyleSelected() { + return new OOError(Localization.lang("No valid style file defined"), + Localization.lang("No bibliography style is selected for citation.") + + "\n" + + Localization.lang("Select one before citing.") + + "\n" + + Localization.lang("You must select either a valid style file," + + " or use one of the default styles.")); + } + + // noEntriesSelectedForCitation + public static OOError noEntriesSelectedForCitation() { + return new OOError(Localization.lang("No entries selected for citation"), + Localization.lang("No bibliography entries are selected for citation.") + + "\n" + + Localization.lang("Select some before citing.")); + } +} diff --git a/src/main/java/org/jabref/logic/openoffice/NoDocumentFoundException.java b/src/main/java/org/jabref/logic/openoffice/NoDocumentFoundException.java new file mode 100644 index 00000000000..2759a9931aa --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/NoDocumentFoundException.java @@ -0,0 +1,12 @@ +package org.jabref.logic.openoffice; + +public class NoDocumentFoundException extends Exception { + + public NoDocumentFoundException(String message) { + super(message); + } + + public NoDocumentFoundException() { + super("No Writer documents found"); + } +} diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index dc2fd8df58a..bf4c349bb76 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -505,6 +505,10 @@ Moved\ group\ "%0".=Moved group "%0". Mr.\ DLib\ Privacy\ settings=Mr. DLib Privacy settings +No\ database\ is\ open=No database is open + +We\ need\ a\ database\ to\ export\ from.\ Open\ one.=We need a database to export from. Open one. + No\ recommendations\ received\ from\ Mr.\ DLib\ for\ this\ entry.=No recommendations received from Mr. DLib for this entry. Error\ while\ fetching\ recommendations\ from\ Mr.DLib.=Error while fetching recommendations from Mr.DLib. @@ -1015,6 +1019,7 @@ Cite\ special=Cite special Extra\ information\ (e.g.\ page\ number)=Extra information (e.g. page number) Manage\ citations=Manage citations Problem\ modifying\ citation=Problem modifying citation +Problem\ collecting\ citations=Problem collecting citations Citation=Citation Connecting...=Connecting... Could\ not\ resolve\ BibTeX\ entry\ for\ citation\ marker\ '%0'.=Could not resolve BibTeX entry for citation marker '%0'. @@ -1029,10 +1034,23 @@ Select\ Writer\ document=Select Writer document Sync\ OpenOffice/LibreOffice\ bibliography=Sync OpenOffice/LibreOffice bibliography Select\ which\ open\ Writer\ document\ to\ work\ on=Select which open Writer document to work on Connected\ to\ document=Connected to document + +Could\ not\ connect\ to\ any\ Writer\ document.\ Please\ make\ sure\ a\ document\ is\ open\ before\ using\ the\ 'Select\ Writer\ document'\ button\ to\ connect\ to\ it.=Could not connect to any Writer document. Please make sure a document is open before using the 'Select Writer document' button to connect to it. + +No\ Writer\ documents\ found=No Writer documents found + Insert\ a\ citation\ without\ text\ (the\ entry\ will\ appear\ in\ the\ reference\ list)=Insert a citation without text (the entry will appear in the reference list) Cite\ selected\ entries\ with\ extra\ information=Cite selected entries with extra information Ensure\ that\ the\ bibliography\ is\ up-to-date=Ensure that the bibliography is up-to-date + Your\ OpenOffice/LibreOffice\ document\ references\ the\ citation\ key\ '%0',\ which\ could\ not\ be\ found\ in\ your\ current\ library.=Your OpenOffice/LibreOffice document references the citation key '%0', which could not be found in your current library. + +This\ operation\ requires\ a\ bibliography\ database.=This operation requires a bibliography database. + +Your\ OpenOffice/LibreOffice\ document\ references\ at\ least\ %0\ citation\ keys\ which\ could\ not\ be\ found\ in\ your\ current\ library.\ Some\ of\ these\ are\ %1.=Your OpenOffice/LibreOffice document references at least %0 citation keys which could not be found in your current library. Some of these are %1. + +Your\ OpenOffice/LibreOffice\ document\ references\ no\ citation\ keys\ which\ could\ also\ be\ found\ in\ your\ current\ library.=Your OpenOffice/LibreOffice document references no citation keys which could also be found in your current library. + Unable\ to\ synchronize\ bibliography=Unable to synchronize bibliography Combine\ pairs\ of\ citations\ that\ are\ separated\ by\ spaces\ only=Combine pairs of citations that are separated by spaces only Autodetection\ failed=Autodetection failed @@ -1040,6 +1058,12 @@ Please\ wait...=Please wait... Connection\ lost=Connection lost The\ paragraph\ format\ is\ controlled\ by\ the\ property\ 'ReferenceParagraphFormat'\ or\ 'ReferenceHeaderParagraphFormat'\ in\ the\ style\ file.=The paragraph format is controlled by the property 'ReferenceParagraphFormat' or 'ReferenceHeaderParagraphFormat' in the style file. The\ character\ format\ is\ controlled\ by\ the\ citation\ property\ 'CitationCharacterFormat'\ in\ the\ style\ file.=The character format is controlled by the citation property 'CitationCharacterFormat' in the style file. + +Not\ connected\ to\ document=Not connected to document +Problem\ combining\ cite\ markers=Problem combining cite markers + +Problem\ during\ separating\ cite\ markers=Problem during separating cite markers + Automatically\ sync\ bibliography\ when\ inserting\ citations=Automatically sync bibliography when inserting citations Look\ up\ BibTeX\ entries\ in\ the\ active\ tab\ only=Look up BibTeX entries in the active tab only Look\ up\ BibTeX\ entries\ in\ all\ open\ libraries=Look up BibTeX entries in all open libraries @@ -1134,7 +1158,9 @@ Toggle\ quality\ assured=Toggle quality assured Toggle\ print\ status=Toggle print status Update\ keywords=Update keywords Write\ values\ of\ special\ fields\ as\ separate\ fields\ to\ BibTeX=Write values of special fields as separate fields to BibTeX +Problem\ connecting=Problem connecting Connection\ to\ OpenOffice/LibreOffice\ has\ been\ lost.\ Please\ make\ sure\ OpenOffice/LibreOffice\ is\ running,\ and\ try\ to\ reconnect.=Connection to OpenOffice/LibreOffice has been lost. Please make sure OpenOffice/LibreOffice is running, and try to reconnect. + JabRef\ will\ send\ at\ least\ one\ request\ per\ entry\ to\ a\ publisher.=JabRef will send at least one request per entry to a publisher. Correct\ the\ entry,\ and\ reopen\ editor\ to\ display/edit\ source.=Correct the entry, and reopen editor to display/edit source. Could\ not\ connect\ to\ running\ OpenOffice/LibreOffice.=Could not connect to running OpenOffice/LibreOffice. @@ -1529,6 +1555,23 @@ Custom=Custom Export\ cited=Export cited Unable\ to\ generate\ new\ library=Unable to generate new library +Could\ not\ get\ the\ cursor.=Could not get the cursor. +The\ cursor\ is\ in\ protected\ area.=The cursor is in protected area. +JabRefException=JabRefException +No\ bibliography\ database\ is\ open\ for\ citation.=No bibliography database is open for citation. + +No\ database\ is\ open\ for\ updating\ citation\ markers\ after\ citing.=No database is open for updating citation markers after citing. + +No\ bibliography\ entries\ are\ selected\ for\ citation.=No bibliography entries are selected for citation. +No\ bibliography\ style\ is\ selected\ for\ citation.=No bibliography style is selected for citation. +No\ database=No database + +No\ entries\ selected\ for\ citation=No entries selected for citation +Open\ one\ before\ citing.=Open one before citing. + +Select\ one\ before\ citing.=Select one before citing. +Select\ some\ before\ citing.=Select some before citing. + Found\ identical\ ranges=Found identical ranges Found\ overlapping\ ranges=Found overlapping ranges Found\ touching\ ranges=Found touching ranges @@ -2300,6 +2343,35 @@ Customization=Customization Use\ custom\ DOI\ base\ URI\ for\ article\ access=Use custom DOI base URI for article access Cited\ on\ pages=Cited on pages +Please\ move\ the\ cursor\ into\ the\ document\ text.=Please\ move\ the\ cursor\ into\ the\ document\ text. +To\ get\ the\ visual\ positions\ of\ your\ citations\ I\ need\ to\ move\ the\ cursor\ around,\ but\ could\ not\ get\ it.=To\ get\ the\ visual\ positions\ of\ your\ citations\ I\ need\ to\ move\ the\ cursor\ around,\ but\ could\ not\ get\ it. + +I\ cannot\ insert\ to\ the\ cursors\ current\ location.=I\ cannot\ insert\ to\ the\ cursors\ current\ location. + +Please\ move\ the\ cursor\ to\ the\ location\ for\ the\ new\ citation.=Please\ move\ the\ cursor\ to\ the\ location\ for\ the\ new\ citation. + +Please\ create\ it\ in\ the\ document\ or\ change\ in\ the\ file\:=Please create it in the document or change in the file: + +Please\ use\ the\ latter\ in\ the\ style\ file\ below\ to\ avoid\ localization\ problems.=Please use the latter in the style file below to avoid localization problems. + +The\ %0\ character\ style\ '%1'\ is\ a\ display\ name\ for\ '%2'.=The %0 character style '%1' is a display name for '%2'. + +The\ %0\ character\ style\ '%1'\ is\ missing\ from\ the\ document=The %0 character style '%1' is missing from the document + +The\ %0\ paragraph\ style\ '%1'\ is\ a\ display\ name\ for\ '%2'.=The %0 paragraph style '%1' is a display name for '%2'. + +The\ %0\ paragraph\ style\ '%1'\ is\ missing\ from\ the\ document=The %0 paragraph style '%1' is missing from the document + +Error\ while\ checking\ if\ Writer\ is\ recording\ changes\ or\ has\ recorded\ changes.=Error while checking if Writer is recording changes or has recorded changes. + +Cannot\ work\ with\ [Edit]/[Track\ Changes]/[Record]\ turned\ on.=Cannot work with [Edit]/[Track Changes]/[Record] turned on. + +Changes\ by\ JabRef\ could\ result\ in\ unexpected\ interactions\ with\ recorded\ changes.=Changes by JabRef could result in unexpected interactions with recorded changes. + +Recording\ and/or\ Recorded\ changes=Recording and/or Recorded changes + +Use\ [Edit]/[Track\ Changes]/[Manage]\ to\ resolve\ them\ first.=Use [Edit]/[Track Changes]/[Manage] to resolve them first. + Unable\ to\ find\ valid\ certification\ path\ to\ requested\ target(%0),\ download\ anyway?=Unable to find valid certification path to requested target(%0), download anyway? Download\ operation\ canceled.=Download operation canceled. From b660d3200d1efc612f1e88e9e55a1ebc6a692e05 Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 12:33:23 +0200 Subject: [PATCH 020/103] integrate --- .../openoffice/ManageCitationsDialogView.java | 16 +- .../ManageCitationsDialogViewModel.java | 45 +-- .../gui/openoffice/OpenOfficePanel.java | 355 ++++++++---------- src/main/resources/l10n/JabRef_en.properties | 12 +- 4 files changed, 178 insertions(+), 250 deletions(-) diff --git a/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogView.java b/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogView.java index a312a4ef375..872d1f8adc0 100644 --- a/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogView.java +++ b/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogView.java @@ -19,16 +19,13 @@ import org.jabref.model.strings.StringUtil; import com.airhacks.afterburner.views.ViewLoader; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; -import com.sun.star.lang.WrappedTargetException; public class ManageCitationsDialogView extends BaseDialog { private static final String HTML_BOLD_END_TAG = ""; private static final String HTML_BOLD_START_TAG = ""; - private final OOBibBase ooBase; + private final OOBibBase2 ooBase; @FXML private TableView citationsTableView; @FXML private TableColumn citation; @@ -38,7 +35,7 @@ public class ManageCitationsDialogView extends BaseDialog { private ManageCitationsDialogViewModel viewModel; - public ManageCitationsDialogView(OOBibBase ooBase) { + public ManageCitationsDialogView(OOBibBase2 ooBase) { this.ooBase = ooBase; ViewLoader.view(this) @@ -56,7 +53,7 @@ public ManageCitationsDialogView(OOBibBase ooBase) { } @FXML - private void initialize() throws NoSuchElementException, WrappedTargetException, UnknownPropertyException { + private void initialize() { viewModel = new ManageCitationsDialogViewModel(ooBase, dialogService); @@ -90,4 +87,11 @@ private Node getText(String citationContext) { FlowPane flow = new FlowPane(startText, inBetweenText, endText); return flow; } + + public boolean isOkToShowThisDialog() { + if (viewModel == null || viewModel.failedToGetCitationEntries) { + return false; + } + return true; + } } diff --git a/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java b/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java index 40cee65036f..b854a445fa9 100644 --- a/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java +++ b/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java @@ -9,40 +9,26 @@ import javafx.collections.FXCollections; import org.jabref.gui.DialogService; -import org.jabref.logic.l10n.Localization; import org.jabref.model.openoffice.CitationEntry; -import com.sun.star.beans.IllegalTypeException; -import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; -import com.sun.star.container.XNameAccess; -import com.sun.star.lang.IllegalArgumentException; -import com.sun.star.lang.WrappedTargetException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class ManageCitationsDialogViewModel { - private static final Logger LOGGER = LoggerFactory.getLogger(ManageCitationsDialogViewModel.class); - + public final boolean failedToGetCitationEntries; private final ListProperty citations = new SimpleListProperty<>(FXCollections.observableArrayList()); - private final OOBibBase ooBase; + private final OOBibBase2 ooBase; private final DialogService dialogService; - public ManageCitationsDialogViewModel(OOBibBase ooBase, DialogService dialogService) throws NoSuchElementException, WrappedTargetException, UnknownPropertyException { + public ManageCitationsDialogViewModel(OOBibBase2 ooBase, DialogService dialogService) { this.ooBase = ooBase; this.dialogService = dialogService; - XNameAccess nameAccess = ooBase.getReferenceMarks(); - List names = ooBase.getJabRefReferenceMarks(nameAccess); - for (String name : names) { - - CitationEntry entry = new CitationEntry(name, - ooBase.getCitationContext(nameAccess, name, 30, 30, true), - ooBase.getCustomProperty(name)); + Optional> citationEntries = ooBase.guiActionGetCitationEntries(); + this.failedToGetCitationEntries = citationEntries.isEmpty(); + if (citationEntries.isEmpty()) { + return; + } + for (CitationEntry entry : citationEntries.get()) { CitationEntryViewModel itemViewModelEntry = new CitationEntryViewModel(entry); citations.add(itemViewModelEntry); } @@ -50,18 +36,7 @@ public ManageCitationsDialogViewModel(OOBibBase ooBase, DialogService dialogServ public void storeSettings() { List ciationEntries = citations.stream().map(CitationEntryViewModel::toCitationEntry).collect(Collectors.toList()); - try { - for (CitationEntry entry : ciationEntries) { - Optional pageInfo = entry.getPageInfo(); - if (pageInfo.isPresent()) { - ooBase.setCustomProperty(entry.getRefMarkName(), pageInfo.get()); - } - } - } catch (UnknownPropertyException | NotRemoveableException | PropertyExistException | IllegalTypeException | - IllegalArgumentException ex) { - LOGGER.warn("Problem modifying citation", ex); - dialogService.showErrorDialogAndWait(Localization.lang("Problem modifying citation"), ex); - } + ooBase.guiActionApplyCitationEntries(ciationEntries); } public ListProperty citationsProperty() { diff --git a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java index 367855a4b37..8b8f398c1ff 100644 --- a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java +++ b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java @@ -1,6 +1,5 @@ package org.jabref.gui.openoffice; -import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.nio.file.Path; @@ -46,24 +45,17 @@ import org.jabref.logic.l10n.Localization; import org.jabref.logic.openoffice.OpenOfficeFileSearch; import org.jabref.logic.openoffice.OpenOfficePreferences; -import org.jabref.logic.openoffice.UndefinedParagraphFormatException; +import org.jabref.logic.openoffice.action.Update; import org.jabref.logic.openoffice.style.OOBibStyle; import org.jabref.logic.openoffice.style.StyleLoader; import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; +import org.jabref.model.openoffice.style.CitationType; import org.jabref.model.openoffice.uno.CreationException; -import org.jabref.model.openoffice.uno.NoDocumentException; import org.jabref.preferences.PreferencesService; -import com.sun.star.beans.IllegalTypeException; -import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; -import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; import com.sun.star.comp.helper.BootstrapException; -import com.sun.star.container.NoSuchElementException; -import com.sun.star.lang.WrappedTargetException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -97,7 +89,7 @@ public class OpenOfficePanel { private final TaskExecutor taskExecutor; private final StyleLoader loader; private OpenOfficePreferences ooPrefs; - private OOBibBase ooBase; + private OOBibBase2 ooBase; private OOBibStyle style; public OpenOfficePanel(JabRefFrame frame, PreferencesService preferencesService, OpenOfficePreferences ooPrefs, KeyBindingRepository keyBindingRepository) { @@ -142,23 +134,40 @@ public Node getContent() { return vbox; } + /* Note: the style may still be null on return. + * + * Return true if failed. In this case the dialog is already shown. + */ + private boolean getOrUpdateTheStyle(String title) { + final boolean FAIL = true; + final boolean PASS = false; + + if (style == null) { + style = loader.getUsedStyle(); + } else { + try { + style.ensureUpToDate(); + } catch (IOException ex) { + LOGGER.warn("Unable to reload style file '" + style.getPath() + "'", ex); + String msg = (Localization.lang("Unable to reload style file") + + "'" + style.getPath() + "'" + + "\n" + ex.getMessage()); + new OOError(title, msg, ex).showErrorDialog(dialogService); + return FAIL; + } + } + return PASS; + } + private void initPanel() { connect.setOnAction(e -> connectAutomatically()); manualConnect.setOnAction(e -> connectManually()); selectDocument.setTooltip(new Tooltip(Localization.lang("Select which open Writer document to work on"))); - selectDocument.setOnAction(e -> { - try { - ooBase.selectDocument(); - dialogService.notify(Localization.lang("Connected to document") + ": " - + ooBase.getCurrentDocumentTitle().orElse("")); - } catch (WrappedTargetException | IndexOutOfBoundsException | - NoSuchElementException | NoDocumentException ex) { - LOGGER.warn("Problem connecting", ex); - dialogService.showErrorDialogAndWait(ex); - } + selectDocument.setOnAction(e -> { + ooBase.guiActionSelectDocument(false); }); setStyleFile.setMaxWidth(Double.MAX_VALUE); @@ -176,85 +185,39 @@ private void initPanel() { }); pushEntries.setTooltip(new Tooltip(Localization.lang("Cite selected entries between parenthesis"))); - pushEntries.setOnAction(e -> pushEntries(true, true, false)); + pushEntries.setOnAction(e -> pushEntries(CitationType.AUTHORYEAR_PAR, false)); pushEntries.setMaxWidth(Double.MAX_VALUE); pushEntriesInt.setTooltip(new Tooltip(Localization.lang("Cite selected entries with in-text citation"))); - pushEntriesInt.setOnAction(e -> pushEntries(false, true, false)); + pushEntriesInt.setOnAction(e -> pushEntries(CitationType.AUTHORYEAR_INTEXT, false)); pushEntriesInt.setMaxWidth(Double.MAX_VALUE); pushEntriesEmpty.setTooltip(new Tooltip(Localization.lang("Insert a citation without text (the entry will appear in the reference list)"))); - pushEntriesEmpty.setOnAction(e -> pushEntries(false, false, false)); + pushEntriesEmpty.setOnAction(e -> pushEntries(CitationType.INVISIBLE_CIT, false)); pushEntriesEmpty.setMaxWidth(Double.MAX_VALUE); pushEntriesAdvanced.setTooltip(new Tooltip(Localization.lang("Cite selected entries with extra information"))); - pushEntriesAdvanced.setOnAction(e -> pushEntries(false, true, true)); + pushEntriesAdvanced.setOnAction(e -> pushEntries(CitationType.AUTHORYEAR_INTEXT, true)); pushEntriesAdvanced.setMaxWidth(Double.MAX_VALUE); update.setTooltip(new Tooltip(Localization.lang("Ensure that the bibliography is up-to-date"))); update.setOnAction(event -> { - try { - if (style == null) { - style = loader.getUsedStyle(); - } else { - style.ensureUpToDate(); - } - - ooBase.updateSortedReferenceMarks(); - - List databases = getBaseList(); - List unresolvedKeys = ooBase.refreshCiteMarkers(databases, style); - ooBase.rebuildBibTextSection(databases, style); - if (!unresolvedKeys.isEmpty()) { - dialogService.showErrorDialogAndWait(Localization.lang("Unable to synchronize bibliography"), - Localization.lang("Your OpenOffice/LibreOffice document references the citation key '%0', which could not be found in your current library.", - unresolvedKeys.get(0))); - } - } catch (UndefinedCharacterFormatException ex) { - reportUndefinedCharacterFormat(ex); - } catch (UndefinedParagraphFormatException ex) { - reportUndefinedParagraphFormat(ex); - } catch (ConnectionLostException ex) { - showConnectionLostErrorMessage(); - } catch (IOException ex) { - LOGGER.warn("Problem with style file", ex); - dialogService.showErrorDialogAndWait(Localization.lang("No valid style file defined"), - Localization.lang("You must select either a valid style file, or use one of the default styles.")); - } catch (BibEntryNotFoundException ex) { - LOGGER.debug("BibEntry not found", ex); - dialogService.showErrorDialogAndWait(Localization.lang("Unable to synchronize bibliography"), Localization.lang( - "Your OpenOffice/LibreOffice document references the citation key '%0', which could not be found in your current library.", - ex.getCitationKey())); - } catch (com.sun.star.lang.IllegalArgumentException | PropertyVetoException | UnknownPropertyException | WrappedTargetException | NoSuchElementException | - CreationException ex) { - LOGGER.warn("Could not update bibliography", ex); + String title = Localization.lang("Could not update bibliography"); + if (getOrUpdateTheStyle(title)) { + return; } + List databases = getBaseList(); + ooBase.guiActionUpdateDocument(databases, style); }); merge.setMaxWidth(Double.MAX_VALUE); merge.setTooltip(new Tooltip(Localization.lang("Combine pairs of citations that are separated by spaces only"))); merge.setOnAction(e -> { - try { - ooBase.combineCiteMarkers(getBaseList(), style); - } catch (UndefinedCharacterFormatException ex) { - reportUndefinedCharacterFormat(ex); - } catch (com.sun.star.lang.IllegalArgumentException | UnknownPropertyException | PropertyVetoException | - CreationException | NoSuchElementException | WrappedTargetException | IOException | - BibEntryNotFoundException ex) { - LOGGER.warn("Problem combining cite markers", ex); - } + ooBase.guiActionMergeCitationGroups(getBaseList(), style); }); unmerge.setMaxWidth(Double.MAX_VALUE); unmerge.setTooltip(new Tooltip(Localization.lang("Separate merged citations"))); unmerge.setOnAction(e -> { - try { - ooBase.unCombineCiteMarkers(getBaseList(), style); - } catch (UndefinedCharacterFormatException ex) { - reportUndefinedCharacterFormat(ex); - } catch (com.sun.star.lang.IllegalArgumentException | UnknownPropertyException | PropertyVetoException | - CreationException | NoSuchElementException | WrappedTargetException | IOException | - BibEntryNotFoundException ex) { - LOGGER.warn("Problem uncombining cite markers", ex); - } + ooBase.guiActionSeparateCitations(getBaseList(), style); }); ContextMenu settingsMenu = createSettingsPopup(); @@ -263,22 +226,16 @@ private void initPanel() { settingsB.setOnAction(e -> settingsMenu.show(settingsB, Side.BOTTOM, 0, 0)); manageCitations.setMaxWidth(Double.MAX_VALUE); manageCitations.setOnAction(e -> { - dialogService.showCustomDialogAndWait(new ManageCitationsDialogView(ooBase)); + ManageCitationsDialogView dialog = new ManageCitationsDialogView(ooBase); + if (dialog.isOkToShowThisDialog()) { + dialogService.showCustomDialogAndWait(dialog); + } }); exportCitations.setMaxWidth(Double.MAX_VALUE); exportCitations.setOnAction(event -> exportEntries()); - selectDocument.setDisable(true); - pushEntries.setDisable(true); - pushEntriesInt.setDisable(true); - pushEntriesEmpty.setDisable(true); - pushEntriesAdvanced.setDisable(true); - update.setDisable(true); - merge.setDisable(true); - unmerge.setDisable(true); - manageCitations.setDisable(true); - exportCitations.setDisable(true); + updateButtonAvailability(); HBox hbox = new HBox(); hbox.getChildren().addAll(connect, manualConnect, selectDocument, update, help); @@ -298,36 +255,13 @@ private void initPanel() { } private void exportEntries() { - try { - if (style == null) { - style = loader.getUsedStyle(); - } else { - style.ensureUpToDate(); - } - - ooBase.updateSortedReferenceMarks(); - - List databases = getBaseList(); - List unresolvedKeys = ooBase.refreshCiteMarkers(databases, style); - BibDatabase newDatabase = ooBase.generateDatabase(databases); - if (!unresolvedKeys.isEmpty()) { - - dialogService.showErrorDialogAndWait(Localization.lang("Unable to generate new library"), - Localization.lang("Your OpenOffice/LibreOffice document references the citation key '%0', which could not be found in your current library.", - unresolvedKeys.get(0))); - } - - BibDatabaseContext databaseContext = new BibDatabaseContext(newDatabase); + final String title = Localization.lang("Problem generating new database."); + List databases = getBaseList(); + boolean returnPartialResult = false; + Optional newDatabase = ooBase.exportCitedHelper(databases, returnPartialResult); + if (newDatabase.isPresent()) { + BibDatabaseContext databaseContext = new BibDatabaseContext(newDatabase.get()); this.frame.addTab(databaseContext, true); - } catch (BibEntryNotFoundException ex) { - LOGGER.debug("BibEntry not found", ex); - dialogService.showErrorDialogAndWait(Localization.lang("Unable to synchronize bibliography"), - Localization.lang("Your OpenOffice/LibreOffice document references the citation key '%0', which could not be found in your current library.", - ex.getCitationKey())); - } catch (com.sun.star.lang.IllegalArgumentException | UnknownPropertyException | PropertyVetoException | - UndefinedCharacterFormatException | NoSuchElementException | WrappedTargetException | IOException | - CreationException e) { - LOGGER.warn("Problem generating new database.", e); } } @@ -338,7 +272,10 @@ private List getBaseList() { databases.add(libraryTab.getDatabase()); } } else { - databases.add(frame.getCurrentLibraryTab().getDatabase()); + LibraryTab libraryTab = frame.getCurrentLibraryTab(); + if (libraryTab != null) { + databases.add(libraryTab.getDatabase()); + } } return databases; @@ -405,13 +342,39 @@ private void connectManually() { } } + private void updateButtonAvailability() { + boolean isConnected = (ooBase != null); + boolean isConnectedToDocument = isConnected && !ooBase.isDocumentConnectionMissing(); + + // For these, we need to watch something + boolean hasStyle = true; // (style != null); + boolean hasDatabase = true; // !getBaseList().isEmpty(); + boolean hasSelectedBibEntry = true; + + selectDocument.setDisable(!(isConnected)); + pushEntries.setDisable(!(isConnectedToDocument && hasStyle && hasDatabase)); + + boolean canCite = isConnectedToDocument && hasStyle && hasSelectedBibEntry; + pushEntriesInt.setDisable(!canCite); + pushEntriesEmpty.setDisable(!canCite); + pushEntriesAdvanced.setDisable(!canCite); + + boolean canRefreshDocument = isConnectedToDocument && hasStyle; + update.setDisable(!canRefreshDocument); + merge.setDisable(!canRefreshDocument); + unmerge.setDisable(!canRefreshDocument); + manageCitations.setDisable(!canRefreshDocument); + + exportCitations.setDisable(!(isConnectedToDocument && hasDatabase)); + } + private void connect() { ooPrefs = preferencesService.getOpenOfficePreferences(); - Task connectTask = new Task<>() { + Task connectTask = new Task<>() { @Override - protected OOBibBase call() throws Exception { + protected OOBibBase2 call() throws Exception { updateProgress(ProgressBar.INDETERMINATE_PROGRESS, ProgressBar.INDETERMINATE_PROGRESS); var path = Path.of(ooPrefs.getExecutablePath()); @@ -422,29 +385,12 @@ protected OOBibBase call() throws Exception { connectTask.setOnSucceeded(value -> { ooBase = connectTask.getValue(); - try { - ooBase.selectDocument(); - } catch (NoSuchElementException | WrappedTargetException | NoDocumentException ex) { - dialogService.showErrorDialogAndWait(Localization.lang("Error connecting to Writer document"), Localization.lang("You need to open Writer with a document before connecting"), ex); - LOGGER.error("Error connecting to writer document", ex); - } - - if (ooBase.isConnectedToDocument()) { - dialogService.notify(Localization.lang("Connected to document") + ": " + ooBase.getCurrentDocumentTitle().orElse("")); - } + ooBase.guiActionSelectDocument(true); // Enable actions that depend on Connect: - selectDocument.setDisable(false); - pushEntries.setDisable(false); - pushEntriesInt.setDisable(false); - pushEntriesEmpty.setDisable(false); - pushEntriesAdvanced.setDisable(false); - update.setDisable(false); - merge.setDisable(false); - unmerge.setDisable(false); - manageCitations.setDisable(false); - exportCitations.setDisable(false); + updateButtonAvailability(); }); + connectTask.setOnFailed(value -> { Throwable ex = connectTask.getException(); if (ex instanceof UnsatisfiedLinkError) { @@ -470,20 +416,63 @@ protected OOBibBase call() throws Exception { taskExecutor.execute(connectTask); } - private OOBibBase createBibBase(Path loPath) throws IOException, InvocationTargetException, IllegalAccessException, + private OOBibBase2 createBibBase(Path loPath) throws IOException, InvocationTargetException, IllegalAccessException, BootstrapException, CreationException, ClassNotFoundException { - return new OOBibBase(loPath, true, dialogService); + return new OOBibBase2(loPath, dialogService); } - private void pushEntries(boolean inParenthesisIn, boolean withText, boolean addPageInfo) { - if (!ooBase.isConnectedToDocument()) { - dialogService.showErrorDialogAndWait(Localization.lang("Error pushing entries"), Localization.lang("Not connected to any Writer document. Please" + " make sure a document is open, and use the 'Select Writer document' button to connect to it.")); + /** + * Given the withText and inParenthesis options, + * return the corresponding citationType. + * + * @param withText False means invisible citation (no text). + * @param inParenthesis True means "(Au and Thor 2000)". + * False means "Au and Thor (2000)". + */ + private static CitationType citationTypeFromOptions(boolean withText, boolean inParenthesis) { + if (!withText) { + return CitationType.INVISIBLE_CIT; + } + return (inParenthesis + ? CitationType.AUTHORYEAR_PAR + : CitationType.AUTHORYEAR_INTEXT); + } + + private void pushEntries(CitationType citationType, boolean addPageInfo) { + final String title = Localization.lang("Error pushing entries"); + + LibraryTab libraryTab = frame.getCurrentLibraryTab(); + if (libraryTab == null) { + OOError.noDataBaseIsOpenForCiting() + .setTitle(title) + .showErrorDialog(dialogService); + return; + } + + final BibDatabase database = libraryTab.getDatabase(); + if (database == null) { + OOError.noDataBaseIsOpenForCiting() + .setTitle(title) + .showErrorDialog(dialogService); + return; + } + + List entries = libraryTab.getSelectedEntries(); + if (entries.isEmpty()) { + OOError.noEntriesSelectedForCitation() + .setTitle(title) + .showErrorDialog(dialogService); + return; + } + + if (getOrUpdateTheStyle(title)) { return; } - Boolean inParenthesis = inParenthesisIn; String pageInfo = null; if (addPageInfo) { + Boolean inParenthesis = citationType.inParenthesis(); + boolean withText = citationType.withText(); Optional citeDialogViewModel = dialogService.showCustomDialogAndWait(new AdvancedCiteDialogView()); if (citeDialogViewModel.isPresent()) { @@ -493,42 +482,29 @@ private void pushEntries(boolean inParenthesisIn, boolean withText, boolean addP pageInfo = model.pageInfoProperty().getValue(); } inParenthesis = model.citeInParProperty().getValue(); + citationType = citationTypeFromOptions(withText, inParenthesis); + } else { + // user canceled + return; } } - LibraryTab libraryTab = frame.getCurrentLibraryTab(); - if (libraryTab != null) { - final BibDatabase database = libraryTab.getDatabase(); - List entries = libraryTab.getSelectedEntries(); - if (!entries.isEmpty() && checkThatEntriesHaveKeys(entries)) { - - try { - if (style == null) { - style = loader.getUsedStyle(); - } - ooBase.insertEntry(entries, database, getBaseList(), style, inParenthesis, withText, pageInfo, - ooPrefs.getSyncWhenCiting()); - } catch (FileNotFoundException ex) { - - dialogService.showErrorDialogAndWait( - Localization.lang("No valid style file defined"), - Localization.lang("You must select either a valid style file, or use one of the default styles.")); - - LOGGER.warn("Problem with style file", ex); - } catch (ConnectionLostException ex) { - showConnectionLostErrorMessage(); - } catch (UndefinedCharacterFormatException ex) { - reportUndefinedCharacterFormat(ex); - } catch (UndefinedParagraphFormatException ex) { - reportUndefinedParagraphFormat(ex); - } catch (com.sun.star.lang.IllegalArgumentException | UnknownPropertyException | PropertyVetoException | - CreationException | NoSuchElementException | WrappedTargetException | IOException | - BibEntryNotFoundException | IllegalTypeException | PropertyExistException | - NotRemoveableException ex) { - LOGGER.warn("Could not insert entry", ex); - } - } + if (!checkThatEntriesHaveKeys(entries)) { + // Not all entries have keys and key generation was declined. + return; } + + Optional syncOptions = + (ooPrefs.getSyncWhenCiting() + ? Optional.of(new Update.SyncOptions(getBaseList())) + : Optional.empty()); + + ooBase.guiActionInsertEntry(entries, + database, + style, + citationType, + pageInfo, + syncOptions); } /** @@ -583,27 +559,6 @@ private boolean checkThatEntriesHaveKeys(List entries) { } } - private void showConnectionLostErrorMessage() { - dialogService.showErrorDialogAndWait(Localization.lang("Connection lost"), - Localization.lang("Connection to OpenOffice/LibreOffice has been lost. " + "Please make sure OpenOffice/LibreOffice is running, and try to reconnect.")); - } - - private void reportUndefinedParagraphFormat(UndefinedParagraphFormatException ex) { - dialogService.showErrorDialogAndWait(Localization.lang("Undefined paragraph format"), - Localization.lang("Your style file specifies the paragraph format '%0', " - + "which is undefined in your current OpenOffice/LibreOffice document.", - ex.getFormatName()) + "\n" + Localization.lang("The paragraph format is controlled by the property 'ReferenceParagraphFormat' or 'ReferenceHeaderParagraphFormat' in the style file.")); - } - - private void reportUndefinedCharacterFormat(UndefinedCharacterFormatException ex) { - dialogService.showErrorDialogAndWait(Localization.lang("Undefined character format"), - Localization.lang("Your style file specifies the character format '%0', " - + "which is undefined in your current OpenOffice/LibreOffice document.", - ex.getFormatName()) + "\n" + Localization.lang("The character format is controlled by the citation property 'CitationCharacterFormat' in the style file.") - - ); - } - private ContextMenu createSettingsPopup() { ContextMenu contextMenu = new ContextMenu(); diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index bf4c349bb76..1e9bbace212 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -1056,11 +1056,12 @@ Combine\ pairs\ of\ citations\ that\ are\ separated\ by\ spaces\ only=Combine pa Autodetection\ failed=Autodetection failed Please\ wait...=Please wait... Connection\ lost=Connection lost -The\ paragraph\ format\ is\ controlled\ by\ the\ property\ 'ReferenceParagraphFormat'\ or\ 'ReferenceHeaderParagraphFormat'\ in\ the\ style\ file.=The paragraph format is controlled by the property 'ReferenceParagraphFormat' or 'ReferenceHeaderParagraphFormat' in the style file. -The\ character\ format\ is\ controlled\ by\ the\ citation\ property\ 'CitationCharacterFormat'\ in\ the\ style\ file.=The character format is controlled by the citation property 'CitationCharacterFormat' in the style file. +Could\ not\ update\ bibliography=Could not update bibliography Not\ connected\ to\ document=Not connected to document Problem\ combining\ cite\ markers=Problem combining cite markers +Problem\ generating\ new\ database.=Problem generating new database. +Unable\ to\ reload\ style\ file=Unable to reload style file Problem\ during\ separating\ cite\ markers=Problem during separating cite markers @@ -1174,8 +1175,6 @@ To\ disable\ the\ memory\ stick\ mode\ rename\ or\ remove\ the\ jabref.xml\ file Unable\ to\ connect.\ One\ possible\ reason\ is\ that\ JabRef\ and\ OpenOffice/LibreOffice\ are\ not\ both\ running\ in\ either\ 32\ bit\ mode\ or\ 64\ bit\ mode.=Unable to connect. One possible reason is that JabRef and OpenOffice/LibreOffice are not both running in either 32 bit mode or 64 bit mode. Delimiter(s)=Delimiter(s) When\ downloading\ files,\ or\ moving\ linked\ files\ to\ the\ file\ directory,\ prefer\ the\ BIB\ file\ location\ rather\ than\ the\ file\ directory\ set\ above=When downloading files, or moving linked files to the file directory, prefer the BIB file location rather than the file directory set above -Your\ style\ file\ specifies\ the\ character\ format\ '%0',\ which\ is\ undefined\ in\ your\ current\ OpenOffice/LibreOffice\ document.=Your style file specifies the character format '%0', which is undefined in your current OpenOffice/LibreOffice document. -Your\ style\ file\ specifies\ the\ paragraph\ format\ '%0',\ which\ is\ undefined\ in\ your\ current\ OpenOffice/LibreOffice\ document.=Your style file specifies the paragraph format '%0', which is undefined in your current OpenOffice/LibreOffice document. Searching...=Searching... Please\ enter\ a\ search\ string=Please enter a search string @@ -1845,9 +1844,6 @@ Could\ not\ connect\ to\ Vim\ server.\ Make\ sure\ that\ Vim\ is\ running\ with\ Could\ not\ connect\ to\ a\ running\ gnuserv\ process.\ Make\ sure\ that\ Emacs\ or\ XEmacs\ is\ running,\ and\ that\ the\ server\ has\ been\ started\ (by\ running\ the\ command\ 'server-start'/'gnuserv-start').=Could not connect to a running gnuserv process. Make sure that Emacs or XEmacs is running, and that the server has been started (by running the command 'server-start'/'gnuserv-start'). Error\ pushing\ entries=Error pushing entries -Undefined\ character\ format=Undefined character format -Undefined\ paragraph\ format=Undefined paragraph format - Edit\ Preamble=Edit Preamble Markings=Markings Use\ selected\ instance=Use selected instance @@ -2333,8 +2329,6 @@ Separate\ merged\ citations=Separate merged citations Separate\ citations=Separate citations Unprotect\ terms=Unprotect terms -Error\ connecting\ to\ Writer\ document=Error connecting to Writer document -You\ need\ to\ open\ Writer\ with\ a\ document\ before\ connecting=You need to open Writer with a document before connecting Generate\ a\ new\ key\ for\ imported\ entries\ (overwriting\ their\ default)=Generate a new key for imported entries (overwriting their default) Import\ settings=Import settings From e12fdb7a0867fd5bc0d5a186b75feb768a46fc11 Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 13:39:46 +0200 Subject: [PATCH 021/103] cleanup --- .../openoffice/BibEntryNotFoundException.java | 16 - .../openoffice/ConnectionLostException.java | 11 - .../org/jabref/gui/openoffice/OOBibBase.java | 1424 ----------------- .../UndefinedCharacterFormatException.java | 19 - .../org/jabref/logic/openoffice/OOUtil.java | 285 ---- .../openoffice/UndefinedBibtexEntry.java | 22 - .../UndefinedParagraphFormatException.java | 18 - .../logic/openoffice/style/OOBibStyle.java | 398 ----- src/main/resources/l10n/JabRef_en.properties | 1 - .../openoffice/style/OOBibStyleTest.java | 115 +- .../style/OOBibStyleTestHelper.java | 51 +- 11 files changed, 100 insertions(+), 2260 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/openoffice/BibEntryNotFoundException.java delete mode 100644 src/main/java/org/jabref/gui/openoffice/ConnectionLostException.java delete mode 100644 src/main/java/org/jabref/gui/openoffice/OOBibBase.java delete mode 100644 src/main/java/org/jabref/gui/openoffice/UndefinedCharacterFormatException.java delete mode 100644 src/main/java/org/jabref/logic/openoffice/OOUtil.java delete mode 100644 src/main/java/org/jabref/logic/openoffice/UndefinedBibtexEntry.java delete mode 100644 src/main/java/org/jabref/logic/openoffice/UndefinedParagraphFormatException.java diff --git a/src/main/java/org/jabref/gui/openoffice/BibEntryNotFoundException.java b/src/main/java/org/jabref/gui/openoffice/BibEntryNotFoundException.java deleted file mode 100644 index b3db5f8f9e7..00000000000 --- a/src/main/java/org/jabref/gui/openoffice/BibEntryNotFoundException.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.jabref.gui.openoffice; - -class BibEntryNotFoundException extends Exception { - - private final String citationKey; - - public BibEntryNotFoundException(String citationKey, String message) { - super(message); - - this.citationKey = citationKey; - } - - public String getCitationKey() { - return citationKey; - } -} diff --git a/src/main/java/org/jabref/gui/openoffice/ConnectionLostException.java b/src/main/java/org/jabref/gui/openoffice/ConnectionLostException.java deleted file mode 100644 index 36fc16e5e3f..00000000000 --- a/src/main/java/org/jabref/gui/openoffice/ConnectionLostException.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.jabref.gui.openoffice; - -/** - * This exception is used to indicate that connection to OpenOffice has been lost. - */ -class ConnectionLostException extends RuntimeException { - - public ConnectionLostException(String s) { - super(s); - } -} diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase.java deleted file mode 100644 index 540c5f9216b..00000000000 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase.java +++ /dev/null @@ -1,1424 +0,0 @@ -package org.jabref.gui.openoffice; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import org.jabref.architecture.AllowedToUseAwt; -import org.jabref.gui.DialogService; -import org.jabref.logic.bibtex.comparator.FieldComparator; -import org.jabref.logic.bibtex.comparator.FieldComparatorStack; -import org.jabref.logic.l10n.Localization; -import org.jabref.logic.layout.Layout; -import org.jabref.logic.openoffice.OOUtil; -import org.jabref.logic.openoffice.UndefinedBibtexEntry; -import org.jabref.logic.openoffice.UndefinedParagraphFormatException; -import org.jabref.logic.openoffice.style.OOBibStyle; -import org.jabref.logic.openoffice.style.OOPreFormatter; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.StandardField; -import org.jabref.model.openoffice.uno.CreationException; -import org.jabref.model.openoffice.uno.NoDocumentException; - -import com.sun.star.awt.Point; -import com.sun.star.beans.IllegalTypeException; -import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; -import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.beans.XPropertyContainer; -import com.sun.star.beans.XPropertySet; -import com.sun.star.comp.helper.BootstrapException; -import com.sun.star.container.NoSuchElementException; -import com.sun.star.container.XEnumeration; -import com.sun.star.container.XEnumerationAccess; -import com.sun.star.container.XNameAccess; -import com.sun.star.container.XNamed; -import com.sun.star.document.XDocumentPropertiesSupplier; -import com.sun.star.frame.XComponentLoader; -import com.sun.star.frame.XController; -import com.sun.star.frame.XDesktop; -import com.sun.star.frame.XModel; -import com.sun.star.lang.DisposedException; -import com.sun.star.lang.IllegalArgumentException; -import com.sun.star.lang.Locale; -import com.sun.star.lang.WrappedTargetException; -import com.sun.star.lang.XComponent; -import com.sun.star.lang.XMultiComponentFactory; -import com.sun.star.lang.XMultiServiceFactory; -import com.sun.star.text.XBookmarksSupplier; -import com.sun.star.text.XDocumentIndexesSupplier; -import com.sun.star.text.XFootnote; -import com.sun.star.text.XReferenceMarksSupplier; -import com.sun.star.text.XText; -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.text.XTextRangeCompare; -import com.sun.star.text.XTextSection; -import com.sun.star.text.XTextSectionsSupplier; -import com.sun.star.text.XTextViewCursor; -import com.sun.star.text.XTextViewCursorSupplier; -import com.sun.star.uno.Any; -import com.sun.star.uno.Type; -import com.sun.star.uno.UnoRuntime; -import com.sun.star.uno.XComponentContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class for manipulating the Bibliography of the currently start document in OpenOffice. - */ -@AllowedToUseAwt("Requires AWT for italics and bold") -class OOBibBase { - - private static final OOPreFormatter POSTFORMATTER = new OOPreFormatter(); - - private static final String BIB_SECTION_NAME = "JR_bib"; - private static final String BIB_SECTION_END_NAME = "JR_bib_end"; - private static final String BIB_CITATION = "JR_cite"; - private static final Pattern CITE_PATTERN = Pattern.compile(OOBibBase.BIB_CITATION + "\\d*_(\\d*)_(.*)"); - - private static final String CHAR_STYLE_NAME = "CharStyleName"; - - private static final int AUTHORYEAR_PAR = 1; - private static final int AUTHORYEAR_INTEXT = 2; - private static final int INVISIBLE_CIT = 3; - - private static final Logger LOGGER = LoggerFactory.getLogger(OOBibBase.class); - private XMultiServiceFactory mxDocFactory; - private XTextDocument mxDoc; - private XText text; - private final XDesktop xDesktop; - private XTextViewCursorSupplier xViewCursorSupplier; - private XComponent xCurrentComponent; - private XPropertySet propertySet; - - private XPropertyContainer userProperties; - private final boolean atEnd; - private final Comparator entryComparator; - private final Comparator yearAuthorTitleComparator; - private final FieldComparator authComp = new FieldComparator(StandardField.AUTHOR); - private final FieldComparator yearComp = new FieldComparator(StandardField.YEAR); - - private final FieldComparator titleComp = new FieldComparator(StandardField.TITLE); - private final List> authorYearTitleList = new ArrayList<>(3); - - private final List> yearAuthorTitleList = new ArrayList<>(3); - private final Map uniquefiers = new HashMap<>(); - private List sortedReferenceMarks; - - private final DialogService dialogService; - - public OOBibBase(Path loPath, boolean atEnd, DialogService dialogService) throws IllegalAccessException, InvocationTargetException, BootstrapException, CreationException, IOException, ClassNotFoundException { - - this.dialogService = dialogService; - - authorYearTitleList.add(authComp); - authorYearTitleList.add(yearComp); - authorYearTitleList.add(titleComp); - - yearAuthorTitleList.add(yearComp); - yearAuthorTitleList.add(authComp); - yearAuthorTitleList.add(titleComp); - - entryComparator = new FieldComparatorStack<>(authorYearTitleList); - yearAuthorTitleComparator = new FieldComparatorStack<>(yearAuthorTitleList); - - this.atEnd = atEnd; - - xDesktop = simpleBootstrap(loPath); - } - - public boolean isConnectedToDocument() { - return xCurrentComponent != null; - } - - public XTextDocument selectComponent(List list) { - List viewModel = list.stream().map(DocumentTitleViewModel::new).collect(Collectors.toList()); - // this whole method is part of a background task when auto-detecting instances, so we need to show dialog in FX thread - Optional selectedDocument = dialogService.showChoiceDialogAndWait(Localization.lang("Select document"), Localization.lang("Found documents:"), Localization.lang("Use selected document"), viewModel); - return selectedDocument.map(DocumentTitleViewModel::getXtextDocument).orElse(null); - } - - public Optional getCurrentDocumentTitle() { - return getDocumentTitle(mxDoc); - } - - private Optional getDocumentTitle(XTextDocument doc) { - if (doc == null) { - return Optional.empty(); - } else { - try { - return Optional.of(String.valueOf(OOUtil.getProperty(doc.getCurrentController().getFrame(), "Title"))); - } catch (UnknownPropertyException | WrappedTargetException e) { - LOGGER.warn("Could not get document title", e); - return Optional.empty(); - } - } - } - - public void selectDocument() throws NoDocumentException, NoSuchElementException, WrappedTargetException { - List textDocumentList = getTextDocuments(); - XTextDocument selected; - if (textDocumentList.isEmpty()) { - // No text documents found. - throw new NoDocumentException("No Writer documents found"); - } else if (textDocumentList.size() == 1) { - // Get the only one - selected = textDocumentList.get(0); - } else { - // Bring up a dialog - selected = selectComponent(textDocumentList); - } - - if (selected == null) { - return; - } - xCurrentComponent = UnoRuntime.queryInterface(XComponent.class, selected); - mxDoc = selected; - - UnoRuntime.queryInterface(XDocumentIndexesSupplier.class, xCurrentComponent); - - XModel xModel = UnoRuntime.queryInterface(XModel.class, xCurrentComponent); - XController xController = xModel.getCurrentController(); - xViewCursorSupplier = UnoRuntime.queryInterface(XTextViewCursorSupplier.class, xController); - - // get a reference to the body text of the document - text = mxDoc.getText(); - - // Access the text document's multi service factory: - mxDocFactory = UnoRuntime.queryInterface(XMultiServiceFactory.class, mxDoc); - - XDocumentPropertiesSupplier supp = UnoRuntime.queryInterface(XDocumentPropertiesSupplier.class, mxDoc); - userProperties = supp.getDocumentProperties().getUserDefinedProperties(); - propertySet = UnoRuntime.queryInterface(XPropertySet.class, userProperties); - } - - private List getTextDocuments() throws NoSuchElementException, WrappedTargetException { - List result = new ArrayList<>(); - XEnumerationAccess enumAccess = xDesktop.getComponents(); - XEnumeration componentEnumeration = enumAccess.createEnumeration(); - - // TODO: http://api.openoffice.org/docs/DevelopersGuide/OfficeDev/OfficeDev.xhtml#1_1_3_2_1_2_Frame_Hierarchies - - while (componentEnumeration.hasMoreElements()) { - Object nextElement = componentEnumeration.nextElement(); - XComponent component = UnoRuntime.queryInterface(XComponent.class, nextElement); - XTextDocument document = UnoRuntime.queryInterface(XTextDocument.class, component); - if (document != null) { - result.add(document); - } - } - return result; - } - - private XDesktop simpleBootstrap(Path loPath) - throws CreationException, BootstrapException { - - // Get the office component context: - XComponentContext xContext = org.jabref.gui.openoffice.Bootstrap.bootstrap(loPath); - // Get the office service manager: - XMultiComponentFactory xServiceManager = xContext.getServiceManager(); - // Create the desktop, which is the root frame of the - // hierarchy of frames that contain viewable components: - Object desktop; - try { - desktop = xServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", xContext); - } catch (Exception e) { - throw new CreationException(e.getMessage()); - } - XDesktop resultDesktop = UnoRuntime.queryInterface(XDesktop.class, desktop); - - UnoRuntime.queryInterface(XComponentLoader.class, desktop); - - return resultDesktop; - } - - public Optional getCustomProperty(String property) throws UnknownPropertyException, WrappedTargetException { - if (propertySet.getPropertySetInfo().hasPropertyByName(property)) { - return Optional.ofNullable(propertySet.getPropertyValue(property).toString()); - } - return Optional.empty(); - } - - public void updateSortedReferenceMarks() throws WrappedTargetException, NoSuchElementException { - sortedReferenceMarks = getSortedReferenceMarks(getReferenceMarks()); - } - - public void setCustomProperty(String property, String value) throws UnknownPropertyException, - NotRemoveableException, PropertyExistException, IllegalTypeException, IllegalArgumentException { - if (propertySet.getPropertySetInfo().hasPropertyByName(property)) { - userProperties.removeProperty(property); - } - if (value != null) { - userProperties.addProperty(property, com.sun.star.beans.PropertyAttribute.REMOVEABLE, - new Any(Type.STRING, value)); - } - } - - /** - * This method inserts a cite marker in the text for the given BibEntry, and may refresh the bibliography. - * - * @param entries The entries to cite. - * @param database The database the entry belongs to. - * @param style The bibliography style we are using. - * @param inParenthesis Indicates whether it is an in-text citation or a citation in parenthesis. This is not relevant if numbered citations are used. - * @param withText Indicates whether this should be a normal citation (true) or an empty (invisible) citation (false). - * @param sync Indicates whether the reference list should be refreshed. - * @throws IllegalTypeException - * @throws PropertyExistException - * @throws NotRemoveableException - * @throws UnknownPropertyException - * @throws UndefinedCharacterFormatException - * @throws NoSuchElementException - * @throws WrappedTargetException - * @throws IOException - * @throws PropertyVetoException - * @throws CreationException - * @throws BibEntryNotFoundException - * @throws UndefinedParagraphFormatException - */ - public void insertEntry(List entries, BibDatabase database, - List allBases, OOBibStyle style, - boolean inParenthesis, boolean withText, String pageInfo, boolean sync) - throws IllegalArgumentException, - UnknownPropertyException, NotRemoveableException, PropertyExistException, IllegalTypeException, - UndefinedCharacterFormatException, WrappedTargetException, NoSuchElementException, PropertyVetoException, - IOException, CreationException, BibEntryNotFoundException, UndefinedParagraphFormatException { - - try { - - XTextViewCursor xViewCursor = xViewCursorSupplier.getViewCursor(); - - if (entries.size() > 1) { - if (style.getBooleanCitProperty(OOBibStyle.MULTI_CITE_CHRONOLOGICAL)) { - entries.sort(yearAuthorTitleComparator); - } else { - entries.sort(entryComparator); - } - } - - String keyString = String.join(",", - entries.stream().map(entry -> entry.getCitationKey().orElse("")).collect(Collectors.toList())); - // Insert bookmark: - String bName = getUniqueReferenceMarkName(keyString, - withText ? inParenthesis ? OOBibBase.AUTHORYEAR_PAR : OOBibBase.AUTHORYEAR_INTEXT : OOBibBase.INVISIBLE_CIT); - - // If we should store metadata for page info, do that now: - if (pageInfo != null) { - LOGGER.info("Storing page info: " + pageInfo); - setCustomProperty(bName, pageInfo); - } - - xViewCursor.getText().insertString(xViewCursor, " ", false); - if (style.isFormatCitations()) { - XPropertySet xCursorProps = UnoRuntime.queryInterface(XPropertySet.class, xViewCursor); - String charStyle = style.getCitationCharacterFormat(); - try { - xCursorProps.setPropertyValue(CHAR_STYLE_NAME, charStyle); - } catch (UnknownPropertyException | PropertyVetoException | IllegalArgumentException | - WrappedTargetException ex) { - // Setting the character format failed, so we throw an exception that - // will result in an error message for the user. Before that, - // delete the space we inserted: - xViewCursor.goLeft((short) 1, true); - xViewCursor.setString(""); - throw new UndefinedCharacterFormatException(charStyle); - } - } - xViewCursor.goLeft((short) 1, false); - Map databaseMap = new HashMap<>(); - for (BibEntry entry : entries) { - databaseMap.put(entry, database); - } - String citeText = style.isNumberEntries() ? "-" : style.getCitationMarker(entries, databaseMap, - inParenthesis, null, null); - insertReferenceMark(bName, citeText, xViewCursor, withText, style); - - xViewCursor.collapseToEnd(); - xViewCursor.goRight((short) 1, false); - - XTextRange position = xViewCursor.getEnd(); - - if (sync) { - // To account for numbering and for uniqiefiers, we must refresh the cite markers: - updateSortedReferenceMarks(); - refreshCiteMarkers(allBases, style); - - // Insert it at the current position: - rebuildBibTextSection(allBases, style); - } - - // Go back to the relevant position: - xViewCursor.gotoRange(position, false); - } catch (DisposedException ex) { - // We need to catch this one here because the OpenOfficePanel class is - // loaded before connection, and therefore cannot directly reference - // or catch a DisposedException (which is in a OO JAR file). - throw new ConnectionLostException(ex.getMessage()); - } - } - - public List getJabRefReferenceMarks(XNameAccess nameAccess) { - String[] names = nameAccess.getElementNames(); - // Remove all reference marks that don't look like JabRef citations: - List result = new ArrayList<>(); - if (names != null) { - for (String name : names) { - if (CITE_PATTERN.matcher(name).find()) { - result.add(name); - } - } - } - return result; - } - - /** - * Refresh all cite markers in the document. - * - * @param databases The databases to get entries from. - * @param style The bibliography style to use. - * @return A list of those referenced citation keys that could not be resolved. - * @throws UndefinedCharacterFormatException - * @throws NoSuchElementException - * @throws IllegalArgumentException - * @throws WrappedTargetException - * @throws BibEntryNotFoundException - * @throws CreationException - * @throws IOException - * @throws PropertyVetoException - * @throws UnknownPropertyException - */ - public List refreshCiteMarkers(List databases, OOBibStyle style) - throws WrappedTargetException, IllegalArgumentException, NoSuchElementException, - UndefinedCharacterFormatException, UnknownPropertyException, PropertyVetoException, IOException, - CreationException, BibEntryNotFoundException { - try { - return refreshCiteMarkersInternal(databases, style); - } catch (DisposedException ex) { - // We need to catch this one here because the OpenOfficePanel class is - // loaded before connection, and therefore cannot directly reference - // or catch a DisposedException (which is in a OO JAR file). - throw new ConnectionLostException(ex.getMessage()); - } - } - - private List refreshCiteMarkersInternal(List databases, OOBibStyle style) - throws WrappedTargetException, IllegalArgumentException, NoSuchElementException, - UndefinedCharacterFormatException, UnknownPropertyException, PropertyVetoException, - CreationException, BibEntryNotFoundException { - - List cited = findCitedKeys(); - Map linkSourceBase = new HashMap<>(); - Map entries = findCitedEntries(databases, cited, linkSourceBase); - - XNameAccess xReferenceMarks = getReferenceMarks(); - - List names; - if (style.isSortByPosition()) { - // We need to sort the reference marks according to their order of appearance: - names = sortedReferenceMarks; - } else if (style.isNumberEntries()) { - // We need to sort the reference marks according to the sorting of the bibliographic - // entries: - SortedMap newMap = new TreeMap<>(entryComparator); - for (Map.Entry bibtexEntryBibtexDatabaseEntry : entries.entrySet()) { - newMap.put(bibtexEntryBibtexDatabaseEntry.getKey(), bibtexEntryBibtexDatabaseEntry.getValue()); - } - entries = newMap; - // Rebuild the list of cited keys according to the sort order: - cited.clear(); - for (BibEntry entry : entries.keySet()) { - cited.add(entry.getCitationKey().orElse(null)); - } - names = Arrays.asList(xReferenceMarks.getElementNames()); - } else { - names = sortedReferenceMarks; - } - - // Remove all reference marks that don't look like JabRef citations: - List tmp = new ArrayList<>(); - for (String name : names) { - if (CITE_PATTERN.matcher(name).find()) { - tmp.add(name); - } - } - names = tmp; - - Map numbers = new HashMap<>(); - int lastNum = 0; - // First compute citation markers for all citations: - String[] citMarkers = new String[names.size()]; - String[][] normCitMarkers = new String[names.size()][]; - String[][] bibtexKeys = new String[names.size()][]; - - int minGroupingCount = style.getIntCitProperty(OOBibStyle.MINIMUM_GROUPING_COUNT); - - int[] types = new int[names.size()]; - for (int i = 0; i < names.size(); i++) { - Matcher citeMatcher = CITE_PATTERN.matcher(names.get(i)); - if (citeMatcher.find()) { - String typeStr = citeMatcher.group(1); - int type = Integer.parseInt(typeStr); - types[i] = type; // Remember the type in case we need to uniquefy. - String[] keys = citeMatcher.group(2).split(","); - bibtexKeys[i] = keys; - BibEntry[] cEntries = new BibEntry[keys.length]; - for (int j = 0; j < cEntries.length; j++) { - BibDatabase database = linkSourceBase.get(keys[j]); - Optional tmpEntry = Optional.empty(); - if (database != null) { - tmpEntry = database.getEntryByCitationKey(keys[j]); - } - if (tmpEntry.isPresent()) { - cEntries[j] = tmpEntry.get(); - } else { - LOGGER.info("Citation key not found: '" + keys[j] + '\''); - LOGGER.info("Problem with reference mark: '" + names.get(i) + '\''); - throw new BibEntryNotFoundException(names.get(i), Localization - .lang("Could not resolve BibTeX entry for citation marker '%0'.", names.get(i))); - } - } - - String[] normCitMarker = new String[keys.length]; - String citationMarker; - if (style.isCitationKeyCiteMarkers()) { - StringBuilder sb = new StringBuilder(); - normCitMarkers[i] = new String[keys.length]; - for (int j = 0; j < keys.length; j++) { - normCitMarkers[i][j] = cEntries[j].getCitationKey().orElse(null); - sb.append(cEntries[j].getCitationKey().orElse("")); - if (j < (keys.length - 1)) { - sb.append(','); - } - } - citationMarker = sb.toString(); - } else if (style.isNumberEntries()) { - if (style.isSortByPosition()) { - // We have sorted the citation markers according to their order of appearance, - // so we simply count up for each marker referring to a new entry: - List num = new ArrayList<>(keys.length); - for (int j = 0; j < keys.length; j++) { - if (cEntries[j] instanceof UndefinedBibtexEntry) { - num.add(j, -1); - } else { - num.add(j, lastNum + 1); - if (numbers.containsKey(keys[j])) { - num.set(j, numbers.get(keys[j])); - } else { - numbers.put(keys[j], num.get(j)); - lastNum = num.get(j); - } - } - } - citationMarker = style.getNumCitationMarker(num, minGroupingCount, false); - for (int j = 0; j < keys.length; j++) { - normCitMarker[j] = style.getNumCitationMarker(Collections.singletonList(num.get(j)), - minGroupingCount, false); - } - } else { - // We need to find the number of the cited entry in the bibliography, - // and use that number for the cite marker: - List num = findCitedEntryIndex(names.get(i), cited); - - if (num.isEmpty()) { - throw new BibEntryNotFoundException(names.get(i), Localization - .lang("Could not resolve BibTeX entry for citation marker '%0'.", names.get(i))); - } else { - citationMarker = style.getNumCitationMarker(num, minGroupingCount, false); - } - - for (int j = 0; j < keys.length; j++) { - List list = new ArrayList<>(1); - list.add(num.get(j)); - normCitMarker[j] = style.getNumCitationMarker(list, minGroupingCount, false); - } - } - } else { - - if (cEntries.length > 1) { - if (style.getBooleanCitProperty(OOBibStyle.MULTI_CITE_CHRONOLOGICAL)) { - Arrays.sort(cEntries, yearAuthorTitleComparator); - } else { - Arrays.sort(cEntries, entryComparator); - } - // Update key list to match the new sorting: - for (int j = 0; j < cEntries.length; j++) { - bibtexKeys[i][j] = cEntries[j].getCitationKey().orElse(null); - } - } - - citationMarker = style.getCitationMarker(Arrays.asList(cEntries), entries, - type == OOBibBase.AUTHORYEAR_PAR, null, null); - // We need "normalized" (in parenthesis) markers for uniqueness checking purposes: - for (int j = 0; j < cEntries.length; j++) { - normCitMarker[j] = style.getCitationMarker(Collections.singletonList(cEntries[j]), entries, - true, null, new int[] {-1}); - } - } - citMarkers[i] = citationMarker; - normCitMarkers[i] = normCitMarker; - } - } - - uniquefiers.clear(); - if (!style.isCitationKeyCiteMarkers() && !style.isNumberEntries()) { - // See if there are duplicate citations marks referring to different entries. If so, we need to - // use uniquefiers: - Map> refKeys = new HashMap<>(); - Map> refNums = new HashMap<>(); - for (int i = 0; i < citMarkers.length; i++) { - String[] markers = normCitMarkers[i]; // compare normalized markers, since the actual markers can be different - for (int j = 0; j < markers.length; j++) { - String marker = markers[j]; - String currentKey = bibtexKeys[i][j]; - if (refKeys.containsKey(marker)) { - // Ok, we have seen this exact marker before. - if (!refKeys.get(marker).contains(currentKey)) { - // ... but not for this entry. - refKeys.get(marker).add(currentKey); - refNums.get(marker).add(i); - } - } else { - List l = new ArrayList<>(1); - l.add(currentKey); - refKeys.put(marker, l); - List l2 = new ArrayList<>(1); - l2.add(i); - refNums.put(marker, l2); - } - } - } - // Go through the collected lists and see where we need to uniquefy: - for (Map.Entry> stringListEntry : refKeys.entrySet()) { - List keys = stringListEntry.getValue(); - if (keys.size() > 1) { - // This marker appears for more than one unique entry: - int uniq = 'a'; - for (String key : keys) { - // Update the map of uniquefiers for the benefit of both the following generation of new - // citation markers, and for the method that builds the bibliography: - uniquefiers.put(key, String.valueOf((char) uniq)); - uniq++; - } - } - } - - // Finally, go through all citation markers, and update those referring to entries in our current list: - int maxAuthorsFirst = style.getIntCitProperty(OOBibStyle.MAX_AUTHORS_FIRST); - Set seenBefore = new HashSet<>(); - for (int j = 0; j < bibtexKeys.length; j++) { - boolean needsChange = false; - int[] firstLimAuthors = new int[bibtexKeys[j].length]; - String[] uniquif = new String[bibtexKeys[j].length]; - BibEntry[] cEntries = new BibEntry[bibtexKeys[j].length]; - for (int k = 0; k < bibtexKeys[j].length; k++) { - String currentKey = bibtexKeys[j][k]; - firstLimAuthors[k] = -1; - if (maxAuthorsFirst > 0) { - if (!seenBefore.contains(currentKey)) { - firstLimAuthors[k] = maxAuthorsFirst; - } - seenBefore.add(currentKey); - } - String uniq = uniquefiers.get(currentKey); - Optional tmpEntry = Optional.empty(); - if (uniq == null) { - if (firstLimAuthors[k] > 0) { - needsChange = true; - BibDatabase database = linkSourceBase.get(currentKey); - if (database != null) { - tmpEntry = database.getEntryByCitationKey(currentKey); - } - } else { - BibDatabase database = linkSourceBase.get(currentKey); - if (database != null) { - tmpEntry = database.getEntryByCitationKey(currentKey); - } - } - uniquif[k] = ""; - } else { - needsChange = true; - BibDatabase database = linkSourceBase.get(currentKey); - if (database != null) { - tmpEntry = database.getEntryByCitationKey(currentKey); - } - uniquif[k] = uniq; - } - if (tmpEntry.isPresent()) { - cEntries[k] = tmpEntry.get(); - } - } - if (needsChange) { - citMarkers[j] = style.getCitationMarker(Arrays.asList(cEntries), entries, - types[j] == OOBibBase.AUTHORYEAR_PAR, uniquif, firstLimAuthors); - } - } - } - - // Refresh all reference marks with the citation markers we computed: - boolean hadBibSection = getBookmarkRange(OOBibBase.BIB_SECTION_NAME) != null; - // Check if we are supposed to set a character format for citations: - boolean mustTestCharFormat = style.isFormatCitations(); - for (int i = 0; i < names.size(); i++) { - Object referenceMark = xReferenceMarks.getByName(names.get(i)); - XTextContent bookmark = UnoRuntime.queryInterface(XTextContent.class, referenceMark); - - XTextCursor cursor = bookmark.getAnchor().getText().createTextCursorByRange(bookmark.getAnchor()); - - if (mustTestCharFormat) { - // If we are supposed to set character format for citations, must run a test before we - // delete old citation markers. Otherwise, if the specified character format doesn't - // exist, we end up deleting the markers before the process crashes due to a the missing - // format, with catastrophic consequences for the user. - mustTestCharFormat = false; // need to do this only once - XPropertySet xCursorProps = UnoRuntime.queryInterface(XPropertySet.class, cursor); - String charStyle = style.getCitationCharacterFormat(); - try { - xCursorProps.setPropertyValue(CHAR_STYLE_NAME, charStyle); - } catch (UnknownPropertyException | PropertyVetoException | IllegalArgumentException | - WrappedTargetException ex) { - throw new UndefinedCharacterFormatException(charStyle); - } - } - - text.removeTextContent(bookmark); - - insertReferenceMark(names.get(i), citMarkers[i], cursor, types[i] != OOBibBase.INVISIBLE_CIT, style); - if (hadBibSection && (getBookmarkRange(OOBibBase.BIB_SECTION_NAME) == null)) { - // We have overwritten the marker for the start of the reference list. - // We need to add it again. - cursor.collapseToEnd(); - OOUtil.insertParagraphBreak(text, cursor); - insertBookMark(OOBibBase.BIB_SECTION_NAME, cursor); - } - } - - List unresolvedKeys = new ArrayList<>(); - for (BibEntry entry : entries.keySet()) { - if (entry instanceof UndefinedBibtexEntry) { - String key = ((UndefinedBibtexEntry) entry).getKey(); - if (!unresolvedKeys.contains(key)) { - unresolvedKeys.add(key); - } - } - } - return unresolvedKeys; - } - - private List getSortedReferenceMarks(final XNameAccess nameAccess) - throws WrappedTargetException, NoSuchElementException { - XTextViewCursorSupplier cursorSupplier = UnoRuntime.queryInterface(XTextViewCursorSupplier.class, - mxDoc.getCurrentController()); - - XTextViewCursor viewCursor = cursorSupplier.getViewCursor(); - XTextRange initialPos = viewCursor.getStart(); - List names = Arrays.asList(nameAccess.getElementNames()); - List positions = new ArrayList<>(names.size()); - for (String name : names) { - XTextContent textContent = UnoRuntime.queryInterface(XTextContent.class, nameAccess.getByName(name)); - XTextRange range = textContent.getAnchor(); - // Check if we are inside a footnote: - if (UnoRuntime.queryInterface(XFootnote.class, range.getText()) != null) { - // Find the linking footnote marker: - XFootnote footer = UnoRuntime.queryInterface(XFootnote.class, range.getText()); - // The footnote's anchor gives the correct position in the text: - range = footer.getAnchor(); - } - - positions.add(findPosition(viewCursor, range)); - } - Set set = new TreeSet<>(); - for (int i = 0; i < positions.size(); i++) { - set.add(new ComparableMark(names.get(i), positions.get(i))); - } - - List result = new ArrayList<>(set.size()); - for (ComparableMark mark : set) { - result.add(mark.getName()); - } - viewCursor.gotoRange(initialPos, false); - - return result; - } - - public XNameAccess getReferenceMarks() { - XReferenceMarksSupplier supplier = UnoRuntime.queryInterface(XReferenceMarksSupplier.class, xCurrentComponent); - return supplier.getReferenceMarks(); - } - - private String getUniqueReferenceMarkName(String bibtexKey, int type) { - XNameAccess xNamedRefMarks = getReferenceMarks(); - int i = 0; - String name = OOBibBase.BIB_CITATION + '_' + type + '_' + bibtexKey; - while (xNamedRefMarks.hasByName(name)) { - name = OOBibBase.BIB_CITATION + i + '_' + type + '_' + bibtexKey; - i++; - } - return name; - } - - public void rebuildBibTextSection(List databases, OOBibStyle style) - throws NoSuchElementException, WrappedTargetException, IllegalArgumentException, - CreationException, PropertyVetoException, UnknownPropertyException, UndefinedParagraphFormatException { - List cited = findCitedKeys(); - Map linkSourceBase = new HashMap<>(); - Map entries = findCitedEntries(databases, cited, linkSourceBase); // Although entries are redefined without use, this also updates linkSourceBase - - List names = sortedReferenceMarks; - - if (style.isSortByPosition()) { - // We need to sort the entries according to their order of appearance: - entries = getSortedEntriesFromSortedRefMarks(names, linkSourceBase); - } else { - SortedMap newMap = new TreeMap<>(entryComparator); - for (Map.Entry bibtexEntryBibtexDatabaseEntry : findCitedEntries(databases, cited, - linkSourceBase).entrySet()) { - newMap.put(bibtexEntryBibtexDatabaseEntry.getKey(), bibtexEntryBibtexDatabaseEntry.getValue()); - } - entries = newMap; - } - clearBibTextSectionContent2(); - populateBibTextSection(entries, style); - } - - private List findCitedKeys() throws NoSuchElementException, WrappedTargetException { - XNameAccess xNamedMarks = getReferenceMarks(); - String[] names = xNamedMarks.getElementNames(); - List keys = new ArrayList<>(); - for (String name1 : names) { - Object bookmark = xNamedMarks.getByName(name1); - UnoRuntime.queryInterface(XTextContent.class, bookmark); - - List newKeys = parseRefMarkName(name1); - for (String key : newKeys) { - if (!keys.contains(key)) { - keys.add(key); - } - } - } - - return keys; - } - - private Map findCitedEntries(List databases, List keys, - Map linkSourceBase) { - Map entries = new LinkedHashMap<>(); - for (String key : keys) { - boolean found = false; - for (BibDatabase database : databases) { - Optional entry = database.getEntryByCitationKey(key); - if (entry.isPresent()) { - entries.put(entry.get(), database); - linkSourceBase.put(key, database); - found = true; - break; - } - } - - if (!found) { - entries.put(new UndefinedBibtexEntry(key), null); - } - } - return entries; - } - - private Point findPosition(XTextViewCursor cursor, XTextRange range) { - cursor.gotoRange(range, false); - return cursor.getPosition(); - } - - /** - * Extract the list of citation keys from a reference mark name. - * - * @param name The reference mark name. - * @return The list of citation keys encoded in the name. - */ - public List parseRefMarkName(String name) { - List keys = new ArrayList<>(); - Matcher citeMatcher = CITE_PATTERN.matcher(name); - if (citeMatcher.find()) { - String[] keystring = citeMatcher.group(2).split(","); - for (String aKeystring : keystring) { - if (!keys.contains(aKeystring)) { - keys.add(aKeystring); - } - } - } - return keys; - } - - /** - * Resolve the citation key from a citation reference marker name, and look up the index of the key in a list of keys. - * - * @param citRefName The name of the ReferenceMark representing the citation. - * @param keys A List of citation keys representing the entries in the bibliography. - * @return the indices of the cited keys, -1 if a key is not found. Returns null if the ref name could not be resolved as a citation. - */ - private List findCitedEntryIndex(String citRefName, List keys) { - Matcher citeMatcher = CITE_PATTERN.matcher(citRefName); - if (citeMatcher.find()) { - List keyStrings = Arrays.asList(citeMatcher.group(2).split(",")); - List result = new ArrayList<>(keyStrings.size()); - for (String key : keyStrings) { - int ind = keys.indexOf(key); - result.add(ind == -1 ? -1 : 1 + ind); - } - return result; - } else { - return Collections.emptyList(); - } - } - - private Map getSortedEntriesFromSortedRefMarks(List names, - Map linkSourceBase) { - - Map newList = new LinkedHashMap<>(); - for (String name : names) { - Matcher citeMatcher = CITE_PATTERN.matcher(name); - if (citeMatcher.find()) { - String[] keys = citeMatcher.group(2).split(","); - for (String key : keys) { - BibDatabase database = linkSourceBase.get(key); - Optional origEntry = Optional.empty(); - if (database != null) { - origEntry = database.getEntryByCitationKey(key); - } - if (origEntry.isPresent()) { - if (!newList.containsKey(origEntry.get())) { - newList.put(origEntry.get(), database); - } - } else { - LOGGER.info("Citation key not found: '" + key + "'"); - LOGGER.info("Problem with reference mark: '" + name + "'"); - newList.put(new UndefinedBibtexEntry(key), null); - } - } - } - } - - return newList; - } - - public String getCitationContext(XNameAccess nameAccess, String refMarkName, int charBefore, int charAfter, - boolean htmlMarkup) - throws NoSuchElementException, WrappedTargetException { - Object referenceMark = nameAccess.getByName(refMarkName); - XTextContent bookmark = UnoRuntime.queryInterface(XTextContent.class, referenceMark); - - XTextCursor cursor = bookmark.getAnchor().getText().createTextCursorByRange(bookmark.getAnchor()); - String citPart = cursor.getString(); - int flex = 8; - for (int i = 0; i < charBefore; i++) { - try { - cursor.goLeft((short) 1, true); - if ((i >= (charBefore - flex)) && Character.isWhitespace(cursor.getString().charAt(0))) { - break; - } - } catch (IndexOutOfBoundsException ex) { - LOGGER.warn("Problem going left", ex); - } - } - int length = cursor.getString().length(); - int added = length - citPart.length(); - cursor.collapseToStart(); - for (int i = 0; i < (charAfter + length); i++) { - try { - cursor.goRight((short) 1, true); - if (i >= ((charAfter + length) - flex)) { - String strNow = cursor.getString(); - if (Character.isWhitespace(strNow.charAt(strNow.length() - 1))) { - break; - } - } - } catch (IndexOutOfBoundsException ex) { - LOGGER.warn("Problem going right", ex); - } - } - - String result = cursor.getString(); - if (htmlMarkup) { - result = result.substring(0, added) + "" + citPart + "" + result.substring(length); - } - return result.trim(); - } - - private void insertFullReferenceAtCursor(XTextCursor cursor, Map entries, OOBibStyle style, - String parFormat) - throws UndefinedParagraphFormatException, IllegalArgumentException, - UnknownPropertyException, PropertyVetoException, WrappedTargetException { - Map correctEntries; - // If we don't have numbered entries, we need to sort the entries before adding them: - if (style.isSortByPosition()) { - // Use the received map directly - correctEntries = entries; - } else { - // Sort map - Map newMap = new TreeMap<>(entryComparator); - newMap.putAll(entries); - correctEntries = newMap; - } - int number = 1; - for (Map.Entry entry : correctEntries.entrySet()) { - if (entry.getKey() instanceof UndefinedBibtexEntry) { - continue; - } - OOUtil.insertParagraphBreak(text, cursor); - if (style.isNumberEntries()) { - int minGroupingCount = style.getIntCitProperty(OOBibStyle.MINIMUM_GROUPING_COUNT); - OOUtil.insertTextAtCurrentLocation(text, cursor, - style.getNumCitationMarker(Collections.singletonList(number++), minGroupingCount, true), Collections.emptyList()); - } - Layout layout = style.getReferenceFormat(entry.getKey().getType()); - layout.setPostFormatter(POSTFORMATTER); - OOUtil.insertFullReferenceAtCurrentLocation(text, cursor, layout, parFormat, entry.getKey(), - entry.getValue(), uniquefiers.get(entry.getKey().getCitationKey().orElse(null))); - } - } - - private void createBibTextSection2(boolean end) - throws IllegalArgumentException, CreationException { - - XTextCursor mxDocCursor = text.createTextCursor(); - if (end) { - mxDocCursor.gotoEnd(false); - } - OOUtil.insertParagraphBreak(text, mxDocCursor); - // Create a new TextSection from the document factory and access it's XNamed interface - XNamed xChildNamed; - try { - xChildNamed = UnoRuntime.queryInterface(XNamed.class, - mxDocFactory.createInstance("com.sun.star.text.TextSection")); - } catch (Exception e) { - throw new CreationException(e.getMessage()); - } - // Set the new sections name to 'Child_Section' - xChildNamed.setName(OOBibBase.BIB_SECTION_NAME); - // Access the Child_Section's XTextContent interface and insert it into the document - XTextContent xChildSection = UnoRuntime.queryInterface(XTextContent.class, xChildNamed); - text.insertTextContent(mxDocCursor, xChildSection, false); - } - - private void clearBibTextSectionContent2() - throws NoSuchElementException, WrappedTargetException, IllegalArgumentException, CreationException { - - // Check if the section exists: - XTextSectionsSupplier supplier = UnoRuntime.queryInterface(XTextSectionsSupplier.class, mxDoc); - if (supplier.getTextSections().hasByName(OOBibBase.BIB_SECTION_NAME)) { - XTextSection section = (XTextSection) ((Any) supplier.getTextSections().getByName(OOBibBase.BIB_SECTION_NAME)) - .getObject(); - // Clear it: - XTextCursor cursor = text.createTextCursorByRange(section.getAnchor()); - cursor.gotoRange(section.getAnchor(), false); - cursor.setString(""); - } else { - createBibTextSection2(atEnd); - } - } - - private void populateBibTextSection(Map entries, OOBibStyle style) - throws NoSuchElementException, WrappedTargetException, PropertyVetoException, - UnknownPropertyException, UndefinedParagraphFormatException, IllegalArgumentException, CreationException { - XTextSectionsSupplier supplier = UnoRuntime.queryInterface(XTextSectionsSupplier.class, mxDoc); - XTextSection section = (XTextSection) ((Any) supplier.getTextSections().getByName(OOBibBase.BIB_SECTION_NAME)) - .getObject(); - XTextCursor cursor = text.createTextCursorByRange(section.getAnchor()); - OOUtil.insertTextAtCurrentLocation(text, cursor, (String) style.getProperty(OOBibStyle.TITLE), - (String) style.getProperty(OOBibStyle.REFERENCE_HEADER_PARAGRAPH_FORMAT)); - insertFullReferenceAtCursor(cursor, entries, style, - (String) style.getProperty(OOBibStyle.REFERENCE_PARAGRAPH_FORMAT)); - insertBookMark(OOBibBase.BIB_SECTION_END_NAME, cursor); - } - - private XTextContent insertBookMark(String name, XTextCursor position) - throws IllegalArgumentException, CreationException { - Object bookmark; - try { - bookmark = mxDocFactory.createInstance("com.sun.star.text.Bookmark"); - } catch (Exception e) { - throw new CreationException(e.getMessage()); - } - // name the bookmark - XNamed xNamed = UnoRuntime.queryInterface(XNamed.class, bookmark); - xNamed.setName(name); - // get XTextContent interface - XTextContent xTextContent = UnoRuntime.queryInterface(XTextContent.class, bookmark); - // insert bookmark at the end of the document - // instead of mxDocText.getEnd you could use a text cursor's XTextRange interface or any XTextRange - text.insertTextContent(position, xTextContent, true); - position.collapseToEnd(); - return xTextContent; - } - - private void insertReferenceMark(String name, String citationText, XTextCursor position, boolean withText, - OOBibStyle style) - throws UnknownPropertyException, WrappedTargetException, - PropertyVetoException, IllegalArgumentException, UndefinedCharacterFormatException, CreationException { - - // Check if there is "page info" stored for this citation. If so, insert it into - // the citation text before inserting the citation: - Optional pageInfo = getCustomProperty(name); - String citText; - if ((pageInfo.isPresent()) && !pageInfo.get().isEmpty()) { - citText = style.insertPageInfo(citationText, pageInfo.get()); - } else { - citText = citationText; - } - - Object bookmark; - try { - bookmark = mxDocFactory.createInstance("com.sun.star.text.ReferenceMark"); - } catch (Exception e) { - throw new CreationException(e.getMessage()); - } - // Name the reference - XNamed xNamed = UnoRuntime.queryInterface(XNamed.class, bookmark); - xNamed.setName(name); - - if (withText) { - position.setString(citText); - XPropertySet xCursorProps = UnoRuntime.queryInterface(XPropertySet.class, position); - - // Set language to [None]: - xCursorProps.setPropertyValue("CharLocale", new Locale("zxx", "", "")); - if (style.isFormatCitations()) { - String charStyle = style.getCitationCharacterFormat(); - try { - xCursorProps.setPropertyValue(CHAR_STYLE_NAME, charStyle); - } catch (UnknownPropertyException | PropertyVetoException | IllegalArgumentException | - WrappedTargetException ex) { - throw new UndefinedCharacterFormatException(charStyle); - } - } - } else { - position.setString(""); - } - - // get XTextContent interface - XTextContent xTextContent = UnoRuntime.queryInterface(XTextContent.class, bookmark); - - position.getText().insertTextContent(position, xTextContent, true); - - // Check if we should italicize the "et al." string in citations: - boolean italicize = style.getBooleanCitProperty(OOBibStyle.ITALIC_ET_AL); - if (italicize) { - String etAlString = style.getStringCitProperty(OOBibStyle.ET_AL_STRING); - int index = citText.indexOf(etAlString); - if (index >= 0) { - italicizeOrBold(position, true, index, index + etAlString.length()); - } - } - - position.collapseToEnd(); - } - - private void removeReferenceMark(String name) throws NoSuchElementException, WrappedTargetException { - XNameAccess xReferenceMarks = getReferenceMarks(); - if (xReferenceMarks.hasByName(name)) { - Object referenceMark = xReferenceMarks.getByName(name); - XTextContent bookmark = UnoRuntime.queryInterface(XTextContent.class, referenceMark); - text.removeTextContent(bookmark); - } - } - - /** - * Get the XTextRange corresponding to the named bookmark. - * - * @param name The name of the bookmark to find. - * @return The XTextRange for the bookmark. - * @throws WrappedTargetException - * @throws NoSuchElementException - */ - private XTextRange getBookmarkRange(String name) throws NoSuchElementException, WrappedTargetException { - XNameAccess xNamedBookmarks = getBookmarks(); - - // retrieve bookmark by name - if (!xNamedBookmarks.hasByName(name)) { - return null; - } - Object foundBookmark = xNamedBookmarks.getByName(name); - XTextContent xFoundBookmark = UnoRuntime.queryInterface(XTextContent.class, foundBookmark); - return xFoundBookmark.getAnchor(); - } - - private XNameAccess getBookmarks() { - // query XBookmarksSupplier from document model and get bookmarks collection - XBookmarksSupplier xBookmarksSupplier = UnoRuntime.queryInterface(XBookmarksSupplier.class, xCurrentComponent); - XNameAccess xNamedBookmarks = xBookmarksSupplier.getBookmarks(); - return xNamedBookmarks; - } - - private void italicizeOrBold(XTextCursor position, boolean italicize, int start, int end) - throws UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException { - XTextRange range = position.getStart(); - XTextCursor cursor = position.getText().createTextCursorByRange(range); - cursor.goRight((short) start, false); - cursor.goRight((short) (end - start), true); - XPropertySet xcp = UnoRuntime.queryInterface(XPropertySet.class, cursor); - if (italicize) { - xcp.setPropertyValue("CharPosture", com.sun.star.awt.FontSlant.ITALIC); - } else { - xcp.setPropertyValue("CharWeight", com.sun.star.awt.FontWeight.BOLD); - } - } - - public void combineCiteMarkers(List databases, OOBibStyle style) - throws IOException, WrappedTargetException, NoSuchElementException, IllegalArgumentException, - UndefinedCharacterFormatException, UnknownPropertyException, PropertyVetoException, CreationException, - BibEntryNotFoundException { - XNameAccess nameAccess = getReferenceMarks(); - // TODO: doesn't work for citations in footnotes/tables - List names = getSortedReferenceMarks(nameAccess); - - final XTextRangeCompare compare = UnoRuntime.queryInterface(XTextRangeCompare.class, text); - - int piv = 0; - boolean madeModifications = false; - while (piv < (names.size() - 1)) { - XTextRange range1 = UnoRuntime.queryInterface(XTextContent.class, nameAccess.getByName(names.get(piv))) - .getAnchor().getEnd(); - XTextRange range2 = UnoRuntime.queryInterface(XTextContent.class, nameAccess.getByName(names.get(piv + 1))) - .getAnchor().getStart(); - if (range1.getText() != range2.getText()) { - piv++; - continue; - } - XTextCursor mxDocCursor = range1.getText().createTextCursorByRange(range1); - mxDocCursor.goRight((short) 1, true); - boolean couldExpand = true; - while (couldExpand && (compare.compareRegionEnds(mxDocCursor, range2) > 0)) { - couldExpand = mxDocCursor.goRight((short) 1, true); - } - String cursorText = mxDocCursor.getString(); - // Check if the string contains no line breaks and only whitespace: - if ((cursorText.indexOf('\n') == -1) && cursorText.trim().isEmpty()) { - - // If we are supposed to set character format for citations, test this before - // making any changes. This way we can throw an exception before any reference - // marks are removed, preventing damage to the user's document: - if (style.isFormatCitations()) { - XPropertySet xCursorProps = UnoRuntime.queryInterface(XPropertySet.class, mxDocCursor); - String charStyle = style.getCitationCharacterFormat(); - try { - xCursorProps.setPropertyValue(CHAR_STYLE_NAME, charStyle); - } catch (UnknownPropertyException | PropertyVetoException | IllegalArgumentException | - WrappedTargetException ex) { - // Setting the character format failed, so we throw an exception that - // will result in an error message for the user: - throw new UndefinedCharacterFormatException(charStyle); - } - } - - List keys = parseRefMarkName(names.get(piv)); - keys.addAll(parseRefMarkName(names.get(piv + 1))); - removeReferenceMark(names.get(piv)); - removeReferenceMark(names.get(piv + 1)); - List entries = new ArrayList<>(); - for (String key : keys) { - for (BibDatabase database : databases) { - Optional entry = database.getEntryByCitationKey(key); - if (entry.isPresent()) { - entries.add(entry.get()); - break; - } - } - } - Collections.sort(entries, new FieldComparator(StandardField.YEAR)); - String keyString = String.join(",", entries.stream().map(entry -> entry.getCitationKey().orElse("")) - .collect(Collectors.toList())); - // Insert bookmark: - String bName = getUniqueReferenceMarkName(keyString, OOBibBase.AUTHORYEAR_PAR); - insertReferenceMark(bName, "tmp", mxDocCursor, true, style); - names.set(piv + 1, bName); - madeModifications = true; - } - piv++; - } - if (madeModifications) { - updateSortedReferenceMarks(); - refreshCiteMarkers(databases, style); - } - } - - /** - * Do the opposite of combineCiteMarkers. - * Combined markers are split, with a space inserted between. - */ - public void unCombineCiteMarkers(List databases, OOBibStyle style) - throws IOException, WrappedTargetException, NoSuchElementException, IllegalArgumentException, - UndefinedCharacterFormatException, UnknownPropertyException, PropertyVetoException, CreationException, - BibEntryNotFoundException { - XNameAccess nameAccess = getReferenceMarks(); - List names = getSortedReferenceMarks(nameAccess); - - final XTextRangeCompare compare = UnoRuntime.queryInterface(XTextRangeCompare.class, text); - - int pivot = 0; - boolean madeModifications = false; - while (pivot < (names.size())) { - XTextRange range1 = UnoRuntime.queryInterface(XTextContent.class, nameAccess.getByName(names.get(pivot))) - .getAnchor(); - - XTextCursor textCursor = range1.getText().createTextCursorByRange(range1); - - // If we are supposed to set character format for citations, test this before - // making any changes. This way we can throw an exception before any reference - // marks are removed, preventing damage to the user's document: - if (style.isFormatCitations()) { - XPropertySet xCursorProps = UnoRuntime.queryInterface(XPropertySet.class, textCursor); - String charStyle = style.getCitationCharacterFormat(); - try { - xCursorProps.setPropertyValue(CHAR_STYLE_NAME, charStyle); - } catch (UnknownPropertyException | PropertyVetoException | IllegalArgumentException | - WrappedTargetException ex) { - // Setting the character format failed, so we throw an exception that - // will result in an error message for the user: - throw new UndefinedCharacterFormatException(charStyle); - } - } - - List keys = parseRefMarkName(names.get(pivot)); - if (keys.size() > 1) { - removeReferenceMark(names.get(pivot)); - - // Insert bookmark for each key - int last = keys.size() - 1; - int i = 0; - for (String key : keys) { - String newName = getUniqueReferenceMarkName(key, OOBibBase.AUTHORYEAR_PAR); - insertReferenceMark(newName, "tmp", textCursor, true, style); - textCursor.collapseToEnd(); - if (i != last) { - textCursor.setString(" "); - textCursor.collapseToEnd(); - } - i++; - } - madeModifications = true; - } - pivot++; - } - if (madeModifications) { - updateSortedReferenceMarks(); - refreshCiteMarkers(databases, style); - } - } - - public BibDatabase generateDatabase(List databases) - throws NoSuchElementException, WrappedTargetException { - BibDatabase resultDatabase = new BibDatabase(); - List cited = findCitedKeys(); - List entriesToInsert = new ArrayList<>(); - - // For each cited key - for (String key : cited) { - // Loop through the available databases - for (BibDatabase loopDatabase : databases) { - Optional entry = loopDatabase.getEntryByCitationKey(key); - // If entry found - if (entry.isPresent()) { - BibEntry clonedEntry = (BibEntry) entry.get().clone(); - // Insert a copy of the entry - entriesToInsert.add(clonedEntry); - // Check if the cloned entry has a crossref field - clonedEntry.getField(StandardField.CROSSREF).ifPresent(crossref -> { - // If the crossref entry is not already in the database - if (!resultDatabase.getEntryByCitationKey(crossref).isPresent()) { - // Add it if it is in the current library - loopDatabase.getEntryByCitationKey(crossref).ifPresent(entriesToInsert::add); - } - }); - - // Be happy with the first found BibEntry and move on to next key - break; - } - } - } - resultDatabase.insertEntries(entriesToInsert); - return resultDatabase; - } - - private static class ComparableMark implements Comparable { - - private final String name; - private final Point position; - - public ComparableMark(String name, Point position) { - this.name = name; - this.position = position; - } - - @Override - public int compareTo(ComparableMark other) { - if (position.Y == other.position.Y) { - return position.X - other.position.X; - } else { - return position.Y - other.position.Y; - } - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (o instanceof ComparableMark) { - ComparableMark other = (ComparableMark) o; - return (this.position.X == other.position.X) && (this.position.Y == other.position.Y) - && Objects.equals(this.name, other.name); - } - return false; - } - - public String getName() { - return name; - } - - @Override - public int hashCode() { - return Objects.hash(position, name); - } - } - - private class DocumentTitleViewModel { - - private final XTextDocument xTextDocument; - private final String description; - - public DocumentTitleViewModel(XTextDocument xTextDocument) { - this.xTextDocument = xTextDocument; - this.description = getDocumentTitle(xTextDocument).orElse(""); - } - - public XTextDocument getXtextDocument() { - return xTextDocument; - } - - @Override - public String toString() { - return description; - } - } -} diff --git a/src/main/java/org/jabref/gui/openoffice/UndefinedCharacterFormatException.java b/src/main/java/org/jabref/gui/openoffice/UndefinedCharacterFormatException.java deleted file mode 100644 index 4ab29ca2fa5..00000000000 --- a/src/main/java/org/jabref/gui/openoffice/UndefinedCharacterFormatException.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.jabref.gui.openoffice; - -/** - * Exception used to indicate that the plugin attempted to set a character format that is - * not defined in the current OpenOffice document. - */ -class UndefinedCharacterFormatException extends Exception { - - private final String formatName; - - public UndefinedCharacterFormatException(String formatName) { - super(); - this.formatName = formatName; - } - - public String getFormatName() { - return formatName; - } -} diff --git a/src/main/java/org/jabref/logic/openoffice/OOUtil.java b/src/main/java/org/jabref/logic/openoffice/OOUtil.java deleted file mode 100644 index 9efab82773c..00000000000 --- a/src/main/java/org/jabref/logic/openoffice/OOUtil.java +++ /dev/null @@ -1,285 +0,0 @@ -package org.jabref.logic.openoffice; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.jabref.architecture.AllowedToUseAwt; -import org.jabref.logic.layout.Layout; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.Field; -import org.jabref.model.entry.field.UnknownField; - -import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.beans.XPropertySet; -import com.sun.star.lang.WrappedTargetException; -import com.sun.star.text.ControlCharacter; -import com.sun.star.text.XParagraphCursor; -import com.sun.star.text.XText; -import com.sun.star.text.XTextCursor; -import com.sun.star.uno.UnoRuntime; - -/** - * Utility methods for processing OO Writer documents. - */ -@AllowedToUseAwt("Requires AWT for changing document properties") -public class OOUtil { - - private static final String CHAR_STRIKEOUT = "CharStrikeout"; - private static final String CHAR_UNDERLINE = "CharUnderline"; - private static final String PARA_STYLE_NAME = "ParaStyleName"; - private static final String CHAR_CASE_MAP = "CharCaseMap"; - private static final String CHAR_POSTURE = "CharPosture"; - private static final String CHAR_WEIGHT = "CharWeight"; - private static final String CHAR_ESCAPEMENT_HEIGHT = "CharEscapementHeight"; - private static final String CHAR_ESCAPEMENT = "CharEscapement"; - - public enum Formatting { - BOLD, - ITALIC, - SMALLCAPS, - SUPERSCRIPT, - SUBSCRIPT, - UNDERLINE, - STRIKEOUT, - MONOSPACE - } - - private static final Pattern HTML_TAG = Pattern.compile(""); - - private static final Field UNIQUEFIER_FIELD = new UnknownField("uniq"); - - private OOUtil() { - // Just to hide the public constructor - } - - /** - * Insert a reference, formatted using a Layout, at the position of a given cursor. - * - * @param text The text to insert in. - * @param cursor The cursor giving the insert location. - * @param layout The Layout to format the reference with. - * @param parStyle The name of the paragraph style to use. - * @param entry The entry to insert. - * @param database The database the entry belongs to. - * @param uniquefier Uniqiefier letter, if any, to append to the entry's year. - */ - public static void insertFullReferenceAtCurrentLocation(XText text, XTextCursor cursor, - Layout layout, String parStyle, BibEntry entry, BibDatabase database, String uniquefier) - throws UndefinedParagraphFormatException, UnknownPropertyException, PropertyVetoException, - WrappedTargetException, IllegalArgumentException { - - // Backup the value of the uniq field, just in case the entry already has it: - Optional oldUniqVal = entry.getField(UNIQUEFIER_FIELD); - - // Set the uniq field with the supplied uniquefier: - if (uniquefier == null) { - entry.clearField(UNIQUEFIER_FIELD); - } else { - entry.setField(UNIQUEFIER_FIELD, uniquefier); - } - - // Do the layout for this entry: - String formattedText = layout.doLayout(entry, database); - - // Afterwards, reset the old value: - if (oldUniqVal.isPresent()) { - entry.setField(UNIQUEFIER_FIELD, oldUniqVal.get()); - } else { - entry.clearField(UNIQUEFIER_FIELD); - } - - // Insert the formatted text: - OOUtil.insertOOFormattedTextAtCurrentLocation(text, cursor, formattedText, parStyle); - } - - /** - * Insert a text with formatting indicated by HTML-like tags, into a text at the position given by a cursor. - * - * @param text The text to insert in. - * @param cursor The cursor giving the insert location. - * @param lText The marked-up text to insert. - * @param parStyle The name of the paragraph style to use. - * @throws WrappedTargetException - * @throws PropertyVetoException - * @throws UnknownPropertyException - * @throws IllegalArgumentException - */ - public static void insertOOFormattedTextAtCurrentLocation(XText text, XTextCursor cursor, String lText, - String parStyle) throws UndefinedParagraphFormatException, UnknownPropertyException, PropertyVetoException, - WrappedTargetException, IllegalArgumentException { - - XParagraphCursor parCursor = UnoRuntime.queryInterface( - XParagraphCursor.class, cursor); - XPropertySet props = UnoRuntime.queryInterface( - XPropertySet.class, parCursor); - - try { - props.setPropertyValue(PARA_STYLE_NAME, parStyle); - } catch (com.sun.star.lang.IllegalArgumentException ex) { - throw new UndefinedParagraphFormatException(parStyle); - } - - List formatting = new ArrayList<>(); - // We need to extract formatting. Use a simple regexp search iteration: - int piv = 0; - Matcher m = OOUtil.HTML_TAG.matcher(lText); - while (m.find()) { - String currentSubstring = lText.substring(piv, m.start()); - if (!currentSubstring.isEmpty()) { - OOUtil.insertTextAtCurrentLocation(text, cursor, currentSubstring, formatting); - } - String tag = m.group(); - // Handle tags: - if ("".equals(tag)) { - formatting.add(Formatting.BOLD); - } else if ("".equals(tag)) { - formatting.remove(Formatting.BOLD); - } else if ("".equals(tag) || "".equals(tag)) { - formatting.add(Formatting.ITALIC); - } else if ("".equals(tag) || "".equals(tag)) { - formatting.remove(Formatting.ITALIC); - } else if ("".equals(tag)) { - formatting.add(Formatting.MONOSPACE); - } else if ("".equals(tag)) { - formatting.remove(Formatting.MONOSPACE); - } else if ("".equals(tag)) { - formatting.add(Formatting.SMALLCAPS); - } else if ("".equals(tag)) { - formatting.remove(Formatting.SMALLCAPS); - } else if ("".equals(tag)) { - formatting.add(Formatting.SUPERSCRIPT); - } else if ("".equals(tag)) { - formatting.remove(Formatting.SUPERSCRIPT); - } else if ("".equals(tag)) { - formatting.add(Formatting.SUBSCRIPT); - } else if ("".equals(tag)) { - formatting.remove(Formatting.SUBSCRIPT); - } else if ("".equals(tag)) { - formatting.add(Formatting.UNDERLINE); - } else if ("".equals(tag)) { - formatting.remove(Formatting.UNDERLINE); - } else if ("".equals(tag)) { - formatting.add(Formatting.STRIKEOUT); - } else if ("".equals(tag)) { - formatting.remove(Formatting.STRIKEOUT); - } - - piv = m.end(); - } - - if (piv < lText.length()) { - OOUtil.insertTextAtCurrentLocation(text, cursor, lText.substring(piv), formatting); - } - - cursor.collapseToEnd(); - } - - public static void insertParagraphBreak(XText text, XTextCursor cursor) throws IllegalArgumentException { - text.insertControlCharacter(cursor, ControlCharacter.PARAGRAPH_BREAK, true); - cursor.collapseToEnd(); - } - - public static void insertTextAtCurrentLocation(XText text, XTextCursor cursor, String string, - List formatting) - throws UnknownPropertyException, PropertyVetoException, WrappedTargetException, - IllegalArgumentException { - text.insertString(cursor, string, true); - // Access the property set of the cursor, and set the currently selected text - // (which is the string we just inserted) to be bold - XPropertySet xCursorProps = UnoRuntime.queryInterface( - XPropertySet.class, cursor); - if (formatting.contains(Formatting.BOLD)) { - xCursorProps.setPropertyValue(CHAR_WEIGHT, - com.sun.star.awt.FontWeight.BOLD); - } else { - xCursorProps.setPropertyValue(CHAR_WEIGHT, - com.sun.star.awt.FontWeight.NORMAL); - } - - if (formatting.contains(Formatting.ITALIC)) { - xCursorProps.setPropertyValue(CHAR_POSTURE, - com.sun.star.awt.FontSlant.ITALIC); - } else { - xCursorProps.setPropertyValue(CHAR_POSTURE, - com.sun.star.awt.FontSlant.NONE); - } - - if (formatting.contains(Formatting.SMALLCAPS)) { - xCursorProps.setPropertyValue(CHAR_CASE_MAP, - com.sun.star.style.CaseMap.SMALLCAPS); - } else { - xCursorProps.setPropertyValue(CHAR_CASE_MAP, - com.sun.star.style.CaseMap.NONE); - } - - // TODO: the tag doesn't work - /* - if (formatting.contains(Formatting.MONOSPACE)) { - xCursorProps.setPropertyValue("CharFontPitch", - com.sun.star.awt.FontPitch.FIXED); - } - else { - xCursorProps.setPropertyValue("CharFontPitch", - com.sun.star.awt.FontPitch.VARIABLE); - } */ - if (formatting.contains(Formatting.SUBSCRIPT)) { - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT, - (byte) -101); - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT_HEIGHT, - (byte) 58); - } else if (formatting.contains(Formatting.SUPERSCRIPT)) { - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT, - (byte) 101); - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT_HEIGHT, - (byte) 58); - } else { - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT, - (byte) 0); - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT_HEIGHT, - (byte) 100); - } - - if (formatting.contains(Formatting.UNDERLINE)) { - xCursorProps.setPropertyValue(CHAR_UNDERLINE, com.sun.star.awt.FontUnderline.SINGLE); - } else { - xCursorProps.setPropertyValue(CHAR_UNDERLINE, com.sun.star.awt.FontUnderline.NONE); - } - - if (formatting.contains(Formatting.STRIKEOUT)) { - xCursorProps.setPropertyValue(CHAR_STRIKEOUT, com.sun.star.awt.FontStrikeout.SINGLE); - } else { - xCursorProps.setPropertyValue(CHAR_STRIKEOUT, com.sun.star.awt.FontStrikeout.NONE); - } - cursor.collapseToEnd(); - } - - public static void insertTextAtCurrentLocation(XText text, XTextCursor cursor, String string, String parStyle) - throws WrappedTargetException, PropertyVetoException, UnknownPropertyException, - UndefinedParagraphFormatException { - text.insertString(cursor, string, true); - XParagraphCursor parCursor = UnoRuntime.queryInterface( - XParagraphCursor.class, cursor); - // Access the property set of the cursor, and set the currently selected text - // (which is the string we just inserted) to be bold - XPropertySet props = UnoRuntime.queryInterface( - XPropertySet.class, parCursor); - try { - props.setPropertyValue(PARA_STYLE_NAME, parStyle); - } catch (IllegalArgumentException ex) { - throw new UndefinedParagraphFormatException(parStyle); - } - cursor.collapseToEnd(); - } - - public static Object getProperty(Object o, String property) - throws UnknownPropertyException, WrappedTargetException { - XPropertySet props = UnoRuntime.queryInterface( - XPropertySet.class, o); - return props.getPropertyValue(property); - } -} diff --git a/src/main/java/org/jabref/logic/openoffice/UndefinedBibtexEntry.java b/src/main/java/org/jabref/logic/openoffice/UndefinedBibtexEntry.java deleted file mode 100644 index 8a1a7cf5e8f..00000000000 --- a/src/main/java/org/jabref/logic/openoffice/UndefinedBibtexEntry.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.jabref.logic.openoffice; - -import org.jabref.logic.openoffice.style.OOBibStyle; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.StandardField; - -/** - * Subclass of BibEntry for representing entries referenced in a document that can't be found in JabRef's current database. - */ -public class UndefinedBibtexEntry extends BibEntry { - - private final String key; - - public UndefinedBibtexEntry(String key) { - this.key = key; - setField(StandardField.AUTHOR, OOBibStyle.UNDEFINED_CITATION_MARKER); - } - - public String getKey() { - return key; - } -} diff --git a/src/main/java/org/jabref/logic/openoffice/UndefinedParagraphFormatException.java b/src/main/java/org/jabref/logic/openoffice/UndefinedParagraphFormatException.java deleted file mode 100644 index 361f8d44f54..00000000000 --- a/src/main/java/org/jabref/logic/openoffice/UndefinedParagraphFormatException.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.jabref.logic.openoffice; - -/** - * Exception used to indicate that the plugin attempted to set a paragraph format that is not defined in the current OpenOffice document. - */ -public class UndefinedParagraphFormatException extends Exception { - - private final String formatName; - - public UndefinedParagraphFormatException(String formatName) { - super(); - this.formatName = formatName; - } - - public String getFormatName() { - return formatName; - } -} diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index 113cef246e2..0d81bdbd024 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -25,11 +25,6 @@ import org.jabref.logic.layout.LayoutFormatter; import org.jabref.logic.layout.LayoutFormatterPreferences; import org.jabref.logic.layout.LayoutHelper; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.Author; -import org.jabref.model.entry.AuthorList; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.FieldFactory; import org.jabref.model.entry.field.OrFields; import org.jabref.model.entry.field.StandardField; @@ -44,7 +39,6 @@ import org.jabref.model.openoffice.style.NonUniqueCitationMarker; import org.jabref.model.openoffice.style.PageInfo; import org.jabref.model.openoffice.util.OOListUtil; -import org.jabref.model.strings.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -447,365 +441,6 @@ public Layout getReferenceFormat(EntryType type) { } } - /* begin_old */ - /** - * Format a number-based citation marker for the given number. - * - * @param number The citation numbers. - * @return The text for the citation. - */ - public String getNumCitationMarker(List number, int minGroupingCount, boolean inList) { - String bracketBefore = getStringCitProperty(BRACKET_BEFORE); - if (inList && (citProperties.containsKey(BRACKET_BEFORE_IN_LIST))) { - bracketBefore = getStringCitProperty(BRACKET_BEFORE_IN_LIST); - } - String bracketAfter = getStringCitProperty(BRACKET_AFTER); - if (inList && (citProperties.containsKey(BRACKET_AFTER_IN_LIST))) { - bracketAfter = getStringCitProperty(BRACKET_AFTER_IN_LIST); - } - // Sort the numbers: - List lNum = new ArrayList<>(number); - Collections.sort(lNum); - StringBuilder sb = new StringBuilder(bracketBefore); - int combineFrom = -1; - int written = 0; - for (int i = 0; i < lNum.size(); i++) { - int i1 = lNum.get(i); - if (combineFrom < 0) { - // Check if next entry is the next in the ref list: - if ((i < (lNum.size() - 1)) && (lNum.get(i + 1) == (i1 + 1)) && (i1 > 0)) { - combineFrom = i1; - } else { - // Add single entry: - if (i > 0) { - sb.append(getStringCitProperty(CITATION_SEPARATOR)); - } - sb.append(lNum.get(i) > 0 ? String.valueOf(lNum.get(i)) : OOBibStyle.UNDEFINED_CITATION_MARKER); - written++; - } - } else { - // We are building a list of combined entries. - // Check if it ends here: - if ((i == (lNum.size() - 1)) || (lNum.get(i + 1) != (i1 + 1))) { - if (written > 0) { - sb.append(getStringCitProperty(CITATION_SEPARATOR)); - } - if ((minGroupingCount > 0) && (((i1 + 1) - combineFrom) >= minGroupingCount)) { - sb.append(combineFrom); - sb.append(getStringCitProperty(GROUPED_NUMBERS_SEPARATOR)); - sb.append(i1); - written++; - } else { - // Either we should never group, or there aren't enough - // entries in this case to group. Output all: - for (int jj = combineFrom; jj <= i1; jj++) { - sb.append(jj); - if (jj < i1) { - sb.append(getStringCitProperty(CITATION_SEPARATOR)); - } - written++; - } - } - combineFrom = -1; - } - // If it doesn't end here, just keep iterating. - } - } - sb.append(bracketAfter); - return sb.toString(); - } - /* end_old */ - - /* begin_old */ - /** - * Format the marker for the in-text citation according to this BIB style. Uniquefier letters are added as - * provided by the uniquefiers argument. If successive entries within the citation are uniquefied from each other, - * this method will perform a grouping of these entries. - * - * @param entries The list of JabRef BibEntry providing the data. - * @param database A map of BibEntry-BibDatabase pairs. - * @param inParenthesis Signals whether a parenthesized citation or an in-text citation is wanted. - * @param uniquefiers Strings to add behind the year for each entry in case it's needed to separate similar - * entries. - * @param unlimAuthors Boolean for each entry. If true, we should not use "et al" formatting regardless - * of the number of authors. Can be null to indicate that no entries should have unlimited names. - * @return The formatted citation. - */ - public String getCitationMarker(List entries, Map database, boolean inParenthesis, - String[] uniquefiers, int[] unlimAuthors) { - // Look for groups of uniquefied entries that should be combined in the output. - // E.g. (Olsen, 2005a, b) should be output instead of (Olsen, 2005a; Olsen, 2005b). - int piv = -1; - String tmpMarker = null; - if (uniquefiers != null) { - for (int i = 0; i < uniquefiers.length; i++) { - - if ((uniquefiers[i] == null) || uniquefiers[i].isEmpty()) { - // This entry has no uniquefier. - // Check if we just passed a group of more than one entry with uniquefier: - if ((piv > -1) && (i > (piv + 1))) { - // Do the grouping: - group(entries, uniquefiers, piv, i - 1); - } - - piv = -1; - } else { - BibEntry currentEntry = entries.get(i); - if (piv == -1) { - piv = i; - tmpMarker = getAuthorYearParenthesisMarker(Collections.singletonList(currentEntry), database, - null, unlimAuthors); - } else { - // See if this entry can go into a group with the previous one: - String thisMarker = getAuthorYearParenthesisMarker(Collections.singletonList(currentEntry), - database, null, unlimAuthors); - - String authorField = getStringCitProperty(AUTHOR_FIELD); - int maxAuthors = getIntCitProperty(MAX_AUTHORS); - String author = getCitationMarkerField(currentEntry, database.get(currentEntry), - authorField); - AuthorList al = AuthorList.parse(author); - int prevALim = unlimAuthors[i - 1]; // i always at least 1 here - if (!thisMarker.equals(tmpMarker) - || ((al.getNumberOfAuthors() > maxAuthors) && (unlimAuthors[i] != prevALim))) { - // No match. Update piv to exclude the previous entry. But first check if the - // previous entry was part of a group: - if ((piv > -1) && (i > (piv + 1))) { - // Do the grouping: - group(entries, uniquefiers, piv, i - 1); - } - tmpMarker = thisMarker; - piv = i; - } - } - } - - } - // Finished with the loop. See if the last entries form a group: - if (piv >= 0) { - // Do the grouping: - group(entries, uniquefiers, piv, uniquefiers.length - 1); - } - } - - if (inParenthesis) { - return getAuthorYearParenthesisMarker(entries, database, uniquefiers, unlimAuthors); - } else { - return getAuthorYearInTextMarker(entries, database, uniquefiers, unlimAuthors); - } - } - /* end_old */ - - /* begin_old */ - /** - * Modify entry and uniquefier arrays to facilitate a grouped presentation of uniquefied entries. - * - * @param entries The entry array. - * @param uniquefiers The uniquefier array. - * @param from The first index to group (inclusive) - * @param to The last index to group (inclusive) - */ - private void group(List entries, String[] uniquefiers, int from, int to) { - String separator = getStringCitProperty(UNIQUEFIER_SEPARATOR); - StringBuilder sb = new StringBuilder(uniquefiers[from]); - for (int i = from + 1; i <= to; i++) { - sb.append(separator); - sb.append(uniquefiers[i]); - entries.set(i, null); - } - uniquefiers[from] = sb.toString(); - } - /* end_old */ - - /* begin_old */ - /** - * This method produces (Author, year) style citation strings in many different forms. - * - * @param entries The list of BibEntry to get fields from. - * @param database A map of BibEntry-BibDatabase pairs. - * @param uniquifiers Optional parameter to separate similar citations. Elements can be null if not needed. - * @return The formatted citation. - */ - private String getAuthorYearParenthesisMarker(List entries, Map database, - String[] uniquifiers, int[] unlimAuthors) { - - String authorField = getStringCitProperty(AUTHOR_FIELD); // The bibtex field providing author names, e.g. "author" or "editor". - int maxA = getIntCitProperty(MAX_AUTHORS); // The maximum number of authors to write out in full without using etal. Set to - // -1 to always write out all authors. - String yearSep = getStringCitProperty(YEAR_SEPARATOR); // The String to separate authors from year, e.g. "; ". - String startBrace = getStringCitProperty(BRACKET_BEFORE); // The opening parenthesis. - String endBrace = getStringCitProperty(BRACKET_AFTER); // The closing parenthesis. - String citationSeparator = getStringCitProperty(CITATION_SEPARATOR); // The String to separate citations from each other. - String yearField = getStringCitProperty(YEAR_FIELD); // The bibtex field providing the year, e.g. "year". - String andString = getStringCitProperty(AUTHOR_LAST_SEPARATOR); // The String to add between the two last author names, e.g. " & ". - StringBuilder sb = new StringBuilder(startBrace); - for (int j = 0; j < entries.size(); j++) { - BibEntry currentEntry = entries.get(j); - - // Check if this entry has been nulled due to grouping with the previous entry(ies): - if (currentEntry == null) { - continue; - } - - if (j > 0) { - sb.append(citationSeparator); - } - - BibDatabase currentDatabase = database.get(currentEntry); - int unlimA = unlimAuthors == null ? -1 : unlimAuthors[j]; - int maxAuthors = unlimA > 0 ? unlimA : maxA; - - String author = getCitationMarkerField(currentEntry, currentDatabase, authorField); - String authorString = createAuthorList(author, maxAuthors, andString, yearSep); - sb.append(authorString); - String year = getCitationMarkerField(currentEntry, currentDatabase, yearField); - if (year != null) { - sb.append(year); - } - if ((uniquifiers != null) && (uniquifiers[j] != null)) { - sb.append(uniquifiers[j]); - } - } - sb.append(endBrace); - return sb.toString(); - } - /* end_old */ - - /* begin_old */ - /** - * This method produces "Author (year)" style citation strings in many different forms. - * - * @param entries The list of BibEntry to get fields from. - * @param database A map of BibEntry-BibDatabase pairs. - * @param uniquefiers Optional parameters to separate similar citations. Can be null if not needed. - * @return The formatted citation. - */ - private String getAuthorYearInTextMarker(List entries, Map database, - String[] uniquefiers, - int[] unlimAuthors) { - String authorField = getStringCitProperty(AUTHOR_FIELD); // The bibtex field providing author names, e.g. "author" or "editor". - int maxA = getIntCitProperty(MAX_AUTHORS); // The maximum number of authors to write out in full without using etal. Set to - // -1 to always write out all authors. - String yearSep = getStringCitProperty(IN_TEXT_YEAR_SEPARATOR); // The String to separate authors from year, e.g. "; ". - String startBrace = getStringCitProperty(BRACKET_BEFORE); // The opening parenthesis. - String endBrace = getStringCitProperty(BRACKET_AFTER); // The closing parenthesis. - String citationSeparator = getStringCitProperty(CITATION_SEPARATOR); // The String to separate citations from each other. - String yearField = getStringCitProperty(YEAR_FIELD); // The bibtex field providing the year, e.g. "year". - String andString = getStringCitProperty(AUTHOR_LAST_SEPARATOR_IN_TEXT); // The String to add between the two last author names, e.g. " & ". - - if (andString == null) { - // Use the default one if no explicit separator for text is defined - andString = getStringCitProperty(AUTHOR_LAST_SEPARATOR); - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < entries.size(); i++) { - BibEntry currentEntry = entries.get(i); - - // Check if this entry has been nulled due to grouping with the previous entry(ies): - if (currentEntry == null) { - continue; - } - - BibDatabase currentDatabase = database.get(currentEntry); - int unlimA = unlimAuthors == null ? -1 : unlimAuthors[i]; - int maxAuthors = unlimA > 0 ? unlimA : maxA; - - if (i > 0) { - sb.append(citationSeparator); - } - String author = getCitationMarkerField(currentEntry, currentDatabase, authorField); - String authorString = createAuthorList(author, maxAuthors, andString, yearSep); - sb.append(authorString); - sb.append(startBrace); - String year = getCitationMarkerField(currentEntry, currentDatabase, yearField); - if (year != null) { - sb.append(year); - } - if ((uniquefiers != null) && (uniquefiers[i] != null)) { - sb.append(uniquefiers[i]); - } - sb.append(endBrace); - } - return sb.toString(); - - } - /* end_old */ - - /* begin_old */ - /* moved to OOBibStyleGetCitationMarker */ - /** - * This method looks up a field for an entry in a database. Any number of backup fields can be used - * if the primary field is empty. - * - * @param entry The entry. - * @param database The database the entry belongs to. - * @param fields The field, or succession of fields, to look up. If backup fields are needed, separate - * field names by /. E.g. to use "author" with "editor" as backup, specify StandardField.orFields(StandardField.AUTHOR, StandardField.EDITOR). - * @return The resolved field content, or an empty string if the field(s) were empty. - */ - private String getCitationMarkerField(BibEntry entry, BibDatabase database, String fields) { - Objects.requireNonNull(entry, "Entry cannot be null"); - Objects.requireNonNull(database, "database cannot be null"); - - Set authorFields = FieldFactory.parseOrFields(getStringCitProperty(AUTHOR_FIELD)); - for (Field field : FieldFactory.parseOrFields(fields)) { - Optional content = entry.getResolvedFieldOrAlias(field, database); - - if ((content.isPresent()) && !content.get().trim().isEmpty()) { - if (authorFields.contains(field) && StringUtil.isInCurlyBrackets(content.get())) { - return "{" + fieldFormatter.format(content.get()) + "}"; - } - return fieldFormatter.format(content.get()); - } - } - // No luck? Return an empty string: - return ""; - } - /* end_old */ - - /* begin_old */ - /* moved to OOBibStyleGetCitationMarker */ - /** - * Look up the nth author and return the proper last name for citation markers. - * - * @param al The author list. - * @param number The number of the author to return. - * @return The author name, or an empty String if inapplicable. - */ - private String getAuthorLastName(AuthorList al, int number) { - StringBuilder sb = new StringBuilder(); - - if (al.getNumberOfAuthors() > number) { - Author a = al.getAuthor(number); - a.getVon().filter(von -> !von.isEmpty()).ifPresent(von -> sb.append(von).append(' ')); - sb.append(a.getLast().orElse("")); - } - - return sb.toString(); - } - /* end_old */ - - /* begin_old */ - /* to be removed */ - /** - * Take a finished citation and insert a string at the end (but inside the end bracket) - * separated by "PageInfoSeparator" - * - * @param citation - * @param pageInfo - * @return - */ - public String insertPageInfo(String citation, String pageInfo) { - String bracketAfter = getStringCitProperty(BRACKET_AFTER); - if (citation.endsWith(bracketAfter)) { - String first = citation.substring(0, citation.length() - bracketAfter.length()); - return first + getStringCitProperty(PAGE_INFO_SEPARATOR) + pageInfo + bracketAfter; - } else { - return citation + getStringCitProperty(PAGE_INFO_SEPARATOR) + pageInfo; - } - } - /* end_old */ - /** * Convenience method for checking the property for whether we use number citations or * author-year citations. @@ -931,39 +566,6 @@ public int hashCode() { return Objects.hash(path, name, citProperties, properties); } - /* begin_old */ - /* moved to OOBibStyleGetCitationMarker as formatAuthorList */ - private String createAuthorList(String author, int maxAuthors, String andString, - String yearSep) { - Objects.requireNonNull(author); - String etAlString = getStringCitProperty(ET_AL_STRING); // The String to represent authors that are not mentioned, e.g. " et al." - String authorSep = getStringCitProperty(AUTHOR_SEPARATOR); // The String to add between author names except the last two, e.g. ", ". - String oxfordComma = getStringCitProperty(OXFORD_COMMA); // The String to put after the second to last author in case of three or more authors - StringBuilder sb = new StringBuilder(); - AuthorList al = AuthorList.parse(author); - if (!al.isEmpty()) { - sb.append(getAuthorLastName(al, 0)); - } - if ((al.getNumberOfAuthors() > 1) && ((al.getNumberOfAuthors() <= maxAuthors) || (maxAuthors < 0))) { - int j = 1; - while (j < (al.getNumberOfAuthors() - 1)) { - sb.append(authorSep); - sb.append(getAuthorLastName(al, j)); - j++; - } - if (al.getNumberOfAuthors() > 2) { - sb.append(oxfordComma); - } - sb.append(andString); - sb.append(getAuthorLastName(al, al.getNumberOfAuthors() - 1)); - } else if (al.getNumberOfAuthors() > maxAuthors) { - sb.append(etAlString); - } - sb.append(yearSep); - return sb.toString(); - } - /* end_old */ - enum BibStyleMode { NONE, LAYOUT, diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 1e9bbace212..8e48a2486bd 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -1022,7 +1022,6 @@ Problem\ modifying\ citation=Problem modifying citation Problem\ collecting\ citations=Problem collecting citations Citation=Citation Connecting...=Connecting... -Could\ not\ resolve\ BibTeX\ entry\ for\ citation\ marker\ '%0'.=Could not resolve BibTeX entry for citation marker '%0'. Select\ style=Select style Journals=Journals Cite=Cite diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java index bf0bdf945a4..8d5da6e4d00 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java @@ -148,6 +148,22 @@ static String getCitationMarker2(OOBibStyle style, pageInfo ); } + static String getCitationMarker2b(OOBibStyle style, + List entries, + Map entryDBMap, + boolean inParenthesis, + String[] uniquefiers, + Boolean[] isFirstAppearanceOfSource, + String[] pageInfo) { + return OOBibStyleTestHelper.getCitationMarker2b(style, + entries, + entryDBMap, + inParenthesis, + uniquefiers, + isFirstAppearanceOfSource, + pageInfo ); + } + /* * end helpers */ @@ -157,35 +173,16 @@ static String getCitationMarker2(OOBibStyle style, void testGetNumCitationMarker() throws IOException { OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, layoutFormatterPreferences); - assertEquals("[1] ", style.getNumCitationMarker(Arrays.asList(1), -1, true)); assertEquals("[1] ", runGetNumCitationMarker2a(style, Arrays.asList(1), -1, true)); - assertEquals("[1]", style.getNumCitationMarker(Arrays.asList(1), -1, false)); assertEquals("[1]", runGetNumCitationMarker2a(style, Arrays.asList(1), -1, false)); assertEquals("[1]", runGetNumCitationMarker2b(style, -1, numEntry("key", 1, null))); - assertEquals("[1] ", style.getNumCitationMarker(Arrays.asList(1), 0, true)); assertEquals("[1] ", runGetNumCitationMarker2a(style, Arrays.asList(1), 0, true)); - /* - * The following tests as for a numeric label for a - * bibliography entry containing more than one numbers. - * We do not need this, not reproduced. - */ - assertEquals("[1-3] ", style.getNumCitationMarker(Arrays.asList(1, 2, 3), 1, true)); - assertEquals("[1; 2; 3] ", style.getNumCitationMarker(Arrays.asList(1, 2, 3), 5, true)); - assertEquals("[1; 2; 3] ", style.getNumCitationMarker(Arrays.asList(1, 2, 3), -1, true)); - assertEquals("[1; 3; 12] ", style.getNumCitationMarker(Arrays.asList(1, 12, 3), 1, true)); - assertEquals("[3-5; 7; 10-12] ", style.getNumCitationMarker(Arrays.asList(12, 7, 3, 4, 11, 10, 5), 1, true)); - - String citation = style.getNumCitationMarker(Arrays.asList(1), -1, false); - assertEquals("[1; pp. 55-56]", style.insertPageInfo(citation, "pp. 55-56")); - CitationMarkerNumericEntry e2 = numEntry("key", 1, "pp. 55-56"); assertEquals(true, e2.getPageInfo().isPresent()); assertEquals("pp. 55-56", e2.getPageInfo().get().asString()); - citation = runGetNumCitationMarker2b(style, -1, e2); - assertEquals("[1; pp. 55-56]", citation); OOBibStyleTestHelper.testGetNumCitationMarkerExtra(style); } @@ -194,26 +191,6 @@ void testGetNumCitationMarker() throws IOException { void testGetNumCitationMarkerUndefined() throws IOException { OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, layoutFormatterPreferences); - /* - * Testing bibliography labels with multiple numbers again. - * Not reproduced. - */ - assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "; 2-4] ", - style.getNumCitationMarker(Arrays.asList(4, 2, 3, 0), 1, true)); - - assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "] ", - style.getNumCitationMarker(Arrays.asList(0), 1, true)); - - assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "; 1-3] ", - style.getNumCitationMarker(Arrays.asList(1, 2, 3, 0), 1, true)); - - assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "; " + OOBibStyle.UNDEFINED_CITATION_MARKER + "; " - + OOBibStyle.UNDEFINED_CITATION_MARKER + "] ", - style.getNumCitationMarker(Arrays.asList(0, 0, 0), 1, true)); - - /* - * We have these instead: - */ // unresolved citations look like [??key] assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "]", @@ -301,28 +278,22 @@ void testGetCitationMarker() throws IOException { assertEquals(3, style.getMaxAuthors()); assertEquals(-1, style.getMaxAuthorsFirst()); - assertEquals("[Boström et al., 2006]", - style.getCitationMarker(Collections.singletonList(entry), entryDBMap, true, null, null)); assertEquals("[Boström et al., 2006]", getCitationMarker2(style, Collections.singletonList(entry), entryDBMap, true, null, null, null)); - assertEquals("Boström et al. [2006]", - style.getCitationMarker(Collections.singletonList(entry), entryDBMap, false, null, new int[]{3})); assertEquals("Boström et al. [2006]", getCitationMarker2(style, Collections.singletonList(entry), entryDBMap, false, null, new Boolean[]{false}, null)); - assertEquals("[Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006]", - style.getCitationMarker(Collections.singletonList(entry), entryDBMap, true, null, new int[]{5})); assertEquals("[Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006]", getCitationMarker2(style, Collections.singletonList(entry), entryDBMap, true, null, - new Boolean[]{true} /* corresponds to -1, not 5 */, + new Boolean[]{true}, null)); } @@ -408,7 +379,6 @@ void testInstitutionAuthorMarker() throws IOException { database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); - assertEquals("[JabRef Development Team, 2016]", style.getCitationMarker(entries, entryDBMap, true, null, null)); assertEquals("[JabRef Development Team, 2016]", getCitationMarker2(style, @@ -429,10 +399,11 @@ void testVonAuthorMarker() throws IOException { entry.setField(StandardField.AUTHOR, "Alpha von Beta"); entry.setField(StandardField.TITLE, "JabRef Manual"); entry.setField(StandardField.YEAR, "2016"); + entry.setCitationKey("a1"); database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); - assertEquals("[von Beta, 2016]", style.getCitationMarker(entries, entryDBMap, true, null, null)); + assertEquals("[von Beta, 2016]", getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); } @Test @@ -447,10 +418,11 @@ void testNullAuthorMarker() throws IOException { BibEntry entry = new BibEntry(); entry.setType(StandardEntryType.Article); entry.setField(StandardField.YEAR, "2016"); + entry.setCitationKey("a1"); database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); - assertEquals("[, 2016]", style.getCitationMarker(entries, entryDBMap, true, null, null)); + assertEquals("[, 2016]", getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); } @Test @@ -465,10 +437,11 @@ void testNullYearMarker() throws IOException { BibEntry entry = new BibEntry(); entry.setType(StandardEntryType.Article); entry.setField(StandardField.AUTHOR, "Alpha von Beta"); + entry.setCitationKey("a1"); database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); - assertEquals("[von Beta, ]", style.getCitationMarker(entries, entryDBMap, true, null, null)); + assertEquals("[von Beta, ]", getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); } @Test @@ -482,10 +455,11 @@ void testEmptyEntryMarker() throws IOException { BibEntry entry = new BibEntry(); entry.setType(StandardEntryType.Article); + entry.setCitationKey("a1"); database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); - assertEquals("[, ]", style.getCitationMarker(entries, entryDBMap, true, null, null)); + assertEquals("[, ]", getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); } @Test @@ -501,17 +475,20 @@ void testGetCitationMarkerInParenthesisUniquefiers() throws IOException { entry1.setField(StandardField.AUTHOR, "Alpha Beta"); entry1.setField(StandardField.TITLE, "Paper 1"); entry1.setField(StandardField.YEAR, "2000"); + entry1.setCitationKey("a1"); entries.add(entry1); database.insertEntry(entry1); BibEntry entry3 = new BibEntry(); entry3.setField(StandardField.AUTHOR, "Alpha Beta"); entry3.setField(StandardField.TITLE, "Paper 2"); entry3.setField(StandardField.YEAR, "2000"); + entry3.setCitationKey("a3"); entries.add(entry3); database.insertEntry(entry3); BibEntry entry2 = new BibEntry(); entry2.setField(StandardField.AUTHOR, "Gamma Epsilon"); entry2.setField(StandardField.YEAR, "2001"); + entry2.setCitationKey("a2"); entries.add(entry2); database.insertEntry(entry2); for (BibEntry entry : database.getEntries()) { @@ -519,9 +496,12 @@ void testGetCitationMarkerInParenthesisUniquefiers() throws IOException { } assertEquals("[Beta, 2000; Beta, 2000; Epsilon, 2001]", - style.getCitationMarker(entries, entryDBMap, true, null, null)); + getCitationMarker2b(style, entries, entryDBMap, true, null, null, null)); assertEquals("[Beta, 2000a,b; Epsilon, 2001]", - style.getCitationMarker(entries, entryDBMap, true, new String[]{"a", "b", ""}, new int[]{1, 1, 1})); + getCitationMarker2(style, entries, entryDBMap, true, + new String[]{"a", "b", ""}, + new Boolean[]{false, false, false}, + null)); } @Test @@ -537,27 +517,33 @@ void testGetCitationMarkerInTextUniquefiers() throws IOException { entry1.setField(StandardField.AUTHOR, "Alpha Beta"); entry1.setField(StandardField.TITLE, "Paper 1"); entry1.setField(StandardField.YEAR, "2000"); + entry1.setCitationKey("a1"); entries.add(entry1); database.insertEntry(entry1); BibEntry entry3 = new BibEntry(); entry3.setField(StandardField.AUTHOR, "Alpha Beta"); entry3.setField(StandardField.TITLE, "Paper 2"); entry3.setField(StandardField.YEAR, "2000"); + entry3.setCitationKey("a3"); entries.add(entry3); database.insertEntry(entry3); BibEntry entry2 = new BibEntry(); entry2.setField(StandardField.AUTHOR, "Gamma Epsilon"); entry2.setField(StandardField.YEAR, "2001"); entries.add(entry2); + entry2.setCitationKey("a2"); database.insertEntry(entry2); for (BibEntry entry : database.getEntries()) { entryDBMap.put(entry, database); } assertEquals("Beta [2000]; Beta [2000]; Epsilon [2001]", - style.getCitationMarker(entries, entryDBMap, false, null, null)); + getCitationMarker2b(style, entries, entryDBMap, false, null, null, null)); assertEquals("Beta [2000a,b]; Epsilon [2001]", - style.getCitationMarker(entries, entryDBMap, false, new String[]{"a", "b", ""}, new int[]{1, 1, 1})); + getCitationMarker2(style, entries, entryDBMap, false, + new String[]{"a", "b", ""}, + new Boolean[]{false, false, false}, + null)); } @Test @@ -573,18 +559,21 @@ void testGetCitationMarkerInParenthesisUniquefiersThreeSameAuthor() throws IOExc entry1.setField(StandardField.AUTHOR, "Alpha Beta"); entry1.setField(StandardField.TITLE, "Paper 1"); entry1.setField(StandardField.YEAR, "2000"); + entry1.setCitationKey("a1"); entries.add(entry1); database.insertEntry(entry1); BibEntry entry2 = new BibEntry(); entry2.setField(StandardField.AUTHOR, "Alpha Beta"); entry2.setField(StandardField.TITLE, "Paper 2"); entry2.setField(StandardField.YEAR, "2000"); + entry2.setCitationKey("a2"); entries.add(entry2); database.insertEntry(entry2); BibEntry entry3 = new BibEntry(); entry3.setField(StandardField.AUTHOR, "Alpha Beta"); entry3.setField(StandardField.TITLE, "Paper 3"); entry3.setField(StandardField.YEAR, "2000"); + entry3.setCitationKey("a3"); entries.add(entry3); database.insertEntry(entry3); for (BibEntry entry : database.getEntries()) { @@ -592,7 +581,10 @@ void testGetCitationMarkerInParenthesisUniquefiersThreeSameAuthor() throws IOExc } assertEquals("[Beta, 2000a,b,c]", - style.getCitationMarker(entries, entryDBMap, true, new String[]{"a", "b", "c"}, new int[]{1, 1, 1})); + getCitationMarker2(style, entries, entryDBMap, true, + new String[]{"a", "b", "c"}, + new Boolean[]{false, false, false}, + null)); } @Test @@ -608,18 +600,21 @@ void testGetCitationMarkerInTextUniquefiersThreeSameAuthor() throws IOException entry1.setField(StandardField.AUTHOR, "Alpha Beta"); entry1.setField(StandardField.TITLE, "Paper 1"); entry1.setField(StandardField.YEAR, "2000"); + entry1.setCitationKey("a1"); entries.add(entry1); database.insertEntry(entry1); BibEntry entry2 = new BibEntry(); entry2.setField(StandardField.AUTHOR, "Alpha Beta"); entry2.setField(StandardField.TITLE, "Paper 2"); entry2.setField(StandardField.YEAR, "2000"); + entry2.setCitationKey("a2"); entries.add(entry2); database.insertEntry(entry2); BibEntry entry3 = new BibEntry(); entry3.setField(StandardField.AUTHOR, "Alpha Beta"); entry3.setField(StandardField.TITLE, "Paper 3"); entry3.setField(StandardField.YEAR, "2000"); + entry3.setCitationKey("a3"); entries.add(entry3); database.insertEntry(entry3); for (BibEntry entry : database.getEntries()) { @@ -627,7 +622,10 @@ void testGetCitationMarkerInTextUniquefiersThreeSameAuthor() throws IOException } assertEquals("Beta [2000a,b,c]", - style.getCitationMarker(entries, entryDBMap, false, new String[]{"a", "b", "c"}, new int[]{1, 1, 1})); + getCitationMarker2(style, entries, entryDBMap, false, + new String[]{"a", "b", "c"}, + new Boolean[]{false, false, false}, + null)); } @Test @@ -681,11 +679,12 @@ void testEmptyStringPropertyAndOxfordComma() throws Exception { entry.setField(StandardField.AUTHOR, "Alpha von Beta and Gamma Epsilon and Ypsilon Tau"); entry.setField(StandardField.TITLE, "JabRef Manual"); entry.setField(StandardField.YEAR, "2016"); + entry.setCitationKey("a1"); database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); assertEquals("von Beta, Epsilon, & Tau, 2016", - style.getCitationMarker(entries, entryDBMap, true, null, null)); + getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); } @Test diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java index c8302030fc6..2bc6e7bb976 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java @@ -185,13 +185,14 @@ static CitationMarkerEntry makeCitationMarkerEntry(BibEntry entry, * Similar to old API. pageInfo is new, and unlimAuthors is * replaced with isFirstAppearanceOfSource */ - static String getCitationMarker2(OOBibStyle style, - List entries, - Map entryDBMap, - boolean inParenthesis, - String[] uniquefiers, - Boolean[] isFirstAppearanceOfSource, - String[] pageInfo) { + static String getCitationMarker2ab(OOBibStyle style, + List entries, + Map entryDBMap, + boolean inParenthesis, + String[] uniquefiers, + Boolean[] isFirstAppearanceOfSource, + String[] pageInfo, + NonUniqueCitationMarker nonunique) { if (uniquefiers == null) { uniquefiers = new String[entries.size()]; Arrays.fill(uniquefiers, null); @@ -216,7 +217,41 @@ static String getCitationMarker2(OOBibStyle style, } return style.createCitationMarker(citationMarkerEntries, inParenthesis, - NonUniqueCitationMarker.THROWS).asString(); + nonunique).asString(); + } + + static String getCitationMarker2(OOBibStyle style, + List entries, + Map entryDBMap, + boolean inParenthesis, + String[] uniquefiers, + Boolean[] isFirstAppearanceOfSource, + String[] pageInfo) { + return getCitationMarker2ab(style, + entries, + entryDBMap, + inParenthesis, + uniquefiers, + isFirstAppearanceOfSource, + pageInfo, + NonUniqueCitationMarker.THROWS); + } + + static String getCitationMarker2b(OOBibStyle style, + List entries, + Map entryDBMap, + boolean inParenthesis, + String[] uniquefiers, + Boolean[] isFirstAppearanceOfSource, + String[] pageInfo) { + return getCitationMarker2ab(style, + entries, + entryDBMap, + inParenthesis, + uniquefiers, + isFirstAppearanceOfSource, + pageInfo, + NonUniqueCitationMarker.FORGIVEN); } /* From 88cab9cfad57b084b332f2d1faef4bedac825125 Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 15:33:58 +0200 Subject: [PATCH 022/103] checkstyle on tests --- .../openoffice/style/OOBibStyleTest.java | 51 ++++++++----------- .../style/OOBibStyleTestHelper.java | 41 ++++----------- 2 files changed, 30 insertions(+), 62 deletions(-) diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java index bf0bdf945a4..03a0b535e34 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java @@ -11,7 +11,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -25,13 +24,10 @@ import org.jabref.model.entry.types.StandardEntryType; import org.jabref.model.entry.types.UnknownEntryType; import org.jabref.model.openoffice.ootext.OOText; -import org.jabref.model.openoffice.style.Citation; -import org.jabref.model.openoffice.style.CitationLookupResult; import org.jabref.model.openoffice.style.CitationMarkerEntry; import org.jabref.model.openoffice.style.CitationMarkerNumericBibEntry; import org.jabref.model.openoffice.style.CitationMarkerNumericEntry; import org.jabref.model.openoffice.style.NonUniqueCitationMarker; -import org.jabref.model.openoffice.style.PageInfo; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -96,7 +92,7 @@ void testNumerical() throws IOException { * begin helpers */ static String runGetNumCitationMarker2a(OOBibStyle style, - List num, int minGroupingCount, boolean inList ) { + List num, int minGroupingCount, boolean inList) { return OOBibStyleTestHelper.runGetNumCitationMarker2a(style, num, minGroupingCount, inList); } @@ -125,7 +121,7 @@ static CitationMarkerEntry makeCitationMarkerEntry(BibEntry entry, database, uniqueLetterQ, pageInfoQ, - isFirstAppearanceOfSource ); + isFirstAppearanceOfSource); } /* @@ -145,14 +141,13 @@ static String getCitationMarker2(OOBibStyle style, inParenthesis, uniquefiers, isFirstAppearanceOfSource, - pageInfo ); + pageInfo); } /* * end helpers */ - @Test void testGetNumCitationMarker() throws IOException { OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, @@ -218,27 +213,27 @@ void testGetNumCitationMarkerUndefined() throws IOException { // unresolved citations look like [??key] assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "]", runGetNumCitationMarker2b(style, 1, - numEntry("key",0,null))); + numEntry("key", 0, null))); // pageInfo is shown for unresolved citations assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "; p1]", runGetNumCitationMarker2b(style, 1, - numEntry("key",0,"p1"))); + numEntry("key", 0, "p1"))); // unresolved citations sorted to the front assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "; 2-4]", runGetNumCitationMarker2b(style, 1, - numEntry("x4",4,""), - numEntry("x2",2,""), - numEntry("x3",3,""), - numEntry("key",0,""))); + numEntry("x4", 4, ""), + numEntry("x2", 2, ""), + numEntry("x3", 3, ""), + numEntry("key", 0, ""))); assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "; 1-3]", runGetNumCitationMarker2b(style, 1, - numEntry("x1",1,""), - numEntry("x2",2,""), - numEntry("y3",3,""), - numEntry("key",0,""))); + numEntry("x1", 1, ""), + numEntry("x2", 2, ""), + numEntry("y3", 3, ""), + numEntry("key", 0, ""))); // multiple unresolved citations are not collapsed assertEquals("[" @@ -246,19 +241,16 @@ void testGetNumCitationMarkerUndefined() throws IOException { + OOBibStyle.UNDEFINED_CITATION_MARKER + "x2" + "; " + OOBibStyle.UNDEFINED_CITATION_MARKER + "x3" + "]", runGetNumCitationMarker2b(style, 1, - numEntry("x1",0,""), - numEntry("x2",0,""), - numEntry("x3",0,""))); + numEntry("x1", 0, ""), + numEntry("x2", 0, ""), + numEntry("x3", 0, ""))); /* * BIBLIOGRAPHY */ - { - CitationMarkerNumericBibEntry x = numBibEntry("key", Optional.empty()); - assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "] ", - style.getNumCitationMarkerForBibliography(x).asString()); - } - + CitationMarkerNumericBibEntry x = numBibEntry("key", Optional.empty()); + assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "] ", + style.getNumCitationMarkerForBibliography(x).asString()); } @Test @@ -280,7 +272,6 @@ void testGetCitProperty() throws IOException { assertTrue(journals.contains("Journal name 1")); } - @Test void testGetCitationMarker() throws IOException { OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, layoutFormatterPreferences); @@ -767,7 +758,7 @@ void testGetCitationMarkerJoinFirst() throws IOException { citationMarkerEntries.add(cm3); assertEquals("[Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006a,b" - +"; Boström, Wäyrynen, Bodén, Beznosov & NotKruchten, 2006c]", + + "; Boström, Wäyrynen, Bodén, Beznosov & NotKruchten, 2006c]", style.createCitationMarker(citationMarkerEntries, true, NonUniqueCitationMarker.THROWS).asString()); @@ -795,7 +786,7 @@ void testGetCitationMarkerJoinFirst() throws IOException { citationMarkerEntries.add(cm3); assertEquals("[Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006a,b" - +"; Boström et al., 2006c]", + + "; Boström et al., 2006c]", style.createCitationMarker(citationMarkerEntries, true, NonUniqueCitationMarker.THROWS).asString()); diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java index c8302030fc6..9fbe9579ccb 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java @@ -1,29 +1,16 @@ package org.jabref.logic.openoffice.style; -import java.io.File; import java.io.IOException; -import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; -import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.jabref.logic.layout.Layout; -import org.jabref.logic.layout.LayoutFormatterPreferences; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.StandardField; -import org.jabref.model.entry.types.StandardEntryType; -import org.jabref.model.entry.types.UnknownEntryType; import org.jabref.model.openoffice.ootext.OOText; import org.jabref.model.openoffice.style.Citation; import org.jabref.model.openoffice.style.CitationLookupResult; @@ -33,15 +20,7 @@ import org.jabref.model.openoffice.style.NonUniqueCitationMarker; import org.jabref.model.openoffice.style.PageInfo; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Answers; - 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.Assertions.assertTrue; -import static org.mockito.Mockito.mock; class OOBibStyleTestHelper { /* @@ -116,7 +95,7 @@ static CitationMarkerNumericBibEntry numBibEntry(String key, Optional n * @param inList true means label for the bibliography */ static String runGetNumCitationMarker2a(OOBibStyle style, - List num, int minGroupingCount, boolean inList ) { + List num, int minGroupingCount, boolean inList) { if (inList) { if (num.size() != 1) { throw new RuntimeException("Numeric label for the bibliography with " @@ -159,7 +138,6 @@ static String runGetNumCitationMarker2b(OOBibStyle style, * end Helpers for testing style.getNumCitationMarker2 */ - /* * begin helper */ @@ -223,21 +201,20 @@ static String getCitationMarker2(OOBibStyle style, * end helper */ - static void testGetNumCitationMarkerExtra(OOBibStyle style) throws IOException { // Identical numeric entries are joined. assertEquals("[1; 2]", runGetNumCitationMarker2b(style, 3, - numEntry("x1",1,null), - numEntry("x2",2,null), - numEntry("x1",2,null), - numEntry("x2",1,null))); + numEntry("x1", 1, null), + numEntry("x2", 2, null), + numEntry("x1", 2, null), + numEntry("x2", 1, null))); // ... unless minGroupingCount <= 0 assertEquals("[1; 1; 2; 2]", runGetNumCitationMarker2b(style, 0, - numEntry("x1",1,null), - numEntry("x2",2,null), - numEntry("x1",2,null), - numEntry("x2",1,null))); + numEntry("x1", 1, null), + numEntry("x2", 2, null), + numEntry("x1", 2, null), + numEntry("x2", 1, null))); // ... or have different pageInfos assertEquals("[1; p1a; 1; p1b; 2; p2; 3]", runGetNumCitationMarker2b(style, 1, From b7aaf2af9be835fac592645787a091338dad3c34 Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 15:39:04 +0200 Subject: [PATCH 023/103] add missing message --- src/main/resources/l10n/JabRef_en.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 0d5281b27a2..c2d0ea46ee7 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2295,6 +2295,7 @@ Custom\ DOI\ URI=Custom DOI URI Customization=Customization Use\ custom\ DOI\ base\ URI\ for\ article\ access=Use custom DOI base URI for article access +Cited\ on\ pages=Cited on pages Unable\ to\ find\ valid\ certification\ path\ to\ requested\ target(%0),\ download\ anyway?=Unable to find valid certification path to requested target(%0), download anyway? Download\ operation\ canceled.=Download operation canceled. From 0fa9a4c03365a15126b79d9cf45e45affd99ce7c Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 11:39:40 +0200 Subject: [PATCH 024/103] add backend --- .../logic/openoffice/backend/Backend52.java | 465 ++++++++++++++++ .../logic/openoffice/backend/Codec52.java | 148 ++++++ .../logic/openoffice/backend/GetContext.java | 87 +++ .../NamedRangeManagerReferenceMark.java | 50 ++ .../backend/NamedRangeReferenceMark.java | 500 ++++++++++++++++++ .../model/openoffice/backend/NamedRange.java | 65 +++ .../openoffice/backend/NamedRangeManager.java | 31 ++ 7 files changed, 1346 insertions(+) create mode 100644 src/main/java/org/jabref/logic/openoffice/backend/Backend52.java create mode 100644 src/main/java/org/jabref/logic/openoffice/backend/Codec52.java create mode 100644 src/main/java/org/jabref/logic/openoffice/backend/GetContext.java create mode 100644 src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java create mode 100644 src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java create mode 100644 src/main/java/org/jabref/model/openoffice/backend/NamedRange.java create mode 100644 src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java new file mode 100644 index 00000000000..d7c1b62086a --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java @@ -0,0 +1,465 @@ +package org.jabref.logic.openoffice.backend; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import org.jabref.model.openoffice.CitationEntry; +import org.jabref.model.openoffice.backend.NamedRange; +import org.jabref.model.openoffice.backend.NamedRangeManager; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.Citation; +import org.jabref.model.openoffice.style.CitationGroup; +import org.jabref.model.openoffice.style.CitationGroupId; +import org.jabref.model.openoffice.style.CitationGroups; +import org.jabref.model.openoffice.style.CitationType; +import org.jabref.model.openoffice.style.OODataModel; +import org.jabref.model.openoffice.style.PageInfo; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoUserDefinedProperty; +import org.jabref.model.openoffice.util.OOListUtil; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Backend52 { + private static final Logger LOGGER = LoggerFactory.getLogger(Backend52.class); + public final OODataModel dataModel; + private final NamedRangeManager citationStorageManager; + private final Map cgidToNamedRange; + + // uses: Codec52 + public Backend52() { + this.dataModel = OODataModel.JabRef52; + this.citationStorageManager = new NamedRangeManagerReferenceMark(); + this.cgidToNamedRange = new HashMap<>(); + } + + /** + * Get reference mark names from the document matching the pattern + * used for JabRef reference mark names. + * + * Note: the names returned are in arbitrary order. + * + */ + public List getJabRefReferenceMarkNames(XTextDocument doc) + throws + NoDocumentException { + List allNames = this.citationStorageManager.nrmGetUsedNames(doc); + return Codec52.filterIsJabRefReferenceMarkName(allNames); + } + + /** + * Names of custom properties belonging to us, but without a + * corresponding reference mark. These can be deleted. + * + * @param citationGroupNames These are the names that are used. + * + */ + private List findUnusedJabrefPropertyNames(XTextDocument doc, + List citationGroupNames) { + + // Collect unused jabrefPropertyNames + Set citationGroupNamesSet = citationGroupNames.stream().collect(Collectors.toSet()); + + List pageInfoThrash = new ArrayList<>(); + List jabrefPropertyNames = + UnoUserDefinedProperty.getListOfNames(doc) + .stream() + .filter(Codec52::isJabRefReferenceMarkName) + .collect(Collectors.toList()); + for (String pn : jabrefPropertyNames) { + if (!citationGroupNamesSet.contains(pn)) { + pageInfoThrash.add(pn); + } + } + return pageInfoThrash; + } + + /** + * @return Optional.empty if all is OK, message text otherwise. + */ + public Optional healthReport(XTextDocument doc) + throws + NoDocumentException { + List pageInfoThrash = + this.findUnusedJabrefPropertyNames(doc, this.getJabRefReferenceMarkNames(doc)); + if (pageInfoThrash.isEmpty()) { + return Optional.empty(); // "Backend52: found no unused pageInfo data"; + } + String msg = + "Backend52: found unused pageInfo data, with names listed below.\n" + + "In LibreOffice you may remove these in [File]/[Properties]/[Custom Properties]\n"; + msg += "" + String.join("\n", pageInfoThrash) + ""; + return Optional.of(msg); + } + + private static void setPageInfoInDataInitial(List citations, Optional pageInfo) { + // attribute to last citation (initially localOrder == storageOrder) + if (citations.size() > 0) { + citations.get(citations.size() - 1).setPageInfo(pageInfo); + } + } + + private static void setPageInfoInData(CitationGroup cg, Optional pageInfo) { + List citations = cg.getCitationsInLocalOrder(); + if (citations.size() > 0) { + citations.get(citations.size() - 1).setPageInfo(pageInfo); + } + } + + private static Optional getPageInfoFromData(CitationGroup cg) { + List citations = cg.getCitationsInLocalOrder(); + if (citations.size() > 0) { + return citations.get(citations.size() - 1).getPageInfo(); + } else { + return Optional.empty(); + } + } + + /** + * We have circular dependency here: backend uses + * class from ... + */ + public CitationGroup readCitationGroupFromDocumentOrThrow(XTextDocument doc, String refMarkName) + throws + WrappedTargetException, + NoDocumentException { + + Optional op = Codec52.parseMarkName(refMarkName); + if (op.isEmpty()) { + throw new IllegalArgumentException("readCitationGroupFromDocumentOrThrow:" + + " found unparsable referenceMarkName"); + } + Codec52.ParsedMarkName ov = op.get(); + CitationGroupId cgid = new CitationGroupId(refMarkName); + List citations = (ov.citationKeys.stream() + .map(Citation::new) + .collect(Collectors.toList())); + + Optional pageInfo = + (UnoUserDefinedProperty.getStringValue(doc, refMarkName) + .map(OOText::fromString)); + pageInfo = PageInfo.normalizePageInfo(pageInfo); + + setPageInfoInDataInitial(citations, pageInfo); + + Optional namedRange = citationStorageManager.nrmGetFromDocument(doc, refMarkName); + + if (namedRange.isEmpty()) { + throw new IllegalArgumentException("readCitationGroupFromDocumentOrThrow:" + + " referenceMarkName is not in the document"); + } + + CitationGroup cg = new CitationGroup(OODataModel.JabRef52, + cgid, + ov.citationType, + citations, + Optional.of(refMarkName)); + this.cgidToNamedRange.put(cgid, namedRange.get()); + return cg; + } + + /** + * Create a reference mark with the given name, at the + * end of position. + * + * On return {@code position} is collapsed, and is after the + * inserted space, or at the end of the reference mark. + * + * @param position Collapsed to its end. + * @param insertSpaceAfter We insert a space after the mark, that + * carries on format of characters from + * the original position. + */ + public CitationGroup createCitationGroup(XTextDocument doc, + List citationKeys, + List> pageInfos, + CitationType citationType, + XTextCursor position, + boolean insertSpaceAfter) + throws + CreationException, + NoDocumentException, + WrappedTargetException, + NotRemoveableException, + PropertyExistException, + PropertyVetoException, + IllegalTypeException { + + Objects.requireNonNull(pageInfos); + if (pageInfos.size() != citationKeys.size()) { + throw new RuntimeException("pageInfos.size != citationKeys.size"); + } + + // Get a new refMarkName + Set usedNames = new HashSet<>(this.citationStorageManager.nrmGetUsedNames(doc)); + String xkey = (citationKeys.stream().collect(Collectors.joining(","))); + String refMarkName = Codec52.getUniqueMarkName(usedNames, xkey, citationType); + + CitationGroupId cgid = new CitationGroupId(refMarkName); + + final int nCitations = citationKeys.size(); + final int last = nCitations - 1; + + // Build citations, add pageInfo to each citation + List citations = new ArrayList<>(nCitations); + for (int i = 0; i < nCitations; i++) { + Citation cit = new Citation(citationKeys.get(i)); + citations.add(cit); + + Optional pageInfo = PageInfo.normalizePageInfo(pageInfos.get(i)); + switch (dataModel) { + case JabRef52: + if (i == last) { + cit.setPageInfo(pageInfo); + } else { + if (pageInfo.isPresent()) { + LOGGER.warn("dataModel JabRef52" + + " only supports pageInfo for the last citation of a group"); + } + } + break; + case JabRef53: + cit.setPageInfo(pageInfo); + break; + } + } + + /* + * Apply to document + */ + boolean withoutBrackets = (citationType == CitationType.INVISIBLE_CIT); + NamedRange namedRange = + this.citationStorageManager.nrmCreate(doc, refMarkName, position, insertSpaceAfter, + withoutBrackets); + + switch (dataModel) { + case JabRef52: + Optional pageInfo = PageInfo.normalizePageInfo(pageInfos.get(last)); + + if (pageInfo.isPresent()) { + String pageInfoString = OOText.toString(pageInfo.get()); + UnoUserDefinedProperty.createStringProperty(doc, refMarkName, pageInfoString); + } else { + // do not inherit from trash + UnoUserDefinedProperty.removeIfExists(doc, refMarkName); + } + CitationGroup cg = new CitationGroup(OODataModel.JabRef52, + cgid, + citationType, citations, + Optional.of(refMarkName)); + this.cgidToNamedRange.put(cgid, namedRange); + return cg; + default: + throw new RuntimeException("Backend52 requires JabRef52 dataModel"); + } + } + + /** + * @return A list with a nullable pageInfo entry for each citation in + * joinableGroups. + * + * TODO: JabRef52 combinePageInfos is not reversible. Should warn + * user to check the result. Or ask what to do. + */ + public static List> + combinePageInfosCommon(OODataModel dataModel, List joinableGroup) { + switch (dataModel) { + case JabRef52: + // collect to cgPageInfos + List> cgPageInfos = OOListUtil.map(joinableGroup, + Backend52::getPageInfoFromData); + + // Try to do something of the cgPageInfos. + String cgPageInfo = (cgPageInfos.stream() + .filter(pi -> pi.isPresent()) + .map(pi -> OOText.toString(pi.get())) + .distinct() + .collect(Collectors.joining("; "))); + + int nCitations = (joinableGroup.stream() + .map(cg -> cg.numberOfCitations()) + .mapToInt(Integer::intValue).sum()); + if ("".equals(cgPageInfo)) { + cgPageInfo = null; + } + return OODataModel.fakePageInfos(cgPageInfo, nCitations); + + case JabRef53: + return (joinableGroup.stream() + .flatMap(cg -> (cg.citationsInStorageOrder.stream() + .map(Citation::getPageInfo))) + .collect(Collectors.toList())); + default: + throw new RuntimeException("unhandled dataModel here"); + } + } + + /** + * + */ + public List> combinePageInfos(List joinableGroup) { + return combinePageInfosCommon(this.dataModel, joinableGroup); + } + + private NamedRange getNamedRangeOrThrow(CitationGroup cg) { + NamedRange namedRange = this.cgidToNamedRange.get(cg.cgid); + if (namedRange == null) { + LOGGER.warn("getNamedRange: could not lookup namedRange"); + throw new RuntimeException("getNamedRange: could not lookup namedRange"); + } + return namedRange; + } + + public void removeCitationGroup(CitationGroup cg, XTextDocument doc) + throws + WrappedTargetException, + NoDocumentException, + NoSuchElementException, + NotRemoveableException, + IllegalTypeException, + PropertyExistException { + + NamedRange namedRange = getNamedRangeOrThrow(cg); + String refMarkName = namedRange.nrGetRangeName(); + namedRange.nrRemoveFromDocument(doc); + UnoUserDefinedProperty.removeIfExists(doc, refMarkName); + this.cgidToNamedRange.remove(cg.cgid); + } + + /** + * + * @return Optional.empty if the reference mark is missing. + * + */ + public Optional getMarkRange(CitationGroup cg, XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + + NamedRange namedRange = getNamedRangeOrThrow(cg); + return namedRange.nrGetMarkRange(doc); + } + + /** + * Cursor for the reference marks as is, not prepared for filling, + * but does not need cleanFillCursorForCitationGroup either. + */ + public Optional getRawCursorForCitationGroup(CitationGroup cg, XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + NamedRange namedRange = getNamedRangeOrThrow(cg); + return namedRange.nrGetRawCursor(doc); + } + + /** + * Must be followed by call to cleanFillCursorForCitationGroup + */ + public XTextCursor getFillCursorForCitationGroup(CitationGroup cg, XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException, + CreationException { + + NamedRange namedRange = getNamedRangeOrThrow(cg); + return namedRange.nrGetFillCursor(doc); + } + + /** To be called after getFillCursorForCitationGroup */ + public void cleanFillCursorForCitationGroup(CitationGroup cg, XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException, + CreationException { + NamedRange namedRange = getNamedRangeOrThrow(cg); + namedRange.nrCleanFillCursor(doc); + } + + public List getCitationEntries(XTextDocument doc, CitationGroups cgs) + throws + UnknownPropertyException, + WrappedTargetException, + NoDocumentException { + + switch (dataModel) { + case JabRef52: + // One context per CitationGroup: Backend52 (DataModel.JabRef52) + // For DataModel.JabRef53 (Backend53) we need one context per Citation + int n = cgs.numberOfCitationGroups(); + List citations = new ArrayList<>(n); + for (CitationGroup cg : cgs.getCitationGroupsUnordered()) { + String name = cg.cgid.citationGroupIdAsString(); + XTextCursor cursor = (this + .getRawCursorForCitationGroup(cg, doc) + .orElseThrow(RuntimeException::new)); + String context = GetContext.getCursorStringWithContext(cursor, 30, 30, true); + Optional pageInfo = (cg.numberOfCitations() > 0 + ? (getPageInfoFromData(cg) + .map(e -> OOText.toString(e))) + : Optional.empty()); + CitationEntry entry = new CitationEntry(name, context, pageInfo); + citations.add(entry); + } + return citations; + case JabRef53: + // xx + throw new RuntimeException("getCitationEntries for JabRef53 is not implemented yet"); + default: + throw new RuntimeException("getCitationEntries: unhandled dataModel "); + } + } + + /* + * Only applies to storage. Citation markers are not changed. + */ + public void applyCitationEntries(XTextDocument doc, List citationEntries) + throws + UnknownPropertyException, + NotRemoveableException, + PropertyExistException, + PropertyVetoException, + IllegalTypeException, + IllegalArgumentException, + NoDocumentException, + WrappedTargetException { + + switch (dataModel) { + case JabRef52: + for (CitationEntry entry : citationEntries) { + Optional pageInfo = entry.getPageInfo().map(OOText::fromString); + pageInfo = PageInfo.normalizePageInfo(pageInfo); + if (pageInfo.isPresent()) { + String name = entry.getRefMarkName(); + UnoUserDefinedProperty.createStringProperty(doc, name, pageInfo.get().asString()); + } + } + break; + case JabRef53: + // xx + throw new RuntimeException("applyCitationEntries for JabRef53 is not implemented yet"); + default: + throw new RuntimeException("applyCitationEntries: unhandled dataModel "); + } + } + +} + diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java new file mode 100644 index 00000000000..352df27cdeb --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java @@ -0,0 +1,148 @@ +package org.jabref.logic.openoffice.backend; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.jabref.model.openoffice.style.CitationType; +import org.jabref.model.openoffice.uno.NoDocumentException; + +/** + * How and what is encoded in a mark names. + * + * - pageInfo does not appear here. It is not encoded in the mark name. + * - Does not depend on the type of marks (reference mark of bookmark) used. + */ +class Codec52 { + private static final String BIB_CITATION = "JR_cite"; + private static final Pattern CITE_PATTERN = + // Pattern.compile(BIB_CITATION + "(\\d*)_(\\d*)_(.*)"); + // citationType is always "1" "2" or "3" + Pattern.compile(BIB_CITATION + "(\\d*)_([123])_(.*)"); + + /** + * This is what we get back from parsing a refMarkName. + * + */ + public static class ParsedMarkName { + /** "", "0", "1" ... */ + public final String i; + /** in-text-citation type */ + public final CitationType citationType; + /** Citation keys embedded in the reference mark. */ + public final List citationKeys; + + ParsedMarkName(String i, CitationType citationType, List citationKeys) { + Objects.requireNonNull(i); + Objects.requireNonNull(citationKeys); + this.i = i; + this.citationType = citationType; + this.citationKeys = citationKeys; + } + } + + /* + * Integer representation was written into the document in + * JabRef52, keep it for compatibility. + */ + public static CitationType CitationTypeFromInt(int i) { + switch (i) { + case 1: + return CitationType.AUTHORYEAR_PAR; + case 2: + return CitationType.AUTHORYEAR_INTEXT; + case 3: + return CitationType.INVISIBLE_CIT; + default: + throw new RuntimeException("Invalid CitationType code"); + } + } + + public static int CitationTypeToInt(CitationType i) { + switch (i) { + case AUTHORYEAR_PAR: + return 1; + case AUTHORYEAR_INTEXT: + return 2; + case INVISIBLE_CIT: + return 3; + default: + throw new RuntimeException("Invalid CitationType"); + } + } + + /** + * Produce a reference mark name for JabRef for the given citation + * key and citationType that does not yet appear among the reference + * marks of the document. + * + * @param bibtexKey The citation key. + * @param citationType Encodes the effect of withText and + * inParenthesis options. + * + * The first occurrence of bibtexKey gets no serial number, the + * second gets 0, the third 1 ... + * + * Or the first unused in this series, after removals. + */ + public static String getUniqueMarkName(Set usedNames, + String bibtexKey, + CitationType citationType) + throws + NoDocumentException { + + int i = 0; + int j = CitationTypeToInt(citationType); + String name = BIB_CITATION + '_' + j + '_' + bibtexKey; + while (usedNames.contains(name)) { + name = BIB_CITATION + i + '_' + j + '_' + bibtexKey; + i++; + } + return name; + } + + /** + * Parse a JabRef (reference) mark name. + * + * @return Optional.empty() on failure. + * + */ + public static Optional parseMarkName(String refMarkName) { + + Matcher citeMatcher = CITE_PATTERN.matcher(refMarkName); + if (!citeMatcher.find()) { + return Optional.empty(); + } + + List keys = Arrays.asList(citeMatcher.group(3).split(",")); + String i = citeMatcher.group(1); + int j = Integer.parseInt(citeMatcher.group(2)); + CitationType citationType = CitationTypeFromInt(j); + return (Optional.of(new Codec52.ParsedMarkName(i, citationType, keys))); + } + + /** + * @return true if name matches the pattern used for JabRef + * reference mark names. + */ + public static boolean isJabRefReferenceMarkName(String name) { + return (CITE_PATTERN.matcher(name).find()); + } + + /** + * Filter a list of reference mark names by `isJabRefReferenceMarkName` + * + * @param names The list to be filtered. + */ + public static List filterIsJabRefReferenceMarkName(List names) { + return (names + .stream() + .filter(Codec52::isJabRefReferenceMarkName) + .collect(Collectors.toList())); + } +} diff --git a/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java b/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java new file mode 100644 index 00000000000..468d630e756 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java @@ -0,0 +1,87 @@ +package org.jabref.logic.openoffice.backend; + +import org.jabref.model.openoffice.uno.NoDocumentException; + +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility methods for processing OO Writer documents. + */ +public class GetContext { + + private static final Logger LOGGER = LoggerFactory.getLogger(GetContext.class); + + private GetContext() { + // Just to hide the public constructor + } + + /** + * Get the text belonging to cursor with up to + * charBefore and charAfter characters of context. + * + * The actual context may be smaller than requested. + * + * @param cursor + * @param charBefore Number of characters requested. + * @param charAfter Number of characters requested. + * @param htmlMarkup If true, the text belonging to the + * reference mark is surrounded by bold html tag. + * + */ + public static String getCursorStringWithContext(XTextCursor cursor, + int charBefore, + int charAfter, + boolean htmlMarkup) + throws + WrappedTargetException, + NoDocumentException { + + String citPart = cursor.getString(); + + // extend cursor range left + int flex = 8; + for (int i = 0; i < charBefore; i++) { + try { + cursor.goLeft((short) 1, true); + // If we are close to charBefore and see a space, + // then cut here. Might avoid cutting a word in half. + if ((i >= (charBefore - flex)) + && Character.isWhitespace(cursor.getString().charAt(0))) { + break; + } + } catch (IndexOutOfBoundsException ex) { + LOGGER.warn("Problem going left", ex); + } + } + + int lengthWithBefore = cursor.getString().length(); + int addedBefore = lengthWithBefore - citPart.length(); + + cursor.collapseToStart(); + for (int i = 0; i < (charAfter + lengthWithBefore); i++) { + try { + cursor.goRight((short) 1, true); + if (i >= ((charAfter + lengthWithBefore) - flex)) { + String strNow = cursor.getString(); + if (Character.isWhitespace(strNow.charAt(strNow.length() - 1))) { + break; + } + } + } catch (IndexOutOfBoundsException ex) { + LOGGER.warn("Problem going right", ex); + } + } + + String result = cursor.getString(); + if (htmlMarkup) { + result = (result.substring(0, addedBefore) + + "" + citPart + "" + + result.substring(lengthWithBefore)); + } + return result.trim(); + } + +} diff --git a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java new file mode 100644 index 00000000000..157dd87cf0c --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java @@ -0,0 +1,50 @@ +package org.jabref.logic.openoffice.backend; + +import java.util.List; +import java.util.Optional; + +import org.jabref.model.openoffice.backend.NamedRange; +import org.jabref.model.openoffice.backend.NamedRangeManager; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoReferenceMark; + +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; + +public class NamedRangeManagerReferenceMark implements NamedRangeManager { + + @Override + public NamedRange nrmCreate(XTextDocument doc, + String refMarkName, + XTextCursor position, + boolean insertSpaceAfter, + boolean withoutBrackets) + throws + CreationException { + return NamedRangeReferenceMark.create(doc, + refMarkName, + position, + insertSpaceAfter, + withoutBrackets); + } + + @Override + public List nrmGetUsedNames(XTextDocument doc) + throws + NoDocumentException { + return UnoReferenceMark.getListOfNames(doc); + } + + @Override + public Optional nrmGetFromDocument(XTextDocument doc, String refMarkName) + throws + NoDocumentException, + WrappedTargetException { + return (NamedRangeReferenceMark + .getFromDocument(doc, refMarkName) + .map(x -> x)); + } +} + diff --git a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java new file mode 100644 index 00000000000..38ac716d9ac --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java @@ -0,0 +1,500 @@ +package org.jabref.logic.openoffice.backend; + +import java.util.Optional; + +import org.jabref.model.openoffice.backend.NamedRange; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoCursor; +import org.jabref.model.openoffice.uno.UnoReferenceMark; + +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XText; +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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +// was StorageBaseRefMark + +class NamedRangeReferenceMark implements NamedRange { + + private static final String ZERO_WIDTH_SPACE = "\u200b"; + + // for debugging we may want visible bracket + private static final boolean + REFERENCE_MARK_USE_INVISIBLE_BRACKETS = true; // !debug; + + public static final String + REFERENCE_MARK_LEFT_BRACKET = REFERENCE_MARK_USE_INVISIBLE_BRACKETS ? ZERO_WIDTH_SPACE : "<"; + + public static final String + REFERENCE_MARK_RIGHT_BRACKET = REFERENCE_MARK_USE_INVISIBLE_BRACKETS ? ZERO_WIDTH_SPACE : ">"; + + private static final Logger LOGGER = LoggerFactory.getLogger(NamedRangeReferenceMark.class); + + private String id; /* reference mark name */ + + private NamedRangeReferenceMark(String id) { + this.id = id; + } + + String getId() { + return id; + } + + /** + * Insert {@code n} spaces in a way that reference + * marks just before or just after the cursor are not affected. + * + * This is based on the observation, that starting two + * new paragraphs separates us from a reference mark on either side. + * + * The pattern used is: + * {@code safeInsertSpaces(n): para, para, left, space(n), right-delete, left(n), left-delete} + * + * @param position Where to insert (at position.getStart()) + * @param n Number of spaces to insert. + * + * @return a new cursor, covering the just-inserted spaces. + * + * This could be generalized to insert arbitrary text safely + * between two reference marks. But we do not need that now. + */ + private static XTextCursor safeInsertSpacesBetweenReferenceMarks(XTextRange position, int n) { + // Start with an empty cursor at position.getStart(); + XText text = position.getText(); + XTextCursor cursor = text.createTextCursorByRange(position.getStart()); + text.insertString(cursor, "\r\r", false); // para, para + cursor.goLeft((short) 1, false); // left + text.insertString(cursor, " ".repeat(n), false); // space(n) + cursor.goRight((short) 1, true); + cursor.setString(""); // right-delete + cursor.goLeft((short) n, false); // left(n) + cursor.goLeft((short) 1, true); + cursor.setString(""); // left-delete + cursor.goRight((short) n, true); // select the newly inserted spaces + return cursor; + } + + private static void createReprInDocument(XTextDocument doc, + String refMarkName, + XTextCursor position, + boolean insertSpaceAfter, + boolean withoutBrackets) + throws + CreationException { + + // The cursor we received: we push it before us. + position.collapseToEnd(); + + XTextCursor cursor = safeInsertSpacesBetweenReferenceMarks(position.getEnd(), 2); + + // cursors before the first and after the last space + XTextCursor cursorBefore = cursor.getText().createTextCursorByRange(cursor.getStart()); + XTextCursor cursorAfter = cursor.getText().createTextCursorByRange(cursor.getEnd()); + + cursor.collapseToStart(); + cursor.goRight((short) 1, false); + // now we are between two spaces + + final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; + final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; + final short leftLength = (short) left.length(); + final short rightLength = (short) right.length(); + String bracketedContent = (withoutBrackets + ? "" + : left + right); + + cursor.getText().insertString(cursor, bracketedContent, true); + + UnoReferenceMark.create(doc, refMarkName, cursor, true /* absorb */); + + cursorBefore.goRight((short) 1, true); + cursorBefore.setString(""); + if (!insertSpaceAfter) { + cursorAfter.goLeft((short) 1, true); + cursorAfter.setString(""); + } + } + + static NamedRangeReferenceMark create(XTextDocument doc, + String refMarkName, + XTextCursor position, + boolean insertSpaceAfter, + boolean withoutBrackets) + throws + CreationException { + + createReprInDocument(doc, + refMarkName, + position, + insertSpaceAfter, + withoutBrackets); + return new NamedRangeReferenceMark(refMarkName); + } + + /** + * @return Optional.empty if there is no corresponding range. + */ + static Optional getFromDocument(XTextDocument doc, + String refMarkName) + throws + NoDocumentException, + WrappedTargetException { + return (UnoReferenceMark.getAnchor(doc, refMarkName) + .map(e -> new NamedRangeReferenceMark(refMarkName))); + } + + /* + * Remove it from the document. + * + * See: removeCitationGroups + */ + @Override + public void nrRemoveFromDocument(XTextDocument doc) + throws + WrappedTargetException, + NoDocumentException, + NoSuchElementException { + UnoReferenceMark.remove(doc, this.nrGetRangeName()); + } + + @Override + public String nrGetRangeName() { + return id; + } + + /* + * ranges controlled by citation groups should not overlap with each other. + * + * @return Optional.empty if the reference mark is missing. + * + * See: UnoReferenceMark.getAnchor + */ + @Override + public Optional nrGetMarkRange(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + String name = this.nrGetRangeName(); + return UnoReferenceMark.getAnchor(doc, name); + } + + /** + * Cursor for the reference marks as is, not prepared for filling, + * but does not need nrCleanFillCursor either. + * + * @return Optional.empty() if reference mark is missing from the document, + * otherwise an XTextCursor for getMarkRange + * + * See: getRawCursorForCitationGroup + */ + @Override + public Optional nrGetRawCursor(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + + String name = this.nrGetRangeName(); + Optional full = Optional.empty(); + + Optional markAsTextContent = UnoReferenceMark.getAsTextContent(doc, name); + + if (markAsTextContent.isEmpty()) { + String msg = String.format("nrGetRawCursor: markAsTextContent(%s).isEmpty()", name); + LOGGER.warn(msg); + } + + full = UnoCursor.getTextCursorOfTextContentAnchor(markAsTextContent.get()); + if (full.isEmpty()) { + String msg = "nrGetRawCursor: full.isEmpty()"; + LOGGER.warn(msg); + return Optional.empty(); + } + return full; + } + + /** + * See: getFillCursorForCitationGroup + */ + @Override + public XTextCursor nrGetFillCursor(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException, + CreationException { + + String name = this.nrGetRangeName(); + + final boolean debugThisFun = false; + final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; + final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; + final short leftLength = (short) left.length(); + final short rightLength = (short) right.length(); + + XTextCursor full = null; + String fullText = null; + for (int i = 1; i <= 2; i++) { + Optional markAsTextContent = UnoReferenceMark.getAsTextContent(doc, name); + + if (markAsTextContent.isEmpty()) { + String msg = String.format("nrGetFillCursor:" + + " markAsTextContent(%s).isEmpty (attempt %d)", + name, + i); + throw new RuntimeException(msg); + } + + full = UnoCursor.getTextCursorOfTextContentAnchor(markAsTextContent.get()).orElse(null); + if (full == null) { + String msg = String.format("nrGetFillCursor: full == null (attempt %d)", i); + throw new RuntimeException(msg); + } + + fullText = full.getString(); + + if (debugThisFun) { + System.out.printf("nrGetFillCursor: fulltext = '%s'%n", fullText); + } + + if (fullText.length() >= 2) { + if (debugThisFun) { + System.out.printf("nrGetFillCursor: (attempt: %d) fulltext.length() >= 2," + + " break loop%n", i); + } + break; + } else { + // (fullText.length() < 2) + if (i == 2) { + String msg = String.format("nrGetFillCursor:" + + " (fullText.length() < 2) (attempt %d)", + i); + throw new RuntimeException(msg); + } + // too short, recreate + if (true || debugThisFun) { + System.out.println("nrGetFillCursor: too short, recreate"); + } + full.setString(""); + try { + UnoReferenceMark.remove(doc, name); + } catch (NoSuchElementException ex) { + String msg = String.format("nrGetFillCursor got NoSuchElementException" + + " for '%s'", + name); + LOGGER.warn(msg); + } + createReprInDocument(doc, + name, + full, + false, /* insertSpaceAfter */ + false /* withoutBrackets */); + } + } + + if (full == null) { + throw new RuntimeException("nrGetFillCursorFor: full == null (after loop)"); + } + if (fullText == null) { + throw new RuntimeException("nrGetFillCursor: fullText == null (after loop)"); + } + + fullText = full.getString(); + if (fullText.length() < 2) { + throw new RuntimeException("nrGetFillCursor: fullText.length() < 2 (after loop)'%n"); + } + XTextCursor beta = full.getText().createTextCursorByRange(full); + beta.collapseToStart(); + beta.goRight((short) 1, false); + beta.goRight((short) (fullText.length() - 2), true); + if (debugThisFun) { + System.out.printf("nrGetFillCursor: beta(1) covers '%s'%n", beta.getString()); + } + if (fullText.startsWith(left) && fullText.endsWith(right)) { + beta.setString(""); + } else { + if (debugThisFun) { + String msg = String.format("nrGetFillCursor: recreating brackets for '%s'", fullText); + // LOGGER.warn(msg); + System.out.println(msg); + } + + // we have at least two characters inside + XTextCursor alpha = full.getText().createTextCursorByRange(full); + alpha.collapseToStart(); + + XTextCursor omega = full.getText().createTextCursorByRange(full); + omega.collapseToEnd(); + + // beta now covers everything except first and last character + // Replace its content with brackets + String paddingx = "x"; + String paddingy = "y"; + String paddingz = "z"; + beta.setString(paddingx + left + paddingy + right + paddingz); + if (debugThisFun) { + System.out.printf("nrGetFillCursor: beta(2) covers '%s'%n", beta.getString()); + } + // move beta to before the right bracket + beta.collapseToEnd(); + beta.goLeft((short) (rightLength + 1), false); + // remove middle padding + beta.goLeft((short) 1, true); + if (debugThisFun) { + System.out.printf("nrGetFillCursor: beta(3) covers '%s'%n", beta.getString()); + } + // only drop paddingy later: beta.setString(""); + + // drop the initial character and paddingx + alpha.collapseToStart(); + alpha.goRight((short) (1 + 1), true); + if (debugThisFun) { + System.out.printf("nrGetFillCursor: alpha(4) covers '%s'%n", alpha.getString()); + } + alpha.setString(""); + // drop the last character and paddingz + omega.collapseToEnd(); + omega.goLeft((short) (1 + 1), true); + if (debugThisFun) { + System.out.printf("nrGetFillCursor: omega(5) covers '%s'%n", omega.getString()); + } + omega.setString(""); + + // drop paddingy now + if (debugThisFun) { + System.out.printf("nrGetFillCursor: beta(6) covers '%s'%n", beta.getString()); + } + beta.setString(""); + // should be OK now. + if (debugThisFun) { + alpha.goRight(leftLength, true); + System.out.printf("nrGetFillCursor: alpha(7) covers '%s', should be '%s'%n", + alpha.getString(), left); + omega.goLeft(rightLength, true); + System.out.printf("nrGetFillCursor: omega(8) covers '%s', should be '%s'%n", + omega.getString(), right); + } + } + + // NamedRangeReferenceMark.checkFillCursor(beta); + return beta; + } + + /* + * Throw RuntimeException if the brackets are not there. + */ + public static void checkFillCursor(XTextCursor cursor) { + final String left = REFERENCE_MARK_LEFT_BRACKET; + final String right = REFERENCE_MARK_RIGHT_BRACKET; + final short leftLength = (short) left.length(); + final short rightLength = (short) right.length(); + + XTextCursor alpha = cursor.getText().createTextCursorByRange(cursor); + alpha.collapseToStart(); + + XTextCursor omega = cursor.getText().createTextCursorByRange(cursor); + omega.collapseToEnd(); + + if (leftLength > 0) { + alpha.goLeft(leftLength, true); + if (!left.equals(alpha.getString())) { + String msg = String.format("checkFillCursor:" + + " ('%s') is not prefixed with" + + " REFERENCE_MARK_LEFT_BRACKET, has '%s'", + cursor.getString(), alpha.getString()); + throw new RuntimeException(msg); + } + } + + if (rightLength > 0) { + omega.goRight(rightLength, true); + if (!right.equals(omega.getString())) { + String msg = String.format("checkFillCursor:" + + " ('%s') is not followed by" + + " REFERENCE_MARK_RIGHT_BRACKET, has '%s'", + cursor.getString(), omega.getString()); + throw new RuntimeException(msg); + } + } + } + + /** + * Remove brackets, but if the result would become empty, leave + * them; if the result would be a single characer, leave the left bracket. + * + * See: cleanFillCursorForCitationGroup + */ + @Override + public void nrCleanFillCursor(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException, + CreationException { + + // alwaysRemoveBrackets : full compatibility with JabRef 5.2: + // brackets are temporary, only exist between nrGetFillCursor + // and nrCleanFillCursor. + final boolean alwaysRemoveBrackets = false; + + // removeBracketsFromEmpty is intended to force removal if we + // are working on an "Empty citation" (INVISIBLE_CIT). + final boolean removeBracketsFromEmpty = false; + + final String left = REFERENCE_MARK_LEFT_BRACKET; + final String right = REFERENCE_MARK_RIGHT_BRACKET; + final short leftLength = (short) left.length(); + final short rightLength = (short) right.length(); + + String name = this.nrGetRangeName(); + + XTextCursor full = this.nrGetRawCursor(doc).orElseThrow(RuntimeException::new); + final String fullText = full.getString(); + final int fullTextLength = fullText.length(); + + if (!fullText.startsWith(left)) { + String msg = String.format("nrCleanFillCursor:" + + " (%s) does not start with REFERENCE_MARK_LEFT_BRACKET", + name); + throw new RuntimeException(msg); + } + + if (!fullText.endsWith(right)) { + String msg = String.format("nrCleanFillCursor:" + + " (%s) does not end with REFERENCE_MARK_RIGHT_BRACKET", + name); + throw new RuntimeException(msg); + } + + final int contentLength = (fullTextLength - (leftLength + rightLength)); + if (contentLength < 0) { + String msg = String.format("nrCleanFillCursor: length(%s) < 0", name); + throw new RuntimeException(msg); + } + + boolean removeRight = ((contentLength >= 1) + || ((contentLength == 0) && removeBracketsFromEmpty) + || alwaysRemoveBrackets); + + boolean removeLeft = ((contentLength >= 2) + || ((contentLength == 0) && removeBracketsFromEmpty) + || alwaysRemoveBrackets); + + if (removeRight) { + XTextCursor omega = full.getText().createTextCursorByRange(full); + omega.collapseToEnd(); + omega.goLeft(rightLength, true); + omega.setString(""); + } + + if (removeLeft) { + XTextCursor alpha = full.getText().createTextCursorByRange(full); + alpha.collapseToStart(); + alpha.goRight(leftLength, true); + alpha.setString(""); + } + } +} diff --git a/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java new file mode 100644 index 00000000000..e5c54773b07 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java @@ -0,0 +1,65 @@ +package org.jabref.model.openoffice.backend; + +import java.util.Optional; + +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; + +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; + +public interface NamedRange { + + public String nrGetRangeName(); + + /** + * @return Optional.empty if the mark is missing from the document. + */ + public Optional nrGetMarkRange(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException; + + /** + * Cursor for the reference marks as is, not prepared for filling, + * but does not need nrCleanFillCursor either. + */ + public Optional nrGetRawCursor(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException; + + /** + * Get a cursor for filling in text. + * + * Must be followed by nrCleanFillCursor() + */ + public XTextCursor nrGetFillCursor(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException, + CreationException; + + /** + * Remove brackets, but if the result would become empty, leave + * them; if the result would be a single characer, leave the left bracket. + * + */ + public void nrCleanFillCursor(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException, + CreationException; + + /** + * Note: create is in NamedRangeManager + */ + public void nrRemoveFromDocument(XTextDocument doc) + throws + WrappedTargetException, + NoDocumentException, + NoSuchElementException; +} diff --git a/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java b/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java new file mode 100644 index 00000000000..f53fcc72527 --- /dev/null +++ b/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java @@ -0,0 +1,31 @@ +package org.jabref.model.openoffice.backend; + +import java.util.List; +import java.util.Optional; + +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; + +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; + +public interface NamedRangeManager { + + public NamedRange nrmCreate(XTextDocument doc, + String markName, + XTextCursor position, + boolean insertSpaceAfter, + boolean withoutBrackets) + throws + CreationException; + + public List nrmGetUsedNames(XTextDocument doc) + throws + NoDocumentException; + + public Optional nrmGetFromDocument(XTextDocument doc, String markName) + throws + NoDocumentException, + WrappedTargetException; +} From a5b7a05d635771c4ca821f850d7bb97d6c3e61be Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 11:52:31 +0200 Subject: [PATCH 025/103] add frontend --- .../logic/openoffice/frontend/OOFrontend.java | 615 ++++++++++++++++++ .../frontend/RangeForOverlapCheck.java | 49 ++ .../frontend/UpdateBibliography.java | 153 +++++ .../frontend/UpdateCitationMarkers.java | 174 +++++ src/main/resources/l10n/JabRef_en.properties | 4 + 5 files changed, 995 insertions(+) create mode 100644 src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java create mode 100644 src/main/java/org/jabref/logic/openoffice/frontend/RangeForOverlapCheck.java create mode 100644 src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java create mode 100644 src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java new file mode 100644 index 00000000000..fd0523a4bf8 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java @@ -0,0 +1,615 @@ +package org.jabref.logic.openoffice.frontend; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.jabref.logic.JabRefException; +import org.jabref.logic.l10n.Localization; +import org.jabref.logic.openoffice.backend.Backend52; +import org.jabref.model.openoffice.CitationEntry; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.rangesort.FunctionalTextViewCursor; +import org.jabref.model.openoffice.rangesort.RangeOverlap; +import org.jabref.model.openoffice.rangesort.RangeOverlapBetween; +import org.jabref.model.openoffice.rangesort.RangeOverlapWithin; +import org.jabref.model.openoffice.rangesort.RangeSet; +import org.jabref.model.openoffice.rangesort.RangeSort; +import org.jabref.model.openoffice.rangesort.RangeSortEntry; +import org.jabref.model.openoffice.rangesort.RangeSortVisual; +import org.jabref.model.openoffice.rangesort.RangeSortable; +import org.jabref.model.openoffice.style.CitationGroup; +import org.jabref.model.openoffice.style.CitationGroupId; +import org.jabref.model.openoffice.style.CitationGroups; +import org.jabref.model.openoffice.style.CitationType; +import org.jabref.model.openoffice.style.OODataModel; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoCursor; +import org.jabref.model.openoffice.uno.UnoTextRange; +import org.jabref.model.openoffice.util.OOListUtil; +import org.jabref.model.openoffice.util.OOVoidResult; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OOFrontend { + private static final Logger LOGGER = LoggerFactory.getLogger(OOFrontend.class); + public final Backend52 backend; + public final CitationGroups citationGroups; + + public OOFrontend(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + + // TODO: dataModel should come from looking at the + // document and preferences. + // + this.backend = new Backend52(); + + // Get the citationGroupNames + List citationGroupNames = this.backend.getJabRefReferenceMarkNames(doc); + + Map citationGroups = + readCitationGroupsFromDocument(this.backend, doc, citationGroupNames); + this.citationGroups = new CitationGroups(citationGroups); + } + + public OODataModel getDataModel() { + return backend.dataModel; + } + + public Optional healthReport(XTextDocument doc) + throws + NoDocumentException { + return backend.healthReport(doc); + } + + private static Map + readCitationGroupsFromDocument(Backend52 backend, + XTextDocument doc, + List citationGroupNames) + throws + WrappedTargetException, + NoDocumentException { + + Map citationGroups = new HashMap<>(); + for (int i = 0; i < citationGroupNames.size(); i++) { + final String name = citationGroupNames.get(i); + CitationGroup cg = backend.readCitationGroupFromDocumentOrThrow(doc, name); + citationGroups.put(cg.cgid, cg); + } + return citationGroups; + } + + /** + * Creates a list of {@code RangeSortable} values for + * our {@code CitationGroup} values. Originally designed to be + * passed to {@code visualSort}. + * + * The elements of the returned list are actually of type + * {@code RangeSortEntry}. + * + * The result is sorted within {@code XTextRange.getText()} + * partitions of the citation groups according to their {@code XTextRange} + * (before mapping to footnote marks). + * + * In the result, RangeSortable.getIndexInPosition() contains + * unique indexes within the original partition (not after + * mapFootnotesToFootnoteMarks). + * + * @param mapFootnotesToFootnoteMarks If true, replace ranges in + * footnotes with the range of the corresponding footnote + * mark. This is used for numbering the citations. + * + */ + private List> + createVisualSortInput(XTextDocument doc, boolean mapFootnotesToFootnoteMarks) + throws + NoDocumentException, + WrappedTargetException { + + List> sortables = new ArrayList<>(); + for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { + XTextRange range = (this + .getMarkRange(doc, cg) + .orElseThrow(RuntimeException::new)); + sortables.add(new RangeSortEntry<>(range, 0, cg)); + } + + /* + * At this point we are almost ready to return sortables. + * + * But we may want to number citations in a footnote + * as if it appeared where the footnote mark is. + * + * The following code replaces ranges within footnotes with + * the range for the corresponding footnote mark. + * + * This brings further ambiguity if we have multiple + * citation groups within the same footnote: for the comparison + * they become indistinguishable. Numbering between them is + * not controlled. Also combineCiteMarkers will see them in + * the wrong order (if we use this comparison), and will not + * be able to merge. To avoid these, we sort textually within + * each .getText() partition and add indexInPosition + * accordingly. + * + */ + + // Sort within partitions + RangeSort.RangePartitions> partitions = + RangeSort.partitionAndSortRanges(sortables); + + // build final list + List> result = new ArrayList<>(); + for (List> partition : partitions.getPartitions()) { + + int indexInPartition = 0; + for (int i = 0; i < partition.size(); i++) { + RangeSortEntry sortable = partition.get(i); + XTextRange aRange = sortable.getRange(); + sortable.setIndexInPosition(indexInPartition++); + if (mapFootnotesToFootnoteMarks) { + Optional footnoteMarkRange = + UnoTextRange.getFootnoteMarkRange(sortable.getRange()); + // Adjust range if we are inside a footnote: + if (footnoteMarkRange.isPresent()) { + sortable.setRange(footnoteMarkRange.get()); + } + } + result.add(sortable); + } + } + return result.stream().map(e -> e).collect(Collectors.toList()); + } + + /** + * @param mapFootnotesToFootnoteMarks If true, sort reference + * marks in footnotes as if they appeared at the + * corresponding footnote mark. + * + * @return citation groups sorted by their visual positions. + * + * Limitation: for two column layout visual (top-down, + * left-right) order does not match the expected (textual) + * order. + * + */ + private List + getVisuallySortedCitationGroups(XTextDocument doc, + boolean mapFootnotesToFootnoteMarks, + FunctionalTextViewCursor fcursor) + throws + WrappedTargetException, + NoDocumentException, + JabRefException { + + List> sortables = + createVisualSortInput(doc, mapFootnotesToFootnoteMarks); + + List> sorted = + RangeSortVisual.visualSort(sortables, + doc, + fcursor); + + List result = + (sorted.stream().map(e -> e.getContent()).collect(Collectors.toList())); + + return result; + } + + /** + * Return citation groups in visual order within (but not across) + * XText partitions. + * + * This is (1) sufficient for combineCiteMarkers which looks for + * consecutive XTextRanges within each XText, (2) not confused by + * multicolumn layout or multipage display. + */ + public List + getCitationGroupsSortedWithinPartitions(XTextDocument doc, boolean mapFootnotesToFootnoteMarks) + throws + NoDocumentException, + WrappedTargetException { + // This is like getVisuallySortedCitationGroups, + // but we skip the visualSort part. + List> sortables = + createVisualSortInput(doc, mapFootnotesToFootnoteMarks); + + return (sortables.stream().map(e -> e.getContent()).collect(Collectors.toList())); + } + + /** + * Create a citation group for the given citation keys, at the + * end of position. + * + * On return {@code position} is collapsed, and is after the + * inserted space, or at the end of the reference mark. + * + * @param citationKeys In storage order + * @param pageInfos In storage order + * @param citationType + * @param position Collapsed to its end. + * @param insertSpaceAfter If true, we insert a space after the mark, that + * carries on format of characters from + * the original position. + */ + public CitationGroup createCitationGroup(XTextDocument doc, + List citationKeys, + List> pageInfos, + CitationType citationType, + XTextCursor position, + boolean insertSpaceAfter) + throws + CreationException, + NoDocumentException, + WrappedTargetException, + NotRemoveableException, + PropertyExistException, + PropertyVetoException, + IllegalTypeException { + + Objects.requireNonNull(pageInfos); + if (pageInfos.size() != citationKeys.size()) { + throw new RuntimeException("pageInfos.size != citationKeys.size"); + } + CitationGroup cg = backend.createCitationGroup(doc, + citationKeys, + pageInfos, + citationType, + position, + insertSpaceAfter); + + this.citationGroups.afterCreateCitationGroup(cg); + return cg; + } + + /** + * Remove {@code cg} both from the document and notify {@code citationGroups} + */ + public void removeCitationGroup(CitationGroup cg, XTextDocument doc) + throws + WrappedTargetException, + NoDocumentException, + NoSuchElementException, + NotRemoveableException, + PropertyExistException, + IllegalTypeException { + + backend.removeCitationGroup(cg, doc); + this.citationGroups.afterRemoveCitationGroup(cg); + } + + public void removeCitationGroups(List cgs, XTextDocument doc) + throws + WrappedTargetException, + NoDocumentException, + NoSuchElementException, + NotRemoveableException, + PropertyExistException, + IllegalTypeException { + + for (CitationGroup cg : cgs) { + removeCitationGroup(cg, doc); + } + } + + /** + * ranges controlled by citation groups should not overlap with each other. + * + * @return Optional.empty() if the reference mark is missing. + * + */ + public Optional getMarkRange(XTextDocument doc, CitationGroup cg) + throws + NoDocumentException, + WrappedTargetException { + return backend.getMarkRange(cg, doc); + } + + public XTextCursor getFillCursorForCitationGroup(XTextDocument doc, CitationGroup cg) + throws + NoDocumentException, + WrappedTargetException, + CreationException { + return backend.getFillCursorForCitationGroup(cg, doc); + } + + /** + * Remove brackets added by getFillCursorForCitationGroup. + */ + public void cleanFillCursorForCitationGroup(XTextDocument doc, CitationGroup cg) + throws + NoDocumentException, + WrappedTargetException, + CreationException { + + backend.cleanFillCursorForCitationGroup(cg, doc); + } + + /** + * @return A RangeForOverlapCheck for each citation group. + * + * result.size() == nRefMarks + */ + public List> citationRanges(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + + List> result = + new ArrayList<>(citationGroups.numberOfCitationGroups()); + + for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { + XTextRange range = this.getMarkRange(doc, cg).orElseThrow(RuntimeException::new); + String description = cg.cgid.citationGroupIdAsString(); // cg.cgRangeStorage.nrGetRangeName(); + result.add(new RangeForOverlapCheck<>(range, + cg.cgid, + RangeForOverlapCheck.REFERENCE_MARK_KIND, + description)); + } + return result; + } + + public List> bibliographyRanges(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + + List> result = new ArrayList<>(); + + Optional range = UpdateBibliography.getBibliographyRange(doc); + if (range.isPresent()) { + String description = "bibliography"; + result.add(new RangeForOverlapCheck<>(range.get(), + new CitationGroupId("bibliography"), + RangeForOverlapCheck.BIBLIOGRAPHY_MARK_KIND, + description)); + } + return result; + } + + public List> viewCursorRanges(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + + List> result = new ArrayList<>(); + + Optional range = UnoCursor.getViewCursor(doc).map(e -> e); + if (range.isPresent()) { + String description = "cursor"; + result.add(new RangeForOverlapCheck<>(range.get(), + new CitationGroupId("cursor"), + RangeForOverlapCheck.CURSOR_MARK_KIND, + description)); + } + return result; + } + + /** + * @return A range for each footnote mark where the footnote + * contains at least one citation group. + * + * Purpose: We do not want markers of footnotes containing + * reference marks to overlap with reference + * marks. Overwriting these footnote marks might kill our + * reference marks in the footnote. + * + * Note: Here we directly communicate to the document, not + * through the backend. This is because mapping ranges to + * footnote marks does not depend on how do we mark or + * structure those ranges. + */ + public List> + footnoteMarkRanges(XTextDocument doc, + List> citationRanges) + throws + NoDocumentException, + WrappedTargetException { + + // Avoid inserting the same mark twice. + // Could use RangeSet if we had that. + RangeSet seen = new RangeSet(); + + List> result = new ArrayList<>(); + + for (RangeForOverlapCheck citationRange : citationRanges) { + + Optional footnoteMarkRange = + UnoTextRange.getFootnoteMarkRange(citationRange.range); + + if (footnoteMarkRange.isEmpty()) { + // not in footnote + continue; + } + + boolean seenContains = seen.contains(footnoteMarkRange.get()); + if (!seenContains) { + seen.add(footnoteMarkRange.get()); + result.add(new RangeForOverlapCheck<>(footnoteMarkRange.get(), + citationRange.idWithinKind, + RangeForOverlapCheck.FOOTNOTE_MARK_KIND, + "FootnoteMark for " + citationRange.format())); + } + } + return result; + } + + static String + rangeOverlapsToMessage(List>> overlaps) { + + if (overlaps.size() == 0) { + return "(*no overlaps*)"; + } + + StringBuilder msg = new StringBuilder(); + for (RangeOverlap> overlap : overlaps) { + String listOfRanges = (overlap.valuesForOverlappingRanges.stream() + .map(v -> String.format("'%s'", v.format())) + .collect(Collectors.joining(", "))); + msg.append( + switch (overlap.kind) { + case EQUAL_RANGE -> Localization.lang("Found identical ranges"); + case OVERLAP -> Localization.lang("Found overlapping ranges"); + case TOUCH -> Localization.lang("Found touching ranges"); + }); + msg.append(": "); + msg.append(listOfRanges); + msg.append("\n"); + } + return msg.toString(); + } + + /** + * Check for any overlap between userRanges and protected ranges. + * + * Assume userRanges is small (usually 1 elements for checking the cursor) + * Returns on first problem found. + */ + public OOVoidResult + checkRangeOverlapsWithCursor(XTextDocument doc, + List> userRanges, + boolean requireSeparation) + throws + NoDocumentException, + WrappedTargetException { + + List> citationRanges = citationRanges(doc); + List> ranges = new ArrayList<>(); + + // ranges.addAll(userRanges); + ranges.addAll(bibliographyRanges(doc)); + ranges.addAll(citationRanges); + ranges.addAll(footnoteMarkRanges(doc, citationRanges)); + + List>> overlaps = + RangeOverlapBetween.findFirst( + doc, + userRanges, + ranges, + requireSeparation); + + if (overlaps.size() == 0) { + return OOVoidResult.ok(); + } + return OOVoidResult.error(new JabRefException("Found overlapping or touching ranges", + rangeOverlapsToMessage(overlaps))); + } + + /** + * @param requireSeparation Report range pairs that only share a boundary. + * @param reportAtMost Limit number of overlaps reported (0 for no limit) + * + */ + public OOVoidResult + checkRangeOverlaps(XTextDocument doc, + List> userRanges, + boolean requireSeparation, + int reportAtMost) + throws + NoDocumentException, + WrappedTargetException { + + List> citationRanges = citationRanges(doc); + List> ranges = new ArrayList<>(); + ranges.addAll(userRanges); + ranges.addAll(bibliographyRanges(doc)); + ranges.addAll(citationRanges); + ranges.addAll(footnoteMarkRanges(doc, citationRanges)); + + List>> overlaps = + RangeOverlapWithin.findOverlappingRanges(doc, ranges, requireSeparation, reportAtMost); + + if (overlaps.size() == 0) { + return OOVoidResult.ok(); + } + return OOVoidResult.error(new JabRefException("Found overlapping or touching ranges", + rangeOverlapsToMessage(overlaps))); + } + + /** + * GUI: Get a list of CitationEntry objects corresponding to citations + * in the document. + * + * Called from: ManageCitationsDialogViewModel constructor. + * + * @return A list with entries corresponding to citations in the + * text, in arbitrary order (same order as from + * getJabRefReferenceMarkNames). + * + * Note: visual or alphabetic order could be more + * manageable for the user. We could provide these + * here, but switching between them needs change on + * GUI (adding a toggle or selector). + * + * Note: CitationEntry implements Comparable, where + * compareTo() and equals() are based on refMarkName. + * The order used in the "Manage citations" dialog + * does not seem to use that. + * + * The 1st is labeled "Citation" (show citation in bold, + * and some context around it). + * + * The columns can be sorted by clicking on the column title. + * For the "Citation" column, the sorting is based on the content, + * (the context before the citation), not on the citation itself. + * + * In the "Extra information ..." column some visual indication + * of the editable part could be helpful. + * + * Wish: selecting an entry (or a button in the line) in + * the GUI could move the cursor in the document to + * the entry. + */ + public List getCitationEntries(XTextDocument doc) + throws + UnknownPropertyException, + WrappedTargetException, + NoDocumentException { + return this.backend.getCitationEntries(doc, citationGroups); + } + + public void applyCitationEntries(XTextDocument doc, List citationEntries) + throws + UnknownPropertyException, + NotRemoveableException, + PropertyExistException, + PropertyVetoException, + IllegalTypeException, + IllegalArgumentException, + NoDocumentException, + WrappedTargetException { + this.backend.applyCitationEntries(doc, citationEntries); + } + + public void imposeGlobalOrder(XTextDocument doc, FunctionalTextViewCursor fcursor) + throws + WrappedTargetException, + NoDocumentException, + JabRefException { + + boolean mapFootnotesToFootnoteMarks = true; + List sortedCitationGroups = + getVisuallySortedCitationGroups(doc, mapFootnotesToFootnoteMarks, fcursor); + List sortedCitationGroupIds = + OOListUtil.map(sortedCitationGroups, cg -> cg.cgid); + citationGroups.setGlobalOrder(sortedCitationGroupIds); + } +} diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/RangeForOverlapCheck.java b/src/main/java/org/jabref/logic/openoffice/frontend/RangeForOverlapCheck.java new file mode 100644 index 00000000000..6cbf560ec62 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/frontend/RangeForOverlapCheck.java @@ -0,0 +1,49 @@ +package org.jabref.logic.openoffice.frontend; + +import org.jabref.model.openoffice.rangesort.RangeHolder; + +import com.sun.star.text.XTextRange; + +/** + * Describe a protected range for overlap checking and reporting. + * + * To check that our protected ranges do not overlap, we collect + * these ranges. To check for overlaps between these, we need the + * {@code range} itself. To report the results of overlap + * checking, we need a {@code description} that can be understood + * by the user. + * + * To be able to refer back to more extended data, we might need to + * identify its {@code kind}, and its index in the corresponding + * tables or other identifier within its kind ({@code idWithinKind}) + * + */ +public class RangeForOverlapCheck implements RangeHolder { + + public final static int REFERENCE_MARK_KIND = 0; + public final static int FOOTNOTE_MARK_KIND = 1; + public final static int CURSOR_MARK_KIND = 2; + public final static int BIBLIOGRAPHY_MARK_KIND = 3; + + public final XTextRange range; + + public final int kind; + public final T idWithinKind; + private final String description; + + public RangeForOverlapCheck(XTextRange range, T idWithinKind, int kind, String description) { + this.range = range; + this.kind = kind; + this.idWithinKind = idWithinKind; + this.description = description; + } + + public String format() { + return description; + } + + @Override + public XTextRange getRange() { + return range; + } +} diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java new file mode 100644 index 00000000000..ef1a4c42dc5 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java @@ -0,0 +1,153 @@ +package org.jabref.logic.openoffice.frontend; + +import java.util.Optional; + +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.logic.openoffice.style.OOFormatBibliography; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.ootext.OOTextIntoOO; +import org.jabref.model.openoffice.style.CitedKeys; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoBookmark; +import org.jabref.model.openoffice.uno.UnoTextSection; + +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; + +/* + * Update document: citation marks and bibliography + */ +public class UpdateBibliography { + + private static final String BIB_SECTION_NAME = "JR_bib"; + private static final String BIB_SECTION_END_NAME = "JR_bib_end"; + + public static Optional getBibliographyRange(XTextDocument doc) + throws + NoDocumentException, + WrappedTargetException { + Optional sectionRange = UnoTextSection.getAnchor(doc, BIB_SECTION_NAME); + return sectionRange; + } + + /** + * Rebuilds the bibliography. + */ + public static void rebuildBibTextSection(XTextDocument doc, + OOFrontend fr, + CitedKeys bibliography, + OOBibStyle style, + boolean alwaysAddCitedOnPages) + throws + NoSuchElementException, + WrappedTargetException, + IllegalArgumentException, + CreationException, + PropertyVetoException, + UnknownPropertyException, + NoDocumentException { + + clearBibTextSectionContent2(doc); + + populateBibTextSection(doc, + fr, + bibliography, + style, + alwaysAddCitedOnPages); + } + + /** + * Insert a paragraph break and create a text section for the bibliography. + * + * Only called from `clearBibTextSectionContent2` + */ + private static void createBibTextSection2(XTextDocument doc) + throws + CreationException, + IllegalArgumentException { + + // Always creating at the end of the document. + // Alternatively, we could receive a cursor. + XTextCursor textCursor = doc.getText().createTextCursor(); + textCursor.gotoEnd(false); + UnoTextSection.create(doc, BIB_SECTION_NAME, textCursor, false); + } + + /** + * Find and clear the text section BIB_SECTION_NAME to "", + * or create it. + * + * Only called from: `rebuildBibTextSection` + * + */ + private static void clearBibTextSectionContent2(XTextDocument doc) + throws + CreationException, + IllegalArgumentException, + NoDocumentException, + WrappedTargetException { + + // Optional sectionRange = UnoTextSection.getAnchor(doc, BIB_SECTION_NAME); + Optional sectionRange = getBibliographyRange(doc); + if (sectionRange.isEmpty()) { + createBibTextSection2(doc); + return; + } else { + // Clear it + XTextCursor cursor = doc.getText().createTextCursorByRange(sectionRange.get()); + cursor.setString(""); + } + } + + /** + * Only called from: `rebuildBibTextSection` + * + * Assumes the section named BIB_SECTION_NAME exists. + */ + private static void populateBibTextSection(XTextDocument doc, + OOFrontend fr, + CitedKeys bibliography, + OOBibStyle style, + boolean alwaysAddCitedOnPages) + throws + CreationException, + IllegalArgumentException, + NoDocumentException, + NoSuchElementException, + PropertyVetoException, + UnknownPropertyException, + WrappedTargetException { + + XTextRange sectionRange = getBibliographyRange(doc).orElseThrow(RuntimeException::new); + + XTextCursor cursor = doc.getText().createTextCursorByRange(sectionRange); + + // emit the title of the bibliography + OOTextIntoOO.removeDirectFormatting(cursor); + OOText bibliographyText = OOFormatBibliography.formatBibliography(fr.citationGroups, + bibliography, + style, + alwaysAddCitedOnPages); + OOTextIntoOO.write(doc, cursor, bibliographyText); + cursor.collapseToEnd(); + + // remove the inital empty paragraph from the section. + sectionRange = getBibliographyRange(doc).orElseThrow(RuntimeException::new); + XTextCursor initialParagraph = doc.getText().createTextCursorByRange(sectionRange); + initialParagraph.collapseToStart(); + initialParagraph.goRight((short) 1, true); + initialParagraph.setString(""); + + UnoBookmark.remove(doc, BIB_SECTION_END_NAME); + UnoBookmark.create(doc, BIB_SECTION_END_NAME, cursor, true); + + cursor.collapseToEnd(); + } + +} diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java new file mode 100644 index 00000000000..7d864ab1063 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java @@ -0,0 +1,174 @@ +package org.jabref.logic.openoffice.frontend; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import org.jabref.logic.JabRefException; +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.ootext.OOTextIntoOO; +import org.jabref.model.openoffice.style.CitationGroup; +import org.jabref.model.openoffice.style.CitationGroups; +import org.jabref.model.openoffice.style.CitationType; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/* + * Update document: citation marks and bibliography + */ +public class UpdateCitationMarkers { + + private static final Logger LOGGER = LoggerFactory.getLogger(UpdateCitationMarkers.class); + + /** + * Visit each reference mark in referenceMarkNames, overwrite its + * text content. + * + * After each fillCitationMarkInCursor call check if we lost the + * BIB_SECTION_NAME bookmark and recreate it if we did. + * + * @param fr + * + * @param style Bibliography style to use. + * + */ + public static void applyNewCitationMarkers(XTextDocument doc, OOFrontend fr, OOBibStyle style) + throws + NoDocumentException, + UnknownPropertyException, + CreationException, + WrappedTargetException, + PropertyVetoException, + NoSuchElementException, + JabRefException { + + CitationGroups citationGroups = fr.citationGroups; + + for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { + + boolean withText = (cg.citationType != CitationType.INVISIBLE_CIT); + Optional marker = cg.getCitationMarker(); + + if (!marker.isPresent()) { + String msg = String.format("applyNewCitationMarkers: no marker for %s", + cg.cgid.citationGroupIdAsString()); + LOGGER.warn(msg); + continue; + } + + if (withText && marker.isPresent()) { + + XTextCursor cursor = fr.getFillCursorForCitationGroup(doc, cg); + + fillCitationMarkInCursor(doc, cursor, marker.get(), withText, style); + + fr.cleanFillCursorForCitationGroup(doc, cg); + } + + } + } + + public static void fillCitationMarkInCursor(XTextDocument doc, + XTextCursor cursor, + OOText citationText, + boolean withText, + OOBibStyle style) + throws + UnknownPropertyException, + PropertyVetoException, + WrappedTargetException, + NoSuchElementException, + CreationException, + IllegalArgumentException { + + Objects.requireNonNull(cursor); + Objects.requireNonNull(citationText); + Objects.requireNonNull(style); + + if (withText) { + OOText citationText2 = style.decorateCitationMarker(citationText); + // inject a ZERO_WIDTH_SPACE to hold the initial character format + final String ZERO_WIDTH_SPACE = "\u200b"; + citationText2 = OOText.fromString(ZERO_WIDTH_SPACE + citationText2.asString()); + OOTextIntoOO.write(doc, cursor, citationText2); + } else { + cursor.setString(""); + } + } + + /** + * Inserts a citation group in the document: creates and fills it. + * + * @param citationKeys BibTeX keys of + * @param pageInfos + * @param citationType + * + * @param citationText Text for the citation. A citation mark or + * placeholder if not yet available. + * + * @param position Location to insert at. + * @param style + * @param insertSpaceAfter A space inserted after the reference + * mark makes it easier to separate from the text + * coming after. But is not wanted when we recreate a + * reference mark. + */ + public static void createAndFillCitationGroup(OOFrontend fr, + XTextDocument doc, + List citationKeys, + List> pageInfos, + CitationType citationType, + OOText citationText, + XTextCursor position, + OOBibStyle style, + boolean insertSpaceAfter) + throws + UnknownPropertyException, + NotRemoveableException, + PropertyExistException, + PropertyVetoException, + WrappedTargetException, + PropertyVetoException, + IllegalArgumentException, + CreationException, + NoDocumentException, + IllegalTypeException, + NoSuchElementException { + + Objects.requireNonNull(pageInfos); + if (pageInfos.size() != citationKeys.size()) { + throw new RuntimeException("pageInfos.size != citationKeys.size"); + } + CitationGroup cg = fr.createCitationGroup(doc, + citationKeys, + pageInfos, + citationType, + position, + insertSpaceAfter); + + final boolean withText = citationType.withText(); + + if (withText) { + XTextCursor c2 = fr.getFillCursorForCitationGroup(doc, cg); + + UpdateCitationMarkers.fillCitationMarkInCursor(doc, c2, citationText, withText, style); + + fr.cleanFillCursorForCitationGroup(doc, cg); + } + position.collapseToEnd(); + } + +} diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index c2d0ea46ee7..dc2fd8df58a 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -1529,6 +1529,10 @@ Custom=Custom Export\ cited=Export cited Unable\ to\ generate\ new\ library=Unable to generate new library +Found\ identical\ ranges=Found identical ranges +Found\ overlapping\ ranges=Found overlapping ranges +Found\ touching\ ranges=Found touching ranges + Note\:\ Use\ the\ placeholder\ %DIR%\ for\ the\ location\ of\ the\ opened\ library\ file.=Note: Use the placeholder %DIR% for the location of the opened library file. Error\ occured\ while\ executing\ the\ command\ \"%0\".=Error occured while executing the command \"%0\". Reformat\ ISSN=Reformat ISSN From c50c458643b6de3be4f6d217baf38d14702c1a2c Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 11:58:32 +0200 Subject: [PATCH 026/103] add actions --- .../logic/openoffice/action/EditInsert.java | 130 ++++++ .../logic/openoffice/action/EditMerge.java | 372 ++++++++++++++++++ .../logic/openoffice/action/EditSeparate.java | 106 +++++ .../logic/openoffice/action/ExportCited.java | 98 +++++ .../openoffice/action/ManageCitations.java | 41 ++ .../logic/openoffice/action/Update.java | 145 +++++++ 6 files changed, 892 insertions(+) create mode 100644 src/main/java/org/jabref/logic/openoffice/action/EditInsert.java create mode 100644 src/main/java/org/jabref/logic/openoffice/action/EditMerge.java create mode 100644 src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java create mode 100644 src/main/java/org/jabref/logic/openoffice/action/ExportCited.java create mode 100644 src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java create mode 100644 src/main/java/org/jabref/logic/openoffice/action/Update.java diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java new file mode 100644 index 00000000000..277b92bec76 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java @@ -0,0 +1,130 @@ +package org.jabref.logic.openoffice.action; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import org.jabref.logic.JabRefException; +import org.jabref.logic.openoffice.frontend.OOFrontend; +import org.jabref.logic.openoffice.frontend.UpdateCitationMarkers; +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.Citation; +import org.jabref.model.openoffice.style.CitationMarkerEntry; +import org.jabref.model.openoffice.style.CitationType; +import org.jabref.model.openoffice.style.NonUniqueCitationMarker; +import org.jabref.model.openoffice.style.OODataModel; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoScreenRefresh; +import org.jabref.model.openoffice.util.OOListUtil; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EditInsert { + + private static final Logger LOGGER = LoggerFactory.getLogger(EditInsert.class); + + /** + * In insertEntry we receive BibEntry values from the GUI. + * + * In the document we store citations by their citation key. + * + * If the citation key is missing, the best we can do is to notify + * the user. Or the programmer, that we cannot accept such input. + * + */ + private static String insertEntryGetCitationKey(BibEntry entry) { + Optional key = entry.getCitationKey(); + if (key.isEmpty()) { + throw new RuntimeException("insertEntryGetCitationKey:" + + " cannot cite entries without citation key"); + } + return key.get(); + } + + /* + * @param cursor Where to insert. + * + * @param sync If not empty, update citation markers and, + * depending on the embedded options, the + * bibliography. + * + * @param fcursor If sync.isPresent(), it must provide a + * FunctionalTextViewCursor. Otherwise not used. + */ + public static void insertCitationGroup(XTextDocument doc, + OOFrontend fr, + XTextCursor cursor, + List entries, + BibDatabase database, + OOBibStyle style, + CitationType citationType, + String pageInfo) + throws + UnknownPropertyException, + NoDocumentException, + NotRemoveableException, + WrappedTargetException, + PropertyVetoException, + PropertyExistException, + NoSuchElementException, + CreationException, + IllegalTypeException, + JabRefException { + + List citationKeys = OOListUtil.map(entries, EditInsert::insertEntryGetCitationKey); + + final int nEntries = entries.size(); + List> pageInfos = OODataModel.fakePageInfos(pageInfo, nEntries); + + List citations = new ArrayList<>(nEntries); + for (int i = 0; i < nEntries; i++) { + Citation cit = new Citation(citationKeys.get(i)); + cit.lookupInDatabases(Collections.singletonList(database)); + cit.setPageInfo(pageInfos.get(i)); + citations.add(cit); + } + + // The text we insert + OOText citeText = + (style.isNumberEntries() + ? OOText.fromString("[-]") // A dash only. Only refresh later. + : style.createCitationMarker(citations, + citationType.inParenthesis(), + NonUniqueCitationMarker.FORGIVEN)); + + if ("".equals(OOText.toString(citeText))) { + citeText = OOText.fromString("[?]"); + } + + try { + UnoScreenRefresh.lockControllers(doc); + UpdateCitationMarkers.createAndFillCitationGroup(fr, + doc, + citationKeys, + pageInfos, + citationType, + citeText, + cursor, + style, + true /* insertSpaceAfter */); + } finally { + UnoScreenRefresh.unlockControllers(doc); + } + + } +} diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java new file mode 100644 index 00000000000..823610c51cf --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java @@ -0,0 +1,372 @@ +package org.jabref.logic.openoffice.action; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.jabref.logic.JabRefException; +import org.jabref.logic.openoffice.frontend.OOFrontend; +import org.jabref.logic.openoffice.frontend.UpdateCitationMarkers; +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.Citation; +import org.jabref.model.openoffice.style.CitationGroup; +import org.jabref.model.openoffice.style.CitationType; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoScreenRefresh; +import org.jabref.model.openoffice.uno.UnoTextRange; +import org.jabref.model.openoffice.util.OOListUtil; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import com.sun.star.util.InvalidStateException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EditMerge { + + private static final Logger LOGGER = LoggerFactory.getLogger(EditMerge.class); + + private EditMerge() { + // hide constructor + } + + /* + * @return true if modified document + */ + public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend fr, OOBibStyle style) + throws + CreationException, + IllegalArgumentException, + IllegalTypeException, + InvalidStateException, + JabRefException, + NoDocumentException, + NoSuchElementException, + NotRemoveableException, + PropertyExistException, + PropertyVetoException, + UnknownPropertyException, + WrappedTargetException { + + boolean madeModifications = false; + + try { + UnoScreenRefresh.lockControllers(doc); + + List joinableGroups = EditMerge.scan(doc, fr); + + for (JoinableGroupData joinableGroupData : joinableGroups) { + + List cgs = joinableGroupData.group; + + List newCitations = (cgs.stream() + .flatMap(cg -> cg.citationsInStorageOrder.stream()) + .collect(Collectors.toList())); + + CitationType citationType = cgs.get(0).citationType; + List> pageInfos = fr.backend.combinePageInfos(cgs); + + fr.removeCitationGroups(cgs, doc); + XTextCursor textCursor = joinableGroupData.groupCursor; + textCursor.setString(""); // Also remove the spaces between. + + List citationKeys = OOListUtil.map(newCitations, Citation::getCitationKey); + + /* insertSpaceAfter: no, it is already there (or could be) */ + boolean insertSpaceAfter = false; + UpdateCitationMarkers.createAndFillCitationGroup(fr, + doc, + citationKeys, + pageInfos, + citationType, + OOText.fromString("tmp"), + textCursor, + style, + insertSpaceAfter); + } + + madeModifications = !joinableGroups.isEmpty(); + + } finally { + UnoScreenRefresh.unlockControllers(doc); + } + + return madeModifications; + } + + private static class JoinableGroupData { + /* + * A list of consecutive citation groups only separated by spaces. + */ + List group; + /* + * A cursor covering the XTextRange of each entry in group + * (and the spaces between them) + */ + XTextCursor groupCursor; + + JoinableGroupData(List group, XTextCursor groupCursor) { + this.group = group; + this.groupCursor = groupCursor; + } + } + + private static class ScanState { + + // Citation groups in the current group + List currentGroup; + + // A cursor that covers the Citation groups in currentGroup, + // including the space between them. + // Null if currentGroup.isEmpty() + XTextCursor currentGroupCursor; + + // A cursor starting at the end of the last CitationGroup in + // currentGroup. Null if currentGroup.isEmpty() + XTextCursor cursorBetween; + + // The last element of currentGroup. + // Null if currentGroup.isEmpty() + CitationGroup prev; + + // The XTextRange for prev. + // Null if currentGroup.isEmpty() + XTextRange prevRange; + + ScanState() { + reset(); + } + + void reset() { + currentGroup = new ArrayList<>(); + currentGroupCursor = null; + cursorBetween = null; + prev = null; + prevRange = null; + } + } + + /** + * Decide if cg could be added to state.currentGroup + * + * @param cg The CitationGroup to test + * @param currentRange The XTextRange corresponding to cg. + * + * @return false if cannot add, true if can. If returned true, + * then state.cursorBetween and state.currentGroupCursor are + * expanded to end at the start of currentRange. + */ + private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextRange currentRange) { + + if (state.currentGroup.isEmpty()) { + return false; + } + + Objects.requireNonNull(state.currentGroupCursor); + Objects.requireNonNull(state.cursorBetween); + Objects.requireNonNull(state.prev); + Objects.requireNonNull(state.prevRange); + + // Only combine (Author 2000) type citations + if (cg.citationType != CitationType.AUTHORYEAR_PAR) { + return false; + } + + if (state.prev != null) { + + // Even if we combine AUTHORYEAR_INTEXT citations, we + // would not mix them with AUTHORYEAR_PAR + if (cg.citationType != state.prev.citationType) { + return false; + } + + if (!UnoTextRange.comparables(state.prevRange, currentRange)) { + return false; + } + + // Sanity check: the current range should start later than + // the previous. + int textOrder = UnoTextRange.compareStarts(state.prevRange, currentRange); + if (textOrder != (-1)) { + String msg = + String.format("MergeCitationGroups:" + + " \"%s\" supposed to be followed by \"%s\"," + + " but %s", + state.prevRange.getString(), + currentRange.getString(), + ((textOrder == 0) + ? "they start at the same position" + : ("the start of the latter precedes" + + " the start of the first"))); + LOGGER.warn(msg); + return false; + } + } + + if (state.cursorBetween == null) { + return false; + } + + Objects.requireNonNull(state.cursorBetween); + Objects.requireNonNull(state.currentGroupCursor); + + // assume: currentGroupCursor.getEnd() == cursorBetween.getEnd() + if (UnoTextRange.compareEnds(state.cursorBetween, state.currentGroupCursor) != 0) { + String msg = ("MergeCitationGroups:" + + " cursorBetween.end != currentGroupCursor.end"); + throw new RuntimeException(msg); + } + + /* + * Try to expand state.currentGroupCursor and state.cursorBetween by going right + * to reach rangeStart. + */ + XTextRange rangeStart = currentRange.getStart(); + boolean couldExpand = true; + XTextCursor thisCharCursor = + (currentRange.getText().createTextCursorByRange(state.cursorBetween.getEnd())); + + while (couldExpand && (UnoTextRange.compareEnds(state.cursorBetween, rangeStart) < 0)) { + // + // Check that we only walk through inline whitespace. + // + couldExpand = thisCharCursor.goRight((short) 1, true); + String thisChar = thisCharCursor.getString(); + thisCharCursor.collapseToEnd(); + if (thisChar.isEmpty() || thisChar.equals("\n") || !thisChar.trim().isEmpty()) { + couldExpand = false; + if (!thisChar.isEmpty()) { + thisCharCursor.goLeft((short) 1, false); + } + break; + } + state.cursorBetween.goRight((short) 1, true); + state.currentGroupCursor.goRight((short) 1, true); + + // These two should move in sync: + if (UnoTextRange.compareEnds(state.cursorBetween, state.currentGroupCursor) != 0) { + String msg = ("MergeCitationGroups:" + + " cursorBetween.end != currentGroupCursor.end" + + " (during expand)"); + throw new RuntimeException(msg); + } + } // while + + if (!couldExpand) { + return false; + } + + return true; + } + + /** + * Add cg to state.currentGroup + * Set state.cursorBetween to start at currentRange.getEnd() + * Expand state.currentGroupCursor to also cover currentRange + * Set state.prev to cg, state.prevRange to currentRange + */ + private static void addToCurrentGroup(ScanState state, CitationGroup cg, XTextRange currentRange) { + final boolean isNewGroup = state.currentGroup.isEmpty(); + if (!isNewGroup) { + Objects.requireNonNull(state.currentGroupCursor); + Objects.requireNonNull(state.cursorBetween); + Objects.requireNonNull(state.prev); + Objects.requireNonNull(state.prevRange); + } + + // Add the current entry to a group. + state.currentGroup.add(cg); + + // Set up cursorBetween to start at currentRange.getEnd() + XTextRange rangeEnd = currentRange.getEnd(); + state.cursorBetween = currentRange.getText().createTextCursorByRange(rangeEnd); + + // If new group, create currentGroupCursor + if (isNewGroup) { + state.currentGroupCursor = (currentRange.getText() + .createTextCursorByRange(currentRange.getStart())); + } + + // include currentRange in currentGroupCursor + state.currentGroupCursor.goRight((short) (currentRange.getString().length()), true); + + if (UnoTextRange.compareEnds(state.cursorBetween, state.currentGroupCursor) != 0) { + String msg = ("MergeCitationGroups: cursorBetween.end != currentGroupCursor.end"); + throw new RuntimeException(msg); + } + + /* Store data about last entry in currentGroup */ + state.prev = cg; + state.prevRange = currentRange; + } + + /** + * Scan the document for joinable groups. Return those found. + */ + private static List scan(XTextDocument doc, OOFrontend fr) + throws + NoDocumentException, + WrappedTargetException { + List result = new ArrayList<>(); + + List cgs = + fr.getCitationGroupsSortedWithinPartitions(doc, + false /* mapFootnotesToFootnoteMarks */); + if (cgs.isEmpty()) { + return result; + } + + ScanState state = new ScanState(); + + for (CitationGroup cg : cgs) { + + XTextRange currentRange = (fr.getMarkRange(doc, cg) + .orElseThrow(RuntimeException::new)); + + /* + * Decide if we add cg to the group. False when the group is empty. + */ + boolean addToGroup = checkAddToGroup(state, cg, currentRange); + + /* + * Even if we do not add it to an existing group, + * we might use it to start a new group. + * + * Can it start a new group? + */ + boolean canStartGroup = (cg.citationType == CitationType.AUTHORYEAR_PAR); + + if (!addToGroup) { + // close currentGroup + if (state.currentGroup.size() > 1) { + result.add(new JoinableGroupData(state.currentGroup, state.currentGroupCursor)); + } + // Start a new, empty group + state.reset(); + } + + if (addToGroup || canStartGroup) { + addToCurrentGroup(state, cg, currentRange); + } + } + + // close currentGroup + if (state.currentGroup.size() > 1) { + result.add(new JoinableGroupData(state.currentGroup, state.currentGroupCursor)); + } + return result; + } + +} diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java new file mode 100644 index 00000000000..31c23ed52d0 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java @@ -0,0 +1,106 @@ +package org.jabref.logic.openoffice.action; + +import java.util.List; + +import org.jabref.logic.JabRefException; +import org.jabref.logic.openoffice.frontend.OOFrontend; +import org.jabref.logic.openoffice.frontend.UpdateCitationMarkers; +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.logic.openoffice.style.OOProcess; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.openoffice.ootext.OOText; +import org.jabref.model.openoffice.style.Citation; +import org.jabref.model.openoffice.style.CitationGroup; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoScreenRefresh; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import com.sun.star.util.InvalidStateException; + +public class EditSeparate { + + public static boolean separateCitations(XTextDocument doc, + OOFrontend fr, + List databases, + OOBibStyle style) + throws + CreationException, + IllegalTypeException, + InvalidStateException, + JabRefException, + NoDocumentException, + NoSuchElementException, + NotRemoveableException, + PropertyExistException, + PropertyVetoException, + UnknownPropertyException, + WrappedTargetException, + com.sun.star.lang.IllegalArgumentException { + + boolean madeModifications = false; + + // To reduce surprises in JabRef52 mode, impose localOrder to + // decide the visually last Citation in the group. Unless the + // style changed since refresh this is the last on the screen + // as well. + fr.citationGroups.lookupCitations(databases); + fr.citationGroups.imposeLocalOrder(OOProcess.comparatorForMulticite(style)); + + List cgs = fr.citationGroups.getCitationGroupsUnordered(); + + try { + UnoScreenRefresh.lockControllers(doc); + + for (CitationGroup cg : cgs) { + + XTextRange range1 = (fr + .getMarkRange(doc, cg) + .orElseThrow(RuntimeException::new)); + XTextCursor textCursor = range1.getText().createTextCursorByRange(range1); + + List cits = cg.citationsInStorageOrder; + if (cits.size() <= 1) { + continue; + } + + fr.removeCitationGroup(cg, doc); + // Now we own the content of cits + + // Create a citation group for each citation. + final int last = cits.size() - 1; + for (int i = 0; i < cits.size(); i++) { + boolean insertSpaceAfter = (i != last); + Citation cit = cits.get(i); + + UpdateCitationMarkers.createAndFillCitationGroup( + fr, + doc, + List.of(cit.citationKey), + List.of(cit.getPageInfo()), + cg.citationType, + OOText.fromString(cit.citationKey), + textCursor, + style, + insertSpaceAfter); + + textCursor.collapseToEnd(); + } + + madeModifications = true; + } + } finally { + UnoScreenRefresh.unlockControllers(doc); + } + return madeModifications; + } +} diff --git a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java new file mode 100644 index 00000000000..8d344688c68 --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java @@ -0,0 +1,98 @@ +package org.jabref.logic.openoffice.action; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.jabref.logic.openoffice.frontend.OOFrontend; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.StandardField; +import org.jabref.model.openoffice.style.CitedKey; +import org.jabref.model.openoffice.style.CitedKeys; +import org.jabref.model.openoffice.uno.NoDocumentException; + +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextDocument; + +public class ExportCited { + + public static class GenerateDatabaseResult { + /** + * null: not done; isEmpty: no unresolved + */ + public final List unresolvedKeys; + public final BibDatabase newDatabase; + + GenerateDatabaseResult(List unresolvedKeys, BibDatabase newDatabase) { + this.unresolvedKeys = unresolvedKeys; + this.newDatabase = newDatabase; + } + } + + /** + * + * @param databases The databases to look up the citation keys in the document from. + * @return A new database, with cloned entries. + * + * If a key is not found, it is added to result.unresolvedKeys + * + * Cross references (in StandardField.CROSSREF) are followed (not recursively): + * if the referenced entry is found, it is included in the result. + * If it is not found, it is silently ignored. + */ + public static GenerateDatabaseResult generateDatabase(XTextDocument doc, List databases) + throws + NoDocumentException, + NoSuchElementException, + UnknownPropertyException, + WrappedTargetException { + + OOFrontend fr = new OOFrontend(doc); + CitedKeys cks = fr.citationGroups.getCitedKeysUnordered(); + cks.lookupInDatabases(databases); + + List unresolvedKeys = new ArrayList<>(); + BibDatabase resultDatabase = new BibDatabase(); + + List entriesToInsert = new ArrayList<>(); + Set seen = new HashSet<>(); // Only add crossReference once. + + for (CitedKey ck : cks.values()) { + if (ck.getLookupResult().isEmpty()) { + unresolvedKeys.add(ck.citationKey); + continue; + } else { + BibEntry entry = ck.getLookupResult().get().entry; + BibDatabase loopDatabase = ck.getLookupResult().get().database; + + // If entry found + BibEntry clonedEntry = (BibEntry) entry.clone(); + + // Insert a copy of the entry + entriesToInsert.add(clonedEntry); + + // Check if the cloned entry has a cross-reference field + clonedEntry + .getField(StandardField.CROSSREF) + .ifPresent(crossReference -> { + boolean isNew = !seen.contains(crossReference); + if (isNew) { + // Add it if it is in the current library + loopDatabase + .getEntryByCitationKey(crossReference) + .ifPresent(entriesToInsert::add); + seen.add(crossReference); + } + }); + } + } + + resultDatabase.insertEntries(entriesToInsert); + return new GenerateDatabaseResult(unresolvedKeys, resultDatabase); + } + +} diff --git a/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java b/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java new file mode 100644 index 00000000000..4046cbbe11b --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java @@ -0,0 +1,41 @@ +package org.jabref.logic.openoffice.action; + +import java.util.List; + +import org.jabref.logic.openoffice.frontend.OOFrontend; +import org.jabref.model.openoffice.CitationEntry; +import org.jabref.model.openoffice.uno.NoDocumentException; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextDocument; + +public class ManageCitations { + + public static List getCitationEntries(XTextDocument doc) + throws + NoDocumentException, + UnknownPropertyException, + WrappedTargetException { + OOFrontend fr = new OOFrontend(doc); + return fr.getCitationEntries(doc); + } + + public static void applyCitationEntries(XTextDocument doc, List citationEntries) + throws + NoDocumentException, + UnknownPropertyException, + NotRemoveableException, + PropertyExistException, + PropertyVetoException, + IllegalTypeException, + WrappedTargetException, + IllegalArgumentException { + OOFrontend fr = new OOFrontend(doc); + fr.applyCitationEntries(doc, citationEntries); + } +} diff --git a/src/main/java/org/jabref/logic/openoffice/action/Update.java b/src/main/java/org/jabref/logic/openoffice/action/Update.java new file mode 100644 index 00000000000..151e4b6575b --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/action/Update.java @@ -0,0 +1,145 @@ +package org.jabref.logic.openoffice.action; + +import java.util.List; + +import org.jabref.logic.JabRefException; +import org.jabref.logic.openoffice.frontend.OOFrontend; +import org.jabref.logic.openoffice.frontend.UpdateBibliography; +import org.jabref.logic.openoffice.frontend.UpdateCitationMarkers; +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.logic.openoffice.style.OOProcess; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.openoffice.rangesort.FunctionalTextViewCursor; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoScreenRefresh; + +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextDocument; + +/* + * Update document: citation marks and bibliography + */ +public class Update { + + /* + * @return unresolvedKeys + */ + private static List updateDocument(XTextDocument doc, + OOFrontend fr, + List databases, + OOBibStyle style, + FunctionalTextViewCursor fcursor, + boolean doUpdateBibliography, + boolean alwaysAddCitedOnPages) + throws + CreationException, + JabRefException, + NoDocumentException, + NoSuchElementException, + PropertyVetoException, + UnknownPropertyException, + WrappedTargetException, + com.sun.star.lang.IllegalArgumentException { + + final boolean useLockControllers = true; + + fr.imposeGlobalOrder(doc, fcursor); + OOProcess.produceCitationMarkers(fr.citationGroups, databases, style); + + try { + if (useLockControllers) { + UnoScreenRefresh.lockControllers(doc); + } + + UpdateCitationMarkers.applyNewCitationMarkers(doc, fr, style); + + if (doUpdateBibliography) { + UpdateBibliography.rebuildBibTextSection(doc, + fr, + fr.citationGroups.getBibliography().get(), + style, + alwaysAddCitedOnPages); + } + List result = fr.citationGroups.getUnresolvedKeys(); + return result; + } finally { + if (useLockControllers && UnoScreenRefresh.hasControllersLocked(doc)) { + UnoScreenRefresh.unlockControllers(doc); + } + } + } + + public static class SyncOptions { + + public final List databases; + boolean updateBibliography; + boolean alwaysAddCitedOnPages; + + public SyncOptions(List databases) { + this.databases = databases; + this.updateBibliography = false; + this.alwaysAddCitedOnPages = false; + } + + public SyncOptions setUpdateBibliography(boolean value) { + this.updateBibliography = value; + return this; + } + + public SyncOptions setAlwaysAddCitedOnPages(boolean value) { + this.alwaysAddCitedOnPages = value; + return this; + } + } + + public static List synchronizeDocument(XTextDocument doc, + OOFrontend fr, + OOBibStyle style, + FunctionalTextViewCursor fcursor, + SyncOptions syncOptions) + throws + CreationException, + JabRefException, + NoDocumentException, + NoSuchElementException, + PropertyVetoException, + UnknownPropertyException, + WrappedTargetException, + com.sun.star.lang.IllegalArgumentException { + + return Update.updateDocument(doc, + fr, + syncOptions.databases, + style, + fcursor, + syncOptions.updateBibliography, + syncOptions.alwaysAddCitedOnPages); + } + + /* + * Reread document before sync + */ + public static List resyncDocument(XTextDocument doc, + OOBibStyle style, + FunctionalTextViewCursor fcursor, + SyncOptions syncOptions) + throws + CreationException, + JabRefException, + NoDocumentException, + NoSuchElementException, + PropertyVetoException, + UnknownPropertyException, + WrappedTargetException, + com.sun.star.lang.IllegalArgumentException { + + OOFrontend fr = new OOFrontend(doc); + + return Update.synchronizeDocument(doc, fr, style, fcursor, syncOptions); + } + +} From 00527f441b8eb4a1a3561f652562c72d2661cc7e Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 12:16:34 +0200 Subject: [PATCH 027/103] add gui stuff --- .../org/jabref/gui/openoffice/OOBibBase2.java | 973 ++++++++++++++++++ .../gui/openoffice/OOBibBaseConnect.java | 259 +++++ .../org/jabref/gui/openoffice/OOError.java | 141 +++ .../openoffice/NoDocumentFoundException.java | 12 + src/main/resources/l10n/JabRef_en.properties | 72 ++ 5 files changed, 1457 insertions(+) create mode 100644 src/main/java/org/jabref/gui/openoffice/OOBibBase2.java create mode 100644 src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java create mode 100644 src/main/java/org/jabref/gui/openoffice/OOError.java create mode 100644 src/main/java/org/jabref/logic/openoffice/NoDocumentFoundException.java diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java new file mode 100644 index 00000000000..ca8324cda2a --- /dev/null +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java @@ -0,0 +1,973 @@ +package org.jabref.gui.openoffice; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import org.jabref.gui.DialogService; +import org.jabref.logic.JabRefException; +import org.jabref.logic.l10n.Localization; +import org.jabref.logic.openoffice.NoDocumentFoundException; +import org.jabref.logic.openoffice.action.EditInsert; +import org.jabref.logic.openoffice.action.EditMerge; +import org.jabref.logic.openoffice.action.EditSeparate; +import org.jabref.logic.openoffice.action.ExportCited; +import org.jabref.logic.openoffice.action.ManageCitations; +import org.jabref.logic.openoffice.action.Update; +import org.jabref.logic.openoffice.frontend.OOFrontend; +import org.jabref.logic.openoffice.frontend.RangeForOverlapCheck; +import org.jabref.logic.openoffice.style.OOBibStyle; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.openoffice.CitationEntry; +import org.jabref.model.openoffice.rangesort.FunctionalTextViewCursor; +import org.jabref.model.openoffice.style.CitationGroupId; +import org.jabref.model.openoffice.style.CitationType; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoCrossRef; +import org.jabref.model.openoffice.uno.UnoCursor; +import org.jabref.model.openoffice.uno.UnoRedlines; +import org.jabref.model.openoffice.uno.UnoStyle; +import org.jabref.model.openoffice.uno.UnoUndo; +import org.jabref.model.openoffice.util.OOResult; +import org.jabref.model.openoffice.util.OOVoidResult; + +import com.sun.star.beans.IllegalTypeException; +import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyExistException; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.comp.helper.BootstrapException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.lang.DisposedException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextCursor; +import com.sun.star.text.XTextDocument; +import com.sun.star.util.InvalidStateException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class for manipulating the Bibliography of the currently started + * document in OpenOffice. + */ +class OOBibBase2 { + + private static final Logger LOGGER = LoggerFactory.getLogger(OOBibBase2.class); + + /* variables */ + private final DialogService dialogService; + + /* + * After inserting a citation, if ooPrefs.getSyncWhenCiting() returns true, + * shall we also update the bibliography? + */ + private final boolean refreshBibliographyDuringSyncWhenCiting; + + /* + * Shall we add "Cited on pages: ..." to resolved bibliography entries? + */ + private final boolean alwaysAddCitedOnPages; + + private final OOBibBaseConnect connection; + + /* + * Constructor + */ + public OOBibBase2(Path loPath, DialogService dialogService) + throws + BootstrapException, + CreationException { + + this.dialogService = dialogService; + this.connection = new OOBibBaseConnect(loPath, dialogService); + + this.refreshBibliographyDuringSyncWhenCiting = false; + this.alwaysAddCitedOnPages = false; + } + + public void guiActionSelectDocument(boolean autoSelectForSingle) { + final String title = Localization.lang("Problem connecting"); + + try { + + this.connection.selectDocument(autoSelectForSingle); + + } catch (NoDocumentFoundException ex) { + OOError.from(ex).showErrorDialog(dialogService); + } catch (DisposedException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (WrappedTargetException + | IndexOutOfBoundsException + | NoSuchElementException ex) { + LOGGER.warn("Problem connecting", ex); + OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + } + + if (this.isConnectedToDocument()) { + dialogService.notify(Localization.lang("Connected to document") + ": " + + this.getCurrentDocumentTitle().orElse("")); + } + } + + /** + * A simple test for document availability. + * + * See also `isDocumentConnectionMissing` for a test + * actually attempting to use the connection. + * + */ + public boolean isConnectedToDocument() { + return this.connection.isConnectedToDocument(); + } + + /** + * @return true if we are connected to a document + */ + public boolean isDocumentConnectionMissing() { + return this.connection.isDocumentConnectionMissing(); + } + + /** + * Either return an XTextDocument or return JabRefException. + */ + public OOResult getXTextDocument() { + return this.connection.getXTextDocument(); + } + + /** + * The title of the current document, or Optional.empty() + */ + public Optional getCurrentDocumentTitle() { + return this.connection.getCurrentDocumentTitle(); + } + + /* ****************************************************** + * + * Tools to collect and show precondition test results + * + * ******************************************************/ + + void showDialog(OOError ex) { + ex.showErrorDialog(dialogService); + } + + void showDialog(String title, OOError ex) { + ex.setTitle(title).showErrorDialog(dialogService); + } + + OOVoidResult collectResults(String title, List> results) { + String msg = (results.stream() + .filter(e -> e.isError()) + .map(e -> e.getError().getLocalizedMessage()) + .collect(Collectors.joining("\n\n"))); + if (msg.isEmpty()) { + return OOVoidResult.ok(); + } else { + return OOVoidResult.error(new OOError(title, msg)); + } + } + + boolean testDialog(OOVoidResult res) { + return res.ifError(ex -> ex.showErrorDialog(dialogService)).isError(); + } + + boolean testDialog(String title, OOVoidResult res) { + return res.ifError(e -> showDialog(e.setTitle(title))).isError(); + } + + boolean testDialog(String title, List> results) { + return testDialog(title, collectResults(title, results)); + } + + @SafeVarargs + final boolean testDialog(String title, OOVoidResult... results) { + List> rs = Arrays.asList(results); + return testDialog(collectResults(title, rs)); + } + + /* + * + * Get the cursor positioned by the user for inserting text. + * + */ + OOResult getUserCursorForTextInsertion(XTextDocument doc, String title) { + + XTextCursor cursor; + // Get the cursor positioned by the user. + try { + cursor = UnoCursor.getViewCursor(doc).orElse(null); + } catch (RuntimeException ex) { + return OOResult.error(new OOError(title, + Localization.lang("Could not get the cursor."), + ex)); + } + + // Check for crippled XTextViewCursor + Objects.requireNonNull(cursor); + try { + cursor.getStart(); + } catch (com.sun.star.uno.RuntimeException ex) { + String msg = + Localization.lang("Please move the cursor" + + " to the location for the new citation.") + + "\n" + + Localization.lang("I cannot insert to the cursors current location."); + return OOResult.error(new OOError(title, msg, ex)); + } + return OOResult.ok(cursor); + } + + /** + * This may move the view cursor. + */ + OOResult getFunctionalTextViewCursor(XTextDocument doc, + String title) { + String messageOnFailureToObtain = + Localization.lang("Please move the cursor into the document text.") + + "\n" + + Localization.lang("To get the visual positions of your citations" + + " I need to move the cursor around," + + " but could not get it."); + OOResult result = FunctionalTextViewCursor.get(doc); + if (result.isError()) { + LOGGER.warn(result.getError()); + } + return result.mapError(detail -> new OOError(title, messageOnFailureToObtain)); + } + + private static OOVoidResult checkRangeOverlaps(XTextDocument doc, OOFrontend fr) { + final String title = "checkRangeOverlaps"; + boolean requireSeparation = false; + int maxReportedOverlaps = 10; + try { + return (fr.checkRangeOverlaps(doc, + new ArrayList<>(), + requireSeparation, + maxReportedOverlaps) + .mapError(OOError::from)); + } catch (NoDocumentException ex) { + return OOVoidResult.error(OOError.from(ex).setTitle(title)); + } catch (WrappedTargetException ex) { + return OOVoidResult.error(OOError.fromMisc(ex).setTitle(title)); + } + } + + private static OOVoidResult checkRangeOverlapsWithCursor(XTextDocument doc, OOFrontend fr) { + final String title = "checkRangeOverlapsWithCursor"; + + List> userRanges; + try { + userRanges = fr.viewCursorRanges(doc); + } catch (NoDocumentException ex) { + return OOVoidResult.error(OOError.from(ex).setTitle(title)); + } catch (WrappedTargetException ex) { + return OOVoidResult.error(OOError.fromMisc(ex).setTitle(title)); + } + + boolean requireSeparation = false; + OOVoidResult res; + try { + res = fr.checkRangeOverlapsWithCursor(doc, + userRanges, + requireSeparation); + } catch (NoDocumentException ex) { + return OOVoidResult.error(OOError.from(ex).setTitle(title)); + } catch (WrappedTargetException ex) { + return OOVoidResult.error(OOError.fromMisc(ex).setTitle(title)); + } + + if (res.isError()) { + final String xtitle = Localization.lang("The cursor is in protected area."); + return OOVoidResult.error(new OOError(xtitle, + xtitle + "\n" + + res.getError().getLocalizedMessage() + "\n")); + } + return res.mapError(OOError::from); + } + + /* + * + * Tests for preconditions. + * + */ + + private static OOVoidResult checkIfOpenOfficeIsRecordingChanges(XTextDocument doc) { + + String title = Localization.lang("Recording and/or Recorded changes"); + try { + boolean recordingChanges = UnoRedlines.getRecordChanges(doc); + int nRedlines = UnoRedlines.countRedlines(doc); + if (recordingChanges || nRedlines > 0) { + String msg = ""; + if (recordingChanges) { + msg += Localization.lang("Cannot work with" + + " [Edit]/[Track Changes]/[Record] turned on."); + } + if (nRedlines > 0) { + if (recordingChanges) { + msg += "\n"; + } + msg += Localization.lang("Changes by JabRef" + + " could result in unexpected interactions with" + + " recorded changes."); + msg += "\n"; + msg += Localization.lang("Use [Edit]/[Track Changes]/[Manage] to resolve them first."); + } + return OOVoidResult.error(new OOError(title, msg)); + } + } catch (UnknownPropertyException | WrappedTargetException ex) { + String msg = Localization.lang("Error while checking if Writer" + + " is recording changes or has recorded changes."); + return OOVoidResult.error(new OOError(title, msg, ex)); + } + return OOVoidResult.ok(); + } + + OOVoidResult styleIsRequired(OOBibStyle style) { + if (style == null) { + return OOVoidResult.error(OOError.noValidStyleSelected()); + } else { + return OOVoidResult.ok(); + } + } + + OOResult getFrontend(XTextDocument doc) { + final String title = "getFrontend"; + try { + return OOResult.ok(new OOFrontend(doc)); + } catch (NoDocumentException ex) { + return OOResult.error(OOError.from(ex).setTitle(title)); + } catch (WrappedTargetException + | RuntimeException ex) { + return OOResult.error(OOError.fromMisc(ex).setTitle(title)); + } + } + + OOVoidResult databaseIsRequired(List databases, + Supplier fun) { + if (databases == null || databases.isEmpty()) { + return OOVoidResult.error(fun.get()); + } else { + return OOVoidResult.ok(); + } + } + + OOVoidResult selectedBibEntryIsRequired(List entries, + Supplier fun) { + if (entries == null || entries.isEmpty()) { + return OOVoidResult.error(fun.get()); + } else { + return OOVoidResult.ok(); + } + } + + /* + * Checks existence and also checks if it is not an internal name. + */ + private OOVoidResult checkStyleExistsInTheDocument(String familyName, + String styleName, + XTextDocument doc, + String labelInJstyleFile, + String pathToStyleFile) + throws + NoSuchElementException, + WrappedTargetException { + + Optional internalName = UnoStyle.getInternalNameOfStyle(doc, familyName, styleName); + + if (internalName.isEmpty()) { + String msg = + switch (familyName) { + case UnoStyle.PARAGRAPH_STYLES -> + Localization.lang("The %0 paragraph style '%1' is missing from the document", + labelInJstyleFile, + styleName); + case UnoStyle.CHARACTER_STYLES -> + Localization.lang("The %0 character style '%1' is missing from the document", + labelInJstyleFile, + styleName); + default -> + throw new RuntimeException("Expected " + UnoStyle.CHARACTER_STYLES + + " or " + UnoStyle.PARAGRAPH_STYLES + + " for familyName"); + } + + "\n" + + Localization.lang("Please create it in the document or change in the file:") + + "\n" + + pathToStyleFile; + return OOVoidResult.error(new OOError("StyleIsNotKnown", msg)); + } + + if (!internalName.get().equals(styleName)) { + String msg = + switch (familyName) { + case UnoStyle.PARAGRAPH_STYLES -> + Localization.lang("The %0 paragraph style '%1' is a display name for '%2'.", + labelInJstyleFile, + styleName, + internalName.get()); + case UnoStyle.CHARACTER_STYLES -> + Localization.lang("The %0 character style '%1' is a display name for '%2'.", + labelInJstyleFile, + styleName, + internalName.get()); + default -> + throw new RuntimeException("Expected " + UnoStyle.CHARACTER_STYLES + + " or " + UnoStyle.PARAGRAPH_STYLES + + " for familyName"); + } + + "\n" + + Localization.lang("Please use the latter in the style file below" + + " to avoid localization problems.") + + "\n" + + pathToStyleFile; + return OOVoidResult.error(new OOError("StyleNameIsNotInternal", msg)); + } + return OOVoidResult.ok(); + } + + public OOVoidResult checkStylesExistInTheDocument(OOBibStyle style, XTextDocument doc) { + + String pathToStyleFile = style.getPath(); + + List> results = new ArrayList<>(); + try { + results.add(checkStyleExistsInTheDocument(UnoStyle.PARAGRAPH_STYLES, + style.getReferenceHeaderParagraphFormat(), + doc, + "ReferenceHeaderParagraphFormat", + pathToStyleFile)); + results.add(checkStyleExistsInTheDocument(UnoStyle.PARAGRAPH_STYLES, + style.getReferenceParagraphFormat(), + doc, + "ReferenceParagraphFormat", + pathToStyleFile)); + if (style.isFormatCitations()) { + results.add(checkStyleExistsInTheDocument(UnoStyle.CHARACTER_STYLES, + style.getCitationCharacterFormat(), + doc, + "CitationCharacterFormat", + pathToStyleFile)); + } + } catch (NoSuchElementException + | WrappedTargetException ex) { + results.add(OOVoidResult.error(new OOError("Other error in checkStyleExistsInTheDocument", + ex.getMessage(), + ex))); + } + + return collectResults("checkStyleExistsInTheDocument failed", results); + } + + /* + * + * ManageCitationsDialogView + * + */ + public Optional> guiActionGetCitationEntries() { + + final Optional> FAIL = Optional.empty(); + final String title = Localization.lang("Problem collecting citations"); + + OOResult odoc = getXTextDocument(); + if (testDialog(title, odoc.asVoidResult())) { + return FAIL; + } + XTextDocument doc = odoc.get(); + + if (testDialog(title, checkIfOpenOfficeIsRecordingChanges(doc))) { + LOGGER.warn(title); + return FAIL; + } + + try { + + return Optional.of(ManageCitations.getCitationEntries(doc)); + + } catch (NoDocumentException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + return FAIL; + } catch (DisposedException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + return FAIL; + } catch (UnknownPropertyException + | WrappedTargetException ex) { + LOGGER.warn(title, ex); + OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + return FAIL; + } + } + + /** + * Apply editable parts of citationEntries to the document: store + * pageInfo. + * + * Does not change presentation. + * + * Note: we use no undo context here, because only + * DocumentConnection.setUserDefinedStringPropertyValue() is called, + * and Undo in LO will not undo that. + * + * GUI: "Manage citations" dialog "OK" button. + * Called from: ManageCitationsDialogViewModel.storeSettings + * + *

+ * Currently the only editable part is pageInfo. + *

+ * Since the only call to applyCitationEntries() only changes + * pageInfo w.r.t those returned by getCitationEntries(), we can + * do with the following restrictions: + *

    + *
  • Missing pageInfo means no action.
  • + *
  • Missing CitationEntry means no action (no attempt to remove + * citation from the text).
  • + *
+ */ + public void guiActionApplyCitationEntries(List citationEntries) { + + final String title = Localization.lang("Problem modifying citation"); + + OOResult odoc = getXTextDocument(); + if (testDialog(title, odoc.asVoidResult())) { + return; + } + XTextDocument doc = odoc.get(); + + try { + + ManageCitations.applyCitationEntries(doc, citationEntries); + + } catch (NoDocumentException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (DisposedException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (UnknownPropertyException + | NotRemoveableException + | PropertyExistException + | PropertyVetoException + | IllegalTypeException + | WrappedTargetException + | com.sun.star.lang.IllegalArgumentException ex) { + LOGGER.warn(title, ex); + OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + } + } + + /** + * + * Creates a citation group from {@code entries} at the cursor. + * + * Uses LO undo context "Insert citation". + * + * Note: Undo does not remove or reestablish custom properties. + * + * @param entries The entries to cite. + * + * @param database The database the entries belong to (all of them). + * Used when creating the citation mark. + * + * Consistency: for each entry in {@entries}: looking it up in + * {@code syncOptions.get().databases} (if present) + * should yield {@code database}. + * + * @param style The bibliography style we are using. + * + * @param citationType Indicates whether it is an in-text + * citation, a citation in parenthesis or + * an invisible citation. + * + * @param pageInfo A single page-info for these entries. + * Attributed to the last entry. + * + * @param syncOptions Indicates whether in-text citations + * should be refreshed in the document. + * Optional.empty() indicates no refresh. + * Otherwise provides options for refreshing + * the reference list. + */ + public void guiActionInsertEntry(List entries, + BibDatabase database, + OOBibStyle style, + CitationType citationType, + String pageInfo, + Optional syncOptions) { + + final String title = "Could not insert citation"; + + OOResult odoc = getXTextDocument(); + if (testDialog(title, + odoc.asVoidResult(), + styleIsRequired(style), + selectedBibEntryIsRequired(entries, OOError::noEntriesSelectedForCitation))) { + return; + } + XTextDocument doc = odoc.get(); + + OOResult ofr = getFrontend(doc); + if (testDialog(title, ofr.asVoidResult())) { + return; + } + OOFrontend fr = ofr.get(); + + OOResult cursor = getUserCursorForTextInsertion(doc, title); + if (testDialog(title, cursor.asVoidResult())) { + return; + } + + if (testDialog(title, checkRangeOverlapsWithCursor(doc, fr))) { + return; + } + + if (testDialog(title, + checkStylesExistInTheDocument(style, doc), + checkIfOpenOfficeIsRecordingChanges(doc))) { + return; + } + + /* + * For sync we need a FunctionalTextViewCursor. + */ + OOResult fcursor = null; + if (syncOptions.isPresent()) { + fcursor = getFunctionalTextViewCursor(doc, title); + if (testDialog(title, fcursor.asVoidResult())) { + return; + } + } + + syncOptions + .map(e -> e.setUpdateBibliography(this.refreshBibliographyDuringSyncWhenCiting)) + .map(e -> e.setAlwaysAddCitedOnPages(this.alwaysAddCitedOnPages)); + + if (syncOptions.isPresent()) { + if (testDialog(databaseIsRequired(syncOptions.get().databases, + OOError::noDataBaseIsOpenForSyncingAfterCitation))) { + return; + } + } + + try { + UnoUndo.enterUndoContext(doc, "Insert citation"); + + EditInsert.insertCitationGroup(doc, + fr, + cursor.get(), + entries, + database, + style, + citationType, + pageInfo); + + if (syncOptions.isPresent()) { + Update.resyncDocument(doc, style, fcursor.get(), syncOptions.get()); + } + + } catch (NoDocumentException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + return; + } catch (DisposedException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + return; + } catch (JabRefException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + return; + } catch (CreationException + | IllegalTypeException + | NoSuchElementException + | NotRemoveableException + | PropertyExistException + | PropertyVetoException + | UnknownPropertyException + | WrappedTargetException ex) { + LOGGER.warn("Could not insert entry", ex); + OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + return; + } finally { + UnoUndo.leaveUndoContext(doc); + } + } + + /** + * GUI action "Merge citations" + * + */ + public void guiActionMergeCitationGroups(List databases, OOBibStyle style) { + + final String title = Localization.lang("Problem combining cite markers"); + + OOResult odoc = getXTextDocument(); + if (testDialog(title, + odoc.asVoidResult(), + styleIsRequired(style), + databaseIsRequired(databases, OOError::noDataBaseIsOpen))) { + return; + } + XTextDocument doc = odoc.get(); + + OOResult fcursor = getFunctionalTextViewCursor(doc, title); + + if (testDialog(title, + fcursor.asVoidResult(), + checkStylesExistInTheDocument(style, doc), + checkIfOpenOfficeIsRecordingChanges(doc))) { + return; + } + + try { + UnoUndo.enterUndoContext(doc, "Merge citations"); + + OOFrontend fr = new OOFrontend(doc); + boolean madeModifications = EditMerge.mergeCitationGroups(doc, fr, style); + if (madeModifications) { + UnoCrossRef.refresh(doc); + Update.SyncOptions syncOptions = new Update.SyncOptions(databases); + Update.resyncDocument(doc, style, fcursor.get(), syncOptions); + } + + } catch (NoDocumentException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (DisposedException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (JabRefException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (CreationException + | IllegalTypeException + | InvalidStateException + | NoSuchElementException + | NotRemoveableException + | PropertyExistException + | PropertyVetoException + | UnknownPropertyException + | WrappedTargetException + | com.sun.star.lang.IllegalArgumentException ex) { + LOGGER.warn("Problem combining cite markers", ex); + OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + } finally { + UnoUndo.leaveUndoContext(doc); + fcursor.get().restore(doc); + } + } // MergeCitationGroups + + /** + * GUI action "Separate citations". + * + * Do the opposite of MergeCitationGroups. + * Combined markers are split, with a space inserted between. + */ + public void guiActionSeparateCitations(List databases, OOBibStyle style) { + + final String title = Localization.lang("Problem during separating cite markers"); + + OOResult odoc = getXTextDocument(); + if (testDialog(title, + odoc.asVoidResult(), + styleIsRequired(style), + databaseIsRequired(databases, OOError::noDataBaseIsOpen))) { + return; + } + + XTextDocument doc = odoc.get(); + OOResult fcursor = getFunctionalTextViewCursor(doc, title); + + if (testDialog(title, + fcursor.asVoidResult(), + checkStylesExistInTheDocument(style, doc), + checkIfOpenOfficeIsRecordingChanges(doc))) { + return; + } + + try { + UnoUndo.enterUndoContext(doc, "Separate citations"); + + OOFrontend fr = new OOFrontend(doc); + boolean madeModifications = EditSeparate.separateCitations(doc, fr, databases, style); + if (madeModifications) { + UnoCrossRef.refresh(doc); + Update.SyncOptions syncOptions = new Update.SyncOptions(databases); + Update.resyncDocument(doc, style, fcursor.get(), syncOptions); + } + + } catch (NoDocumentException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (DisposedException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (JabRefException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (CreationException + | IllegalTypeException + | InvalidStateException + | NoSuchElementException + | NotRemoveableException + | PropertyExistException + | PropertyVetoException + | UnknownPropertyException + | WrappedTargetException + | com.sun.star.lang.IllegalArgumentException ex) { + LOGGER.warn("Problem during separating cite markers", ex); + OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + } finally { + UnoUndo.leaveUndoContext(doc); + fcursor.get().restore(doc); + } + } + + /** + * GUI action for "Export cited" + * + * Does not refresh the bibliography. + * + * @param returnPartialResult If there are some unresolved keys, + * shall we return an otherwise nonempty result, or Optional.empty()? + */ + public Optional exportCitedHelper(List databases, + boolean returnPartialResult) { + + final Optional FAIL = Optional.empty(); + final String title = Localization.lang("Unable to generate new library"); + + OOResult odoc = getXTextDocument(); + if (testDialog(title, + odoc.asVoidResult(), + databaseIsRequired(databases, OOError::noDataBaseIsOpenForExport))) { + return FAIL; + } + XTextDocument doc = odoc.get(); + + try { + + ExportCited.GenerateDatabaseResult result; + try { + UnoUndo.enterUndoContext(doc, "Changes during \"Export cited\""); + result = ExportCited.generateDatabase(doc, databases); + } finally { + // There should be no changes, thus no Undo entry should appear + // in LibreOffice. + UnoUndo.leaveUndoContext(doc); + } + + if (!result.newDatabase.hasEntries()) { + dialogService.showErrorDialogAndWait( + Localization.lang("Unable to generate new library"), + Localization.lang("Your OpenOffice/LibreOffice document references" + + " no citation keys" + + " which could also be found in your current library.")); + return FAIL; + } + + List unresolvedKeys = result.unresolvedKeys; + if (!unresolvedKeys.isEmpty()) { + dialogService.showErrorDialogAndWait( + Localization.lang("Unable to generate new library"), + Localization.lang("Your OpenOffice/LibreOffice document references" + + " at least %0 citation keys" + + " which could not be found in your current library." + + " Some of these are %1.", + String.valueOf(unresolvedKeys.size()), + String.join(", ", unresolvedKeys))); + if (returnPartialResult) { + return Optional.of(result.newDatabase); + } else { + return FAIL; + } + } + return Optional.of(result.newDatabase); + } catch (NoDocumentException ex) { + OOError.from(ex).showErrorDialog(dialogService); + } catch (DisposedException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (NoSuchElementException + | UnknownPropertyException + | WrappedTargetException + | com.sun.star.lang.IllegalArgumentException ex) { + LOGGER.warn("Problem generating new database.", ex); + OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + } + return FAIL; + } + + /** + * GUI action, refreshes citation markers and bibliography. + * + * @param databases Must have at least one. + * @param style Style. + * + */ + public void guiActionUpdateDocument(List databases, OOBibStyle style) { + + final String title = Localization.lang("Unable to synchronize bibliography"); + + try { + + OOResult odoc = getXTextDocument(); + if (testDialog(title, + odoc.asVoidResult(), + styleIsRequired(style))) { + return; + } + + XTextDocument doc = odoc.get(); + + OOResult fcursor = getFunctionalTextViewCursor(doc, title); + + if (testDialog(title, + fcursor.asVoidResult(), + checkStylesExistInTheDocument(style, doc), + checkIfOpenOfficeIsRecordingChanges(doc))) { + return; + } + + OOFrontend fr = new OOFrontend(doc); + if (testDialog(title, checkRangeOverlaps(doc, fr))) { + return; + } + + List unresolvedKeys; + try { + UnoUndo.enterUndoContext(doc, "Refresh bibliography"); + + Update.SyncOptions syncOptions = new Update.SyncOptions(databases); + syncOptions + .setUpdateBibliography(true) + .setAlwaysAddCitedOnPages(this.alwaysAddCitedOnPages); + + unresolvedKeys = Update.synchronizeDocument(doc, fr, style, fcursor.get(), syncOptions); + + } finally { + UnoUndo.leaveUndoContext(doc); + fcursor.get().restore(doc); + } + + if (!unresolvedKeys.isEmpty()) { + String msg = Localization.lang( + "Your OpenOffice/LibreOffice document references the citation key '%0'," + + " which could not be found in your current library.", + unresolvedKeys.get(0)); + dialogService.showErrorDialogAndWait(title, msg); + return; + } + + } catch (JabRefException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (NoDocumentException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (DisposedException ex) { + OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + } catch (CreationException + | NoSuchElementException + | PropertyVetoException + | UnknownPropertyException + | WrappedTargetException + | com.sun.star.lang.IllegalArgumentException ex) { + LOGGER.warn("Could not update bibliography", ex); + OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + } + } + +} diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java b/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java new file mode 100644 index 00000000000..03765f8ffd8 --- /dev/null +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java @@ -0,0 +1,259 @@ +package org.jabref.gui.openoffice; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.jabref.gui.DialogService; +import org.jabref.logic.l10n.Localization; +import org.jabref.logic.openoffice.NoDocumentFoundException; +import org.jabref.model.openoffice.uno.CreationException; +import org.jabref.model.openoffice.uno.NoDocumentException; +import org.jabref.model.openoffice.uno.UnoCast; +import org.jabref.model.openoffice.uno.UnoTextDocument; +import org.jabref.model.openoffice.util.OOResult; + +import com.sun.star.comp.helper.BootstrapException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.container.XEnumeration; +import com.sun.star.container.XEnumerationAccess; +import com.sun.star.frame.XDesktop; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.lang.XComponent; +import com.sun.star.lang.XMultiComponentFactory; +import com.sun.star.text.XTextDocument; +import com.sun.star.uno.XComponentContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Establish connection to a document opened in OpenOffice or LibreOffice. + */ +class OOBibBaseConnect { + + private static final Logger LOGGER = LoggerFactory.getLogger(OOBibBaseConnect.class); + + /* variables */ + private final DialogService dialogService; + private final XDesktop xDesktop; + + /** + * Created when connected to a document. + * + * Cleared (to null) when we discover we lost the connection. + */ + private XTextDocument xTextDocument; + + /* + * Constructor + */ + public OOBibBaseConnect(Path loPath, DialogService dialogService) + throws + BootstrapException, + CreationException { + + this.dialogService = dialogService; + this.xDesktop = simpleBootstrap(loPath); + } + + private XDesktop simpleBootstrap(Path loPath) + throws + CreationException, + BootstrapException { + + // Get the office component context: + XComponentContext context = org.jabref.gui.openoffice.Bootstrap.bootstrap(loPath); + XMultiComponentFactory sem = context.getServiceManager(); + + // Create the desktop, which is the root frame of the + // hierarchy of frames that contain viewable components: + Object desktop; + try { + desktop = sem.createInstanceWithContext("com.sun.star.frame.Desktop", context); + } catch (Exception e) { + throw new CreationException(e.getMessage()); + } + return UnoCast.unoQI(XDesktop.class, desktop); + } + + private static List getTextDocuments(XDesktop desktop) + throws + NoSuchElementException, + WrappedTargetException { + + List result = new ArrayList<>(); + + XEnumerationAccess enumAccess = desktop.getComponents(); + XEnumeration compEnum = enumAccess.createEnumeration(); + + while (compEnum.hasMoreElements()) { + Object next = compEnum.nextElement(); + XComponent comp = UnoCast.unoQI(XComponent.class, next); + XTextDocument doc = UnoCast.unoQI(XTextDocument.class, comp); + if (doc != null) { + result.add(doc); + } + } + return result; + } + + /** + * Run a dialog allowing the user to choose among the documents in `list`. + * + * @return Null if no document was selected. Otherwise the + * document selected. + * + */ + private static XTextDocument selectDocumentDialog(List list, + DialogService dialogService) { + + class DocumentTitleViewModel { + + private final XTextDocument xTextDocument; + private final String description; + + public DocumentTitleViewModel(XTextDocument xTextDocument) { + this.xTextDocument = xTextDocument; + this.description = UnoTextDocument.getFrameTitle(xTextDocument).orElse(""); + } + + public XTextDocument getXtextDocument() { + return xTextDocument; + } + + @Override + public String toString() { + return description; + } + } + + List viewModel = (list.stream() + .map(DocumentTitleViewModel::new) + .collect(Collectors.toList())); + + // This whole method is part of a background task when + // auto-detecting instances, so we need to show dialog in FX + // thread + Optional selectedDocument = + (dialogService + .showChoiceDialogAndWait(Localization.lang("Select document"), + Localization.lang("Found documents:"), + Localization.lang("Use selected document"), + viewModel)); + + return (selectedDocument + .map(DocumentTitleViewModel::getXtextDocument) + .orElse(null)); + } + + /** + * Choose a document to work with. + * + * Assumes we have already connected to LibreOffice or OpenOffice. + * + * If there is a single document to choose from, selects that. + * If there are more than one, shows selection dialog. + * If there are none, throws NoDocumentFoundException + * + * After successful selection connects to the selected document + * and extracts some frequently used parts (starting points for + * managing its content). + * + * Finally initializes this.xTextDocument with the selected + * document and parts extracted. + * + */ + public void selectDocument(boolean autoSelectForSingle) + throws + NoDocumentFoundException, + NoSuchElementException, + WrappedTargetException { + + XTextDocument selected; + List textDocumentList = getTextDocuments(this.xDesktop); + if (textDocumentList.isEmpty()) { + throw new NoDocumentFoundException("No Writer documents found"); + } else if (textDocumentList.size() == 1 && autoSelectForSingle) { + selected = textDocumentList.get(0); // Get the only one + } else { // Bring up a dialog + selected = OOBibBaseConnect.selectDocumentDialog(textDocumentList, + this.dialogService); + } + + if (selected == null) { + return; + } + + this.xTextDocument = selected; + } + + /** + * Mark the current document as missing. + * + */ + private void forgetDocument() { + this.xTextDocument = null; + } + + /** + * A simple test for document availability. + * + * See also `isDocumentConnectionMissing` for a test + * actually attempting to use teh connection. + * + */ + public boolean isConnectedToDocument() { + return this.xTextDocument != null; + } + + /** + * @return true if we are connected to a document + */ + public boolean isDocumentConnectionMissing() { + XTextDocument doc = this.xTextDocument; + + if (doc == null) { + return true; + } + + if (UnoTextDocument.isDocumentConnectionMissing(doc)) { + forgetDocument(); + return true; + } + return false; + } + + /** + * Either return a valid XTextDocument or throw + * NoDocumentException. + */ + public XTextDocument getXTextDocumentOrThrow() + throws + NoDocumentException { + if (isDocumentConnectionMissing()) { + throw new NoDocumentException("Not connected to document"); + } + return this.xTextDocument; + } + + public OOResult getXTextDocument() { + if (isDocumentConnectionMissing()) { + return OOResult.error(OOError.from(new NoDocumentException())); + } + return OOResult.ok(this.xTextDocument); + } + + /** + * The title of the current document, or Optional.empty() + */ + public Optional getCurrentDocumentTitle() { + if (isDocumentConnectionMissing()) { + return Optional.empty(); + } else { + return UnoTextDocument.getFrameTitle(this.xTextDocument); + } + } + +} // end of OOBibBaseConnect diff --git a/src/main/java/org/jabref/gui/openoffice/OOError.java b/src/main/java/org/jabref/gui/openoffice/OOError.java new file mode 100644 index 00000000000..44e70b3e975 --- /dev/null +++ b/src/main/java/org/jabref/gui/openoffice/OOError.java @@ -0,0 +1,141 @@ +package org.jabref.gui.openoffice; + +import org.jabref.gui.DialogService; +import org.jabref.logic.JabRefException; +import org.jabref.logic.l10n.Localization; +import org.jabref.logic.openoffice.NoDocumentFoundException; +import org.jabref.model.openoffice.uno.NoDocumentException; + +import com.sun.star.lang.DisposedException; + +class OOError extends JabRefException { + + private String localizedTitle; + + public OOError(String title, String localizedMessage) { + super(localizedMessage, localizedMessage); + this.localizedTitle = title; + } + + public OOError(String title, String localizedMessage, Throwable cause) { + super(localizedMessage, localizedMessage, cause); + this.localizedTitle = title; + } + + public String getTitle() { + return localizedTitle; + } + + public OOError setTitle(String title) { + localizedTitle = title; + return this; + } + + public void showErrorDialog(DialogService dialogService) { + dialogService.showErrorDialogAndWait(getTitle(), getLocalizedMessage()); + } + + /* + * Conversions from exception caught + */ + + public static OOError from(JabRefException ex) { + return new OOError( + Localization.lang("JabRefException"), + ex.getLocalizedMessage(), + ex); + } + + // For DisposedException + public static OOError from(DisposedException ex) { + return new OOError( + Localization.lang("Connection lost"), + Localization.lang("Connection to OpenOffice/LibreOffice has been lost." + + " Please make sure OpenOffice/LibreOffice is running," + + " and try to reconnect."), + ex); + } + + // For NoDocumentException + public static OOError from(NoDocumentException ex) { + return new OOError( + Localization.lang("Not connected to document"), + Localization.lang("Not connected to any Writer document." + + " Please make sure a document is open," + + " and use the 'Select Writer document' button" + + " to connect to it."), + ex); + } + + // For NoDocumentFoundException + public static OOError from(NoDocumentFoundException ex) { + return new OOError( + Localization.lang("No Writer documents found"), + Localization.lang("Could not connect to any Writer document." + + " Please make sure a document is open" + + " before using the 'Select Writer document' button" + + " to connect to it."), + ex); + } + + public static OOError fromMisc(Exception ex) { + return new OOError( + "Exception", + ex.getMessage(), + ex); + } + + /* + * Messages for error dialog. These are not thrown. + */ + + // noDataBaseIsOpenForCiting + public static OOError noDataBaseIsOpenForCiting() { + return new OOError( + Localization.lang("No database"), + Localization.lang("No bibliography database is open for citation.") + + "\n" + + Localization.lang("Open one before citing.")); + } + + public static OOError noDataBaseIsOpenForSyncingAfterCitation() { + return new OOError( + Localization.lang("No database"), + Localization.lang("No database is open for updating citation markers after citing.") + + "\n" + + Localization.lang("Open one before citing.")); + } + + // noDataBaseIsOpenForExport + public static OOError noDataBaseIsOpenForExport() { + return new OOError( + Localization.lang("No database is open"), + Localization.lang("We need a database to export from. Open one.")); + } + + // noDataBaseIsOpenForExport + public static OOError noDataBaseIsOpen() { + return new OOError( + Localization.lang("No database is open"), + Localization.lang("This operation requires a bibliography database.")); + } + + // noValidStyleSelected + public static OOError noValidStyleSelected() { + return new OOError(Localization.lang("No valid style file defined"), + Localization.lang("No bibliography style is selected for citation.") + + "\n" + + Localization.lang("Select one before citing.") + + "\n" + + Localization.lang("You must select either a valid style file," + + " or use one of the default styles.")); + } + + // noEntriesSelectedForCitation + public static OOError noEntriesSelectedForCitation() { + return new OOError(Localization.lang("No entries selected for citation"), + Localization.lang("No bibliography entries are selected for citation.") + + "\n" + + Localization.lang("Select some before citing.")); + } +} diff --git a/src/main/java/org/jabref/logic/openoffice/NoDocumentFoundException.java b/src/main/java/org/jabref/logic/openoffice/NoDocumentFoundException.java new file mode 100644 index 00000000000..2759a9931aa --- /dev/null +++ b/src/main/java/org/jabref/logic/openoffice/NoDocumentFoundException.java @@ -0,0 +1,12 @@ +package org.jabref.logic.openoffice; + +public class NoDocumentFoundException extends Exception { + + public NoDocumentFoundException(String message) { + super(message); + } + + public NoDocumentFoundException() { + super("No Writer documents found"); + } +} diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index dc2fd8df58a..bf4c349bb76 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -505,6 +505,10 @@ Moved\ group\ "%0".=Moved group "%0". Mr.\ DLib\ Privacy\ settings=Mr. DLib Privacy settings +No\ database\ is\ open=No database is open + +We\ need\ a\ database\ to\ export\ from.\ Open\ one.=We need a database to export from. Open one. + No\ recommendations\ received\ from\ Mr.\ DLib\ for\ this\ entry.=No recommendations received from Mr. DLib for this entry. Error\ while\ fetching\ recommendations\ from\ Mr.DLib.=Error while fetching recommendations from Mr.DLib. @@ -1015,6 +1019,7 @@ Cite\ special=Cite special Extra\ information\ (e.g.\ page\ number)=Extra information (e.g. page number) Manage\ citations=Manage citations Problem\ modifying\ citation=Problem modifying citation +Problem\ collecting\ citations=Problem collecting citations Citation=Citation Connecting...=Connecting... Could\ not\ resolve\ BibTeX\ entry\ for\ citation\ marker\ '%0'.=Could not resolve BibTeX entry for citation marker '%0'. @@ -1029,10 +1034,23 @@ Select\ Writer\ document=Select Writer document Sync\ OpenOffice/LibreOffice\ bibliography=Sync OpenOffice/LibreOffice bibliography Select\ which\ open\ Writer\ document\ to\ work\ on=Select which open Writer document to work on Connected\ to\ document=Connected to document + +Could\ not\ connect\ to\ any\ Writer\ document.\ Please\ make\ sure\ a\ document\ is\ open\ before\ using\ the\ 'Select\ Writer\ document'\ button\ to\ connect\ to\ it.=Could not connect to any Writer document. Please make sure a document is open before using the 'Select Writer document' button to connect to it. + +No\ Writer\ documents\ found=No Writer documents found + Insert\ a\ citation\ without\ text\ (the\ entry\ will\ appear\ in\ the\ reference\ list)=Insert a citation without text (the entry will appear in the reference list) Cite\ selected\ entries\ with\ extra\ information=Cite selected entries with extra information Ensure\ that\ the\ bibliography\ is\ up-to-date=Ensure that the bibliography is up-to-date + Your\ OpenOffice/LibreOffice\ document\ references\ the\ citation\ key\ '%0',\ which\ could\ not\ be\ found\ in\ your\ current\ library.=Your OpenOffice/LibreOffice document references the citation key '%0', which could not be found in your current library. + +This\ operation\ requires\ a\ bibliography\ database.=This operation requires a bibliography database. + +Your\ OpenOffice/LibreOffice\ document\ references\ at\ least\ %0\ citation\ keys\ which\ could\ not\ be\ found\ in\ your\ current\ library.\ Some\ of\ these\ are\ %1.=Your OpenOffice/LibreOffice document references at least %0 citation keys which could not be found in your current library. Some of these are %1. + +Your\ OpenOffice/LibreOffice\ document\ references\ no\ citation\ keys\ which\ could\ also\ be\ found\ in\ your\ current\ library.=Your OpenOffice/LibreOffice document references no citation keys which could also be found in your current library. + Unable\ to\ synchronize\ bibliography=Unable to synchronize bibliography Combine\ pairs\ of\ citations\ that\ are\ separated\ by\ spaces\ only=Combine pairs of citations that are separated by spaces only Autodetection\ failed=Autodetection failed @@ -1040,6 +1058,12 @@ Please\ wait...=Please wait... Connection\ lost=Connection lost The\ paragraph\ format\ is\ controlled\ by\ the\ property\ 'ReferenceParagraphFormat'\ or\ 'ReferenceHeaderParagraphFormat'\ in\ the\ style\ file.=The paragraph format is controlled by the property 'ReferenceParagraphFormat' or 'ReferenceHeaderParagraphFormat' in the style file. The\ character\ format\ is\ controlled\ by\ the\ citation\ property\ 'CitationCharacterFormat'\ in\ the\ style\ file.=The character format is controlled by the citation property 'CitationCharacterFormat' in the style file. + +Not\ connected\ to\ document=Not connected to document +Problem\ combining\ cite\ markers=Problem combining cite markers + +Problem\ during\ separating\ cite\ markers=Problem during separating cite markers + Automatically\ sync\ bibliography\ when\ inserting\ citations=Automatically sync bibliography when inserting citations Look\ up\ BibTeX\ entries\ in\ the\ active\ tab\ only=Look up BibTeX entries in the active tab only Look\ up\ BibTeX\ entries\ in\ all\ open\ libraries=Look up BibTeX entries in all open libraries @@ -1134,7 +1158,9 @@ Toggle\ quality\ assured=Toggle quality assured Toggle\ print\ status=Toggle print status Update\ keywords=Update keywords Write\ values\ of\ special\ fields\ as\ separate\ fields\ to\ BibTeX=Write values of special fields as separate fields to BibTeX +Problem\ connecting=Problem connecting Connection\ to\ OpenOffice/LibreOffice\ has\ been\ lost.\ Please\ make\ sure\ OpenOffice/LibreOffice\ is\ running,\ and\ try\ to\ reconnect.=Connection to OpenOffice/LibreOffice has been lost. Please make sure OpenOffice/LibreOffice is running, and try to reconnect. + JabRef\ will\ send\ at\ least\ one\ request\ per\ entry\ to\ a\ publisher.=JabRef will send at least one request per entry to a publisher. Correct\ the\ entry,\ and\ reopen\ editor\ to\ display/edit\ source.=Correct the entry, and reopen editor to display/edit source. Could\ not\ connect\ to\ running\ OpenOffice/LibreOffice.=Could not connect to running OpenOffice/LibreOffice. @@ -1529,6 +1555,23 @@ Custom=Custom Export\ cited=Export cited Unable\ to\ generate\ new\ library=Unable to generate new library +Could\ not\ get\ the\ cursor.=Could not get the cursor. +The\ cursor\ is\ in\ protected\ area.=The cursor is in protected area. +JabRefException=JabRefException +No\ bibliography\ database\ is\ open\ for\ citation.=No bibliography database is open for citation. + +No\ database\ is\ open\ for\ updating\ citation\ markers\ after\ citing.=No database is open for updating citation markers after citing. + +No\ bibliography\ entries\ are\ selected\ for\ citation.=No bibliography entries are selected for citation. +No\ bibliography\ style\ is\ selected\ for\ citation.=No bibliography style is selected for citation. +No\ database=No database + +No\ entries\ selected\ for\ citation=No entries selected for citation +Open\ one\ before\ citing.=Open one before citing. + +Select\ one\ before\ citing.=Select one before citing. +Select\ some\ before\ citing.=Select some before citing. + Found\ identical\ ranges=Found identical ranges Found\ overlapping\ ranges=Found overlapping ranges Found\ touching\ ranges=Found touching ranges @@ -2300,6 +2343,35 @@ Customization=Customization Use\ custom\ DOI\ base\ URI\ for\ article\ access=Use custom DOI base URI for article access Cited\ on\ pages=Cited on pages +Please\ move\ the\ cursor\ into\ the\ document\ text.=Please\ move\ the\ cursor\ into\ the\ document\ text. +To\ get\ the\ visual\ positions\ of\ your\ citations\ I\ need\ to\ move\ the\ cursor\ around,\ but\ could\ not\ get\ it.=To\ get\ the\ visual\ positions\ of\ your\ citations\ I\ need\ to\ move\ the\ cursor\ around,\ but\ could\ not\ get\ it. + +I\ cannot\ insert\ to\ the\ cursors\ current\ location.=I\ cannot\ insert\ to\ the\ cursors\ current\ location. + +Please\ move\ the\ cursor\ to\ the\ location\ for\ the\ new\ citation.=Please\ move\ the\ cursor\ to\ the\ location\ for\ the\ new\ citation. + +Please\ create\ it\ in\ the\ document\ or\ change\ in\ the\ file\:=Please create it in the document or change in the file: + +Please\ use\ the\ latter\ in\ the\ style\ file\ below\ to\ avoid\ localization\ problems.=Please use the latter in the style file below to avoid localization problems. + +The\ %0\ character\ style\ '%1'\ is\ a\ display\ name\ for\ '%2'.=The %0 character style '%1' is a display name for '%2'. + +The\ %0\ character\ style\ '%1'\ is\ missing\ from\ the\ document=The %0 character style '%1' is missing from the document + +The\ %0\ paragraph\ style\ '%1'\ is\ a\ display\ name\ for\ '%2'.=The %0 paragraph style '%1' is a display name for '%2'. + +The\ %0\ paragraph\ style\ '%1'\ is\ missing\ from\ the\ document=The %0 paragraph style '%1' is missing from the document + +Error\ while\ checking\ if\ Writer\ is\ recording\ changes\ or\ has\ recorded\ changes.=Error while checking if Writer is recording changes or has recorded changes. + +Cannot\ work\ with\ [Edit]/[Track\ Changes]/[Record]\ turned\ on.=Cannot work with [Edit]/[Track Changes]/[Record] turned on. + +Changes\ by\ JabRef\ could\ result\ in\ unexpected\ interactions\ with\ recorded\ changes.=Changes by JabRef could result in unexpected interactions with recorded changes. + +Recording\ and/or\ Recorded\ changes=Recording and/or Recorded changes + +Use\ [Edit]/[Track\ Changes]/[Manage]\ to\ resolve\ them\ first.=Use [Edit]/[Track Changes]/[Manage] to resolve them first. + Unable\ to\ find\ valid\ certification\ path\ to\ requested\ target(%0),\ download\ anyway?=Unable to find valid certification path to requested target(%0), download anyway? Download\ operation\ canceled.=Download operation canceled. From 90078c76010c221099649696f799eb55f7b1ca1a Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 12:33:23 +0200 Subject: [PATCH 028/103] integrate --- .../openoffice/ManageCitationsDialogView.java | 16 +- .../ManageCitationsDialogViewModel.java | 45 +-- .../gui/openoffice/OpenOfficePanel.java | 355 ++++++++---------- src/main/resources/l10n/JabRef_en.properties | 12 +- 4 files changed, 178 insertions(+), 250 deletions(-) diff --git a/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogView.java b/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogView.java index a312a4ef375..872d1f8adc0 100644 --- a/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogView.java +++ b/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogView.java @@ -19,16 +19,13 @@ import org.jabref.model.strings.StringUtil; import com.airhacks.afterburner.views.ViewLoader; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; -import com.sun.star.lang.WrappedTargetException; public class ManageCitationsDialogView extends BaseDialog { private static final String HTML_BOLD_END_TAG = "
"; private static final String HTML_BOLD_START_TAG = ""; - private final OOBibBase ooBase; + private final OOBibBase2 ooBase; @FXML private TableView citationsTableView; @FXML private TableColumn citation; @@ -38,7 +35,7 @@ public class ManageCitationsDialogView extends BaseDialog { private ManageCitationsDialogViewModel viewModel; - public ManageCitationsDialogView(OOBibBase ooBase) { + public ManageCitationsDialogView(OOBibBase2 ooBase) { this.ooBase = ooBase; ViewLoader.view(this) @@ -56,7 +53,7 @@ public ManageCitationsDialogView(OOBibBase ooBase) { } @FXML - private void initialize() throws NoSuchElementException, WrappedTargetException, UnknownPropertyException { + private void initialize() { viewModel = new ManageCitationsDialogViewModel(ooBase, dialogService); @@ -90,4 +87,11 @@ private Node getText(String citationContext) { FlowPane flow = new FlowPane(startText, inBetweenText, endText); return flow; } + + public boolean isOkToShowThisDialog() { + if (viewModel == null || viewModel.failedToGetCitationEntries) { + return false; + } + return true; + } } diff --git a/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java b/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java index 40cee65036f..b854a445fa9 100644 --- a/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java +++ b/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java @@ -9,40 +9,26 @@ import javafx.collections.FXCollections; import org.jabref.gui.DialogService; -import org.jabref.logic.l10n.Localization; import org.jabref.model.openoffice.CitationEntry; -import com.sun.star.beans.IllegalTypeException; -import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; -import com.sun.star.container.XNameAccess; -import com.sun.star.lang.IllegalArgumentException; -import com.sun.star.lang.WrappedTargetException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class ManageCitationsDialogViewModel { - private static final Logger LOGGER = LoggerFactory.getLogger(ManageCitationsDialogViewModel.class); - + public final boolean failedToGetCitationEntries; private final ListProperty citations = new SimpleListProperty<>(FXCollections.observableArrayList()); - private final OOBibBase ooBase; + private final OOBibBase2 ooBase; private final DialogService dialogService; - public ManageCitationsDialogViewModel(OOBibBase ooBase, DialogService dialogService) throws NoSuchElementException, WrappedTargetException, UnknownPropertyException { + public ManageCitationsDialogViewModel(OOBibBase2 ooBase, DialogService dialogService) { this.ooBase = ooBase; this.dialogService = dialogService; - XNameAccess nameAccess = ooBase.getReferenceMarks(); - List names = ooBase.getJabRefReferenceMarks(nameAccess); - for (String name : names) { - - CitationEntry entry = new CitationEntry(name, - ooBase.getCitationContext(nameAccess, name, 30, 30, true), - ooBase.getCustomProperty(name)); + Optional> citationEntries = ooBase.guiActionGetCitationEntries(); + this.failedToGetCitationEntries = citationEntries.isEmpty(); + if (citationEntries.isEmpty()) { + return; + } + for (CitationEntry entry : citationEntries.get()) { CitationEntryViewModel itemViewModelEntry = new CitationEntryViewModel(entry); citations.add(itemViewModelEntry); } @@ -50,18 +36,7 @@ public ManageCitationsDialogViewModel(OOBibBase ooBase, DialogService dialogServ public void storeSettings() { List ciationEntries = citations.stream().map(CitationEntryViewModel::toCitationEntry).collect(Collectors.toList()); - try { - for (CitationEntry entry : ciationEntries) { - Optional pageInfo = entry.getPageInfo(); - if (pageInfo.isPresent()) { - ooBase.setCustomProperty(entry.getRefMarkName(), pageInfo.get()); - } - } - } catch (UnknownPropertyException | NotRemoveableException | PropertyExistException | IllegalTypeException | - IllegalArgumentException ex) { - LOGGER.warn("Problem modifying citation", ex); - dialogService.showErrorDialogAndWait(Localization.lang("Problem modifying citation"), ex); - } + ooBase.guiActionApplyCitationEntries(ciationEntries); } public ListProperty citationsProperty() { diff --git a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java index 367855a4b37..8b8f398c1ff 100644 --- a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java +++ b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java @@ -1,6 +1,5 @@ package org.jabref.gui.openoffice; -import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.nio.file.Path; @@ -46,24 +45,17 @@ import org.jabref.logic.l10n.Localization; import org.jabref.logic.openoffice.OpenOfficeFileSearch; import org.jabref.logic.openoffice.OpenOfficePreferences; -import org.jabref.logic.openoffice.UndefinedParagraphFormatException; +import org.jabref.logic.openoffice.action.Update; import org.jabref.logic.openoffice.style.OOBibStyle; import org.jabref.logic.openoffice.style.StyleLoader; import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; +import org.jabref.model.openoffice.style.CitationType; import org.jabref.model.openoffice.uno.CreationException; -import org.jabref.model.openoffice.uno.NoDocumentException; import org.jabref.preferences.PreferencesService; -import com.sun.star.beans.IllegalTypeException; -import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; -import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; import com.sun.star.comp.helper.BootstrapException; -import com.sun.star.container.NoSuchElementException; -import com.sun.star.lang.WrappedTargetException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -97,7 +89,7 @@ public class OpenOfficePanel { private final TaskExecutor taskExecutor; private final StyleLoader loader; private OpenOfficePreferences ooPrefs; - private OOBibBase ooBase; + private OOBibBase2 ooBase; private OOBibStyle style; public OpenOfficePanel(JabRefFrame frame, PreferencesService preferencesService, OpenOfficePreferences ooPrefs, KeyBindingRepository keyBindingRepository) { @@ -142,23 +134,40 @@ public Node getContent() { return vbox; } + /* Note: the style may still be null on return. + * + * Return true if failed. In this case the dialog is already shown. + */ + private boolean getOrUpdateTheStyle(String title) { + final boolean FAIL = true; + final boolean PASS = false; + + if (style == null) { + style = loader.getUsedStyle(); + } else { + try { + style.ensureUpToDate(); + } catch (IOException ex) { + LOGGER.warn("Unable to reload style file '" + style.getPath() + "'", ex); + String msg = (Localization.lang("Unable to reload style file") + + "'" + style.getPath() + "'" + + "\n" + ex.getMessage()); + new OOError(title, msg, ex).showErrorDialog(dialogService); + return FAIL; + } + } + return PASS; + } + private void initPanel() { connect.setOnAction(e -> connectAutomatically()); manualConnect.setOnAction(e -> connectManually()); selectDocument.setTooltip(new Tooltip(Localization.lang("Select which open Writer document to work on"))); - selectDocument.setOnAction(e -> { - try { - ooBase.selectDocument(); - dialogService.notify(Localization.lang("Connected to document") + ": " - + ooBase.getCurrentDocumentTitle().orElse("")); - } catch (WrappedTargetException | IndexOutOfBoundsException | - NoSuchElementException | NoDocumentException ex) { - LOGGER.warn("Problem connecting", ex); - dialogService.showErrorDialogAndWait(ex); - } + selectDocument.setOnAction(e -> { + ooBase.guiActionSelectDocument(false); }); setStyleFile.setMaxWidth(Double.MAX_VALUE); @@ -176,85 +185,39 @@ private void initPanel() { }); pushEntries.setTooltip(new Tooltip(Localization.lang("Cite selected entries between parenthesis"))); - pushEntries.setOnAction(e -> pushEntries(true, true, false)); + pushEntries.setOnAction(e -> pushEntries(CitationType.AUTHORYEAR_PAR, false)); pushEntries.setMaxWidth(Double.MAX_VALUE); pushEntriesInt.setTooltip(new Tooltip(Localization.lang("Cite selected entries with in-text citation"))); - pushEntriesInt.setOnAction(e -> pushEntries(false, true, false)); + pushEntriesInt.setOnAction(e -> pushEntries(CitationType.AUTHORYEAR_INTEXT, false)); pushEntriesInt.setMaxWidth(Double.MAX_VALUE); pushEntriesEmpty.setTooltip(new Tooltip(Localization.lang("Insert a citation without text (the entry will appear in the reference list)"))); - pushEntriesEmpty.setOnAction(e -> pushEntries(false, false, false)); + pushEntriesEmpty.setOnAction(e -> pushEntries(CitationType.INVISIBLE_CIT, false)); pushEntriesEmpty.setMaxWidth(Double.MAX_VALUE); pushEntriesAdvanced.setTooltip(new Tooltip(Localization.lang("Cite selected entries with extra information"))); - pushEntriesAdvanced.setOnAction(e -> pushEntries(false, true, true)); + pushEntriesAdvanced.setOnAction(e -> pushEntries(CitationType.AUTHORYEAR_INTEXT, true)); pushEntriesAdvanced.setMaxWidth(Double.MAX_VALUE); update.setTooltip(new Tooltip(Localization.lang("Ensure that the bibliography is up-to-date"))); update.setOnAction(event -> { - try { - if (style == null) { - style = loader.getUsedStyle(); - } else { - style.ensureUpToDate(); - } - - ooBase.updateSortedReferenceMarks(); - - List databases = getBaseList(); - List unresolvedKeys = ooBase.refreshCiteMarkers(databases, style); - ooBase.rebuildBibTextSection(databases, style); - if (!unresolvedKeys.isEmpty()) { - dialogService.showErrorDialogAndWait(Localization.lang("Unable to synchronize bibliography"), - Localization.lang("Your OpenOffice/LibreOffice document references the citation key '%0', which could not be found in your current library.", - unresolvedKeys.get(0))); - } - } catch (UndefinedCharacterFormatException ex) { - reportUndefinedCharacterFormat(ex); - } catch (UndefinedParagraphFormatException ex) { - reportUndefinedParagraphFormat(ex); - } catch (ConnectionLostException ex) { - showConnectionLostErrorMessage(); - } catch (IOException ex) { - LOGGER.warn("Problem with style file", ex); - dialogService.showErrorDialogAndWait(Localization.lang("No valid style file defined"), - Localization.lang("You must select either a valid style file, or use one of the default styles.")); - } catch (BibEntryNotFoundException ex) { - LOGGER.debug("BibEntry not found", ex); - dialogService.showErrorDialogAndWait(Localization.lang("Unable to synchronize bibliography"), Localization.lang( - "Your OpenOffice/LibreOffice document references the citation key '%0', which could not be found in your current library.", - ex.getCitationKey())); - } catch (com.sun.star.lang.IllegalArgumentException | PropertyVetoException | UnknownPropertyException | WrappedTargetException | NoSuchElementException | - CreationException ex) { - LOGGER.warn("Could not update bibliography", ex); + String title = Localization.lang("Could not update bibliography"); + if (getOrUpdateTheStyle(title)) { + return; } + List databases = getBaseList(); + ooBase.guiActionUpdateDocument(databases, style); }); merge.setMaxWidth(Double.MAX_VALUE); merge.setTooltip(new Tooltip(Localization.lang("Combine pairs of citations that are separated by spaces only"))); merge.setOnAction(e -> { - try { - ooBase.combineCiteMarkers(getBaseList(), style); - } catch (UndefinedCharacterFormatException ex) { - reportUndefinedCharacterFormat(ex); - } catch (com.sun.star.lang.IllegalArgumentException | UnknownPropertyException | PropertyVetoException | - CreationException | NoSuchElementException | WrappedTargetException | IOException | - BibEntryNotFoundException ex) { - LOGGER.warn("Problem combining cite markers", ex); - } + ooBase.guiActionMergeCitationGroups(getBaseList(), style); }); unmerge.setMaxWidth(Double.MAX_VALUE); unmerge.setTooltip(new Tooltip(Localization.lang("Separate merged citations"))); unmerge.setOnAction(e -> { - try { - ooBase.unCombineCiteMarkers(getBaseList(), style); - } catch (UndefinedCharacterFormatException ex) { - reportUndefinedCharacterFormat(ex); - } catch (com.sun.star.lang.IllegalArgumentException | UnknownPropertyException | PropertyVetoException | - CreationException | NoSuchElementException | WrappedTargetException | IOException | - BibEntryNotFoundException ex) { - LOGGER.warn("Problem uncombining cite markers", ex); - } + ooBase.guiActionSeparateCitations(getBaseList(), style); }); ContextMenu settingsMenu = createSettingsPopup(); @@ -263,22 +226,16 @@ private void initPanel() { settingsB.setOnAction(e -> settingsMenu.show(settingsB, Side.BOTTOM, 0, 0)); manageCitations.setMaxWidth(Double.MAX_VALUE); manageCitations.setOnAction(e -> { - dialogService.showCustomDialogAndWait(new ManageCitationsDialogView(ooBase)); + ManageCitationsDialogView dialog = new ManageCitationsDialogView(ooBase); + if (dialog.isOkToShowThisDialog()) { + dialogService.showCustomDialogAndWait(dialog); + } }); exportCitations.setMaxWidth(Double.MAX_VALUE); exportCitations.setOnAction(event -> exportEntries()); - selectDocument.setDisable(true); - pushEntries.setDisable(true); - pushEntriesInt.setDisable(true); - pushEntriesEmpty.setDisable(true); - pushEntriesAdvanced.setDisable(true); - update.setDisable(true); - merge.setDisable(true); - unmerge.setDisable(true); - manageCitations.setDisable(true); - exportCitations.setDisable(true); + updateButtonAvailability(); HBox hbox = new HBox(); hbox.getChildren().addAll(connect, manualConnect, selectDocument, update, help); @@ -298,36 +255,13 @@ private void initPanel() { } private void exportEntries() { - try { - if (style == null) { - style = loader.getUsedStyle(); - } else { - style.ensureUpToDate(); - } - - ooBase.updateSortedReferenceMarks(); - - List databases = getBaseList(); - List unresolvedKeys = ooBase.refreshCiteMarkers(databases, style); - BibDatabase newDatabase = ooBase.generateDatabase(databases); - if (!unresolvedKeys.isEmpty()) { - - dialogService.showErrorDialogAndWait(Localization.lang("Unable to generate new library"), - Localization.lang("Your OpenOffice/LibreOffice document references the citation key '%0', which could not be found in your current library.", - unresolvedKeys.get(0))); - } - - BibDatabaseContext databaseContext = new BibDatabaseContext(newDatabase); + final String title = Localization.lang("Problem generating new database."); + List databases = getBaseList(); + boolean returnPartialResult = false; + Optional newDatabase = ooBase.exportCitedHelper(databases, returnPartialResult); + if (newDatabase.isPresent()) { + BibDatabaseContext databaseContext = new BibDatabaseContext(newDatabase.get()); this.frame.addTab(databaseContext, true); - } catch (BibEntryNotFoundException ex) { - LOGGER.debug("BibEntry not found", ex); - dialogService.showErrorDialogAndWait(Localization.lang("Unable to synchronize bibliography"), - Localization.lang("Your OpenOffice/LibreOffice document references the citation key '%0', which could not be found in your current library.", - ex.getCitationKey())); - } catch (com.sun.star.lang.IllegalArgumentException | UnknownPropertyException | PropertyVetoException | - UndefinedCharacterFormatException | NoSuchElementException | WrappedTargetException | IOException | - CreationException e) { - LOGGER.warn("Problem generating new database.", e); } } @@ -338,7 +272,10 @@ private List getBaseList() { databases.add(libraryTab.getDatabase()); } } else { - databases.add(frame.getCurrentLibraryTab().getDatabase()); + LibraryTab libraryTab = frame.getCurrentLibraryTab(); + if (libraryTab != null) { + databases.add(libraryTab.getDatabase()); + } } return databases; @@ -405,13 +342,39 @@ private void connectManually() { } } + private void updateButtonAvailability() { + boolean isConnected = (ooBase != null); + boolean isConnectedToDocument = isConnected && !ooBase.isDocumentConnectionMissing(); + + // For these, we need to watch something + boolean hasStyle = true; // (style != null); + boolean hasDatabase = true; // !getBaseList().isEmpty(); + boolean hasSelectedBibEntry = true; + + selectDocument.setDisable(!(isConnected)); + pushEntries.setDisable(!(isConnectedToDocument && hasStyle && hasDatabase)); + + boolean canCite = isConnectedToDocument && hasStyle && hasSelectedBibEntry; + pushEntriesInt.setDisable(!canCite); + pushEntriesEmpty.setDisable(!canCite); + pushEntriesAdvanced.setDisable(!canCite); + + boolean canRefreshDocument = isConnectedToDocument && hasStyle; + update.setDisable(!canRefreshDocument); + merge.setDisable(!canRefreshDocument); + unmerge.setDisable(!canRefreshDocument); + manageCitations.setDisable(!canRefreshDocument); + + exportCitations.setDisable(!(isConnectedToDocument && hasDatabase)); + } + private void connect() { ooPrefs = preferencesService.getOpenOfficePreferences(); - Task connectTask = new Task<>() { + Task connectTask = new Task<>() { @Override - protected OOBibBase call() throws Exception { + protected OOBibBase2 call() throws Exception { updateProgress(ProgressBar.INDETERMINATE_PROGRESS, ProgressBar.INDETERMINATE_PROGRESS); var path = Path.of(ooPrefs.getExecutablePath()); @@ -422,29 +385,12 @@ protected OOBibBase call() throws Exception { connectTask.setOnSucceeded(value -> { ooBase = connectTask.getValue(); - try { - ooBase.selectDocument(); - } catch (NoSuchElementException | WrappedTargetException | NoDocumentException ex) { - dialogService.showErrorDialogAndWait(Localization.lang("Error connecting to Writer document"), Localization.lang("You need to open Writer with a document before connecting"), ex); - LOGGER.error("Error connecting to writer document", ex); - } - - if (ooBase.isConnectedToDocument()) { - dialogService.notify(Localization.lang("Connected to document") + ": " + ooBase.getCurrentDocumentTitle().orElse("")); - } + ooBase.guiActionSelectDocument(true); // Enable actions that depend on Connect: - selectDocument.setDisable(false); - pushEntries.setDisable(false); - pushEntriesInt.setDisable(false); - pushEntriesEmpty.setDisable(false); - pushEntriesAdvanced.setDisable(false); - update.setDisable(false); - merge.setDisable(false); - unmerge.setDisable(false); - manageCitations.setDisable(false); - exportCitations.setDisable(false); + updateButtonAvailability(); }); + connectTask.setOnFailed(value -> { Throwable ex = connectTask.getException(); if (ex instanceof UnsatisfiedLinkError) { @@ -470,20 +416,63 @@ protected OOBibBase call() throws Exception { taskExecutor.execute(connectTask); } - private OOBibBase createBibBase(Path loPath) throws IOException, InvocationTargetException, IllegalAccessException, + private OOBibBase2 createBibBase(Path loPath) throws IOException, InvocationTargetException, IllegalAccessException, BootstrapException, CreationException, ClassNotFoundException { - return new OOBibBase(loPath, true, dialogService); + return new OOBibBase2(loPath, dialogService); } - private void pushEntries(boolean inParenthesisIn, boolean withText, boolean addPageInfo) { - if (!ooBase.isConnectedToDocument()) { - dialogService.showErrorDialogAndWait(Localization.lang("Error pushing entries"), Localization.lang("Not connected to any Writer document. Please" + " make sure a document is open, and use the 'Select Writer document' button to connect to it.")); + /** + * Given the withText and inParenthesis options, + * return the corresponding citationType. + * + * @param withText False means invisible citation (no text). + * @param inParenthesis True means "(Au and Thor 2000)". + * False means "Au and Thor (2000)". + */ + private static CitationType citationTypeFromOptions(boolean withText, boolean inParenthesis) { + if (!withText) { + return CitationType.INVISIBLE_CIT; + } + return (inParenthesis + ? CitationType.AUTHORYEAR_PAR + : CitationType.AUTHORYEAR_INTEXT); + } + + private void pushEntries(CitationType citationType, boolean addPageInfo) { + final String title = Localization.lang("Error pushing entries"); + + LibraryTab libraryTab = frame.getCurrentLibraryTab(); + if (libraryTab == null) { + OOError.noDataBaseIsOpenForCiting() + .setTitle(title) + .showErrorDialog(dialogService); + return; + } + + final BibDatabase database = libraryTab.getDatabase(); + if (database == null) { + OOError.noDataBaseIsOpenForCiting() + .setTitle(title) + .showErrorDialog(dialogService); + return; + } + + List entries = libraryTab.getSelectedEntries(); + if (entries.isEmpty()) { + OOError.noEntriesSelectedForCitation() + .setTitle(title) + .showErrorDialog(dialogService); + return; + } + + if (getOrUpdateTheStyle(title)) { return; } - Boolean inParenthesis = inParenthesisIn; String pageInfo = null; if (addPageInfo) { + Boolean inParenthesis = citationType.inParenthesis(); + boolean withText = citationType.withText(); Optional citeDialogViewModel = dialogService.showCustomDialogAndWait(new AdvancedCiteDialogView()); if (citeDialogViewModel.isPresent()) { @@ -493,42 +482,29 @@ private void pushEntries(boolean inParenthesisIn, boolean withText, boolean addP pageInfo = model.pageInfoProperty().getValue(); } inParenthesis = model.citeInParProperty().getValue(); + citationType = citationTypeFromOptions(withText, inParenthesis); + } else { + // user canceled + return; } } - LibraryTab libraryTab = frame.getCurrentLibraryTab(); - if (libraryTab != null) { - final BibDatabase database = libraryTab.getDatabase(); - List entries = libraryTab.getSelectedEntries(); - if (!entries.isEmpty() && checkThatEntriesHaveKeys(entries)) { - - try { - if (style == null) { - style = loader.getUsedStyle(); - } - ooBase.insertEntry(entries, database, getBaseList(), style, inParenthesis, withText, pageInfo, - ooPrefs.getSyncWhenCiting()); - } catch (FileNotFoundException ex) { - - dialogService.showErrorDialogAndWait( - Localization.lang("No valid style file defined"), - Localization.lang("You must select either a valid style file, or use one of the default styles.")); - - LOGGER.warn("Problem with style file", ex); - } catch (ConnectionLostException ex) { - showConnectionLostErrorMessage(); - } catch (UndefinedCharacterFormatException ex) { - reportUndefinedCharacterFormat(ex); - } catch (UndefinedParagraphFormatException ex) { - reportUndefinedParagraphFormat(ex); - } catch (com.sun.star.lang.IllegalArgumentException | UnknownPropertyException | PropertyVetoException | - CreationException | NoSuchElementException | WrappedTargetException | IOException | - BibEntryNotFoundException | IllegalTypeException | PropertyExistException | - NotRemoveableException ex) { - LOGGER.warn("Could not insert entry", ex); - } - } + if (!checkThatEntriesHaveKeys(entries)) { + // Not all entries have keys and key generation was declined. + return; } + + Optional syncOptions = + (ooPrefs.getSyncWhenCiting() + ? Optional.of(new Update.SyncOptions(getBaseList())) + : Optional.empty()); + + ooBase.guiActionInsertEntry(entries, + database, + style, + citationType, + pageInfo, + syncOptions); } /** @@ -583,27 +559,6 @@ private boolean checkThatEntriesHaveKeys(List entries) { } } - private void showConnectionLostErrorMessage() { - dialogService.showErrorDialogAndWait(Localization.lang("Connection lost"), - Localization.lang("Connection to OpenOffice/LibreOffice has been lost. " + "Please make sure OpenOffice/LibreOffice is running, and try to reconnect.")); - } - - private void reportUndefinedParagraphFormat(UndefinedParagraphFormatException ex) { - dialogService.showErrorDialogAndWait(Localization.lang("Undefined paragraph format"), - Localization.lang("Your style file specifies the paragraph format '%0', " - + "which is undefined in your current OpenOffice/LibreOffice document.", - ex.getFormatName()) + "\n" + Localization.lang("The paragraph format is controlled by the property 'ReferenceParagraphFormat' or 'ReferenceHeaderParagraphFormat' in the style file.")); - } - - private void reportUndefinedCharacterFormat(UndefinedCharacterFormatException ex) { - dialogService.showErrorDialogAndWait(Localization.lang("Undefined character format"), - Localization.lang("Your style file specifies the character format '%0', " - + "which is undefined in your current OpenOffice/LibreOffice document.", - ex.getFormatName()) + "\n" + Localization.lang("The character format is controlled by the citation property 'CitationCharacterFormat' in the style file.") - - ); - } - private ContextMenu createSettingsPopup() { ContextMenu contextMenu = new ContextMenu(); diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index bf4c349bb76..1e9bbace212 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -1056,11 +1056,12 @@ Combine\ pairs\ of\ citations\ that\ are\ separated\ by\ spaces\ only=Combine pa Autodetection\ failed=Autodetection failed Please\ wait...=Please wait... Connection\ lost=Connection lost -The\ paragraph\ format\ is\ controlled\ by\ the\ property\ 'ReferenceParagraphFormat'\ or\ 'ReferenceHeaderParagraphFormat'\ in\ the\ style\ file.=The paragraph format is controlled by the property 'ReferenceParagraphFormat' or 'ReferenceHeaderParagraphFormat' in the style file. -The\ character\ format\ is\ controlled\ by\ the\ citation\ property\ 'CitationCharacterFormat'\ in\ the\ style\ file.=The character format is controlled by the citation property 'CitationCharacterFormat' in the style file. +Could\ not\ update\ bibliography=Could not update bibliography Not\ connected\ to\ document=Not connected to document Problem\ combining\ cite\ markers=Problem combining cite markers +Problem\ generating\ new\ database.=Problem generating new database. +Unable\ to\ reload\ style\ file=Unable to reload style file Problem\ during\ separating\ cite\ markers=Problem during separating cite markers @@ -1174,8 +1175,6 @@ To\ disable\ the\ memory\ stick\ mode\ rename\ or\ remove\ the\ jabref.xml\ file Unable\ to\ connect.\ One\ possible\ reason\ is\ that\ JabRef\ and\ OpenOffice/LibreOffice\ are\ not\ both\ running\ in\ either\ 32\ bit\ mode\ or\ 64\ bit\ mode.=Unable to connect. One possible reason is that JabRef and OpenOffice/LibreOffice are not both running in either 32 bit mode or 64 bit mode. Delimiter(s)=Delimiter(s) When\ downloading\ files,\ or\ moving\ linked\ files\ to\ the\ file\ directory,\ prefer\ the\ BIB\ file\ location\ rather\ than\ the\ file\ directory\ set\ above=When downloading files, or moving linked files to the file directory, prefer the BIB file location rather than the file directory set above -Your\ style\ file\ specifies\ the\ character\ format\ '%0',\ which\ is\ undefined\ in\ your\ current\ OpenOffice/LibreOffice\ document.=Your style file specifies the character format '%0', which is undefined in your current OpenOffice/LibreOffice document. -Your\ style\ file\ specifies\ the\ paragraph\ format\ '%0',\ which\ is\ undefined\ in\ your\ current\ OpenOffice/LibreOffice\ document.=Your style file specifies the paragraph format '%0', which is undefined in your current OpenOffice/LibreOffice document. Searching...=Searching... Please\ enter\ a\ search\ string=Please enter a search string @@ -1845,9 +1844,6 @@ Could\ not\ connect\ to\ Vim\ server.\ Make\ sure\ that\ Vim\ is\ running\ with\ Could\ not\ connect\ to\ a\ running\ gnuserv\ process.\ Make\ sure\ that\ Emacs\ or\ XEmacs\ is\ running,\ and\ that\ the\ server\ has\ been\ started\ (by\ running\ the\ command\ 'server-start'/'gnuserv-start').=Could not connect to a running gnuserv process. Make sure that Emacs or XEmacs is running, and that the server has been started (by running the command 'server-start'/'gnuserv-start'). Error\ pushing\ entries=Error pushing entries -Undefined\ character\ format=Undefined character format -Undefined\ paragraph\ format=Undefined paragraph format - Edit\ Preamble=Edit Preamble Markings=Markings Use\ selected\ instance=Use selected instance @@ -2333,8 +2329,6 @@ Separate\ merged\ citations=Separate merged citations Separate\ citations=Separate citations Unprotect\ terms=Unprotect terms -Error\ connecting\ to\ Writer\ document=Error connecting to Writer document -You\ need\ to\ open\ Writer\ with\ a\ document\ before\ connecting=You need to open Writer with a document before connecting Generate\ a\ new\ key\ for\ imported\ entries\ (overwriting\ their\ default)=Generate a new key for imported entries (overwriting their default) Import\ settings=Import settings From 3e001c597b8c80af55293f0e7680bfed3d43d48b Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 13:39:46 +0200 Subject: [PATCH 029/103] cleanup --- .../openoffice/BibEntryNotFoundException.java | 16 - .../openoffice/ConnectionLostException.java | 11 - .../org/jabref/gui/openoffice/OOBibBase.java | 1424 ----------------- .../UndefinedCharacterFormatException.java | 19 - .../org/jabref/logic/openoffice/OOUtil.java | 285 ---- .../openoffice/UndefinedBibtexEntry.java | 22 - .../UndefinedParagraphFormatException.java | 18 - .../logic/openoffice/style/OOBibStyle.java | 398 ----- src/main/resources/l10n/JabRef_en.properties | 1 - .../openoffice/style/OOBibStyleTest.java | 115 +- .../style/OOBibStyleTestHelper.java | 51 +- 11 files changed, 100 insertions(+), 2260 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/openoffice/BibEntryNotFoundException.java delete mode 100644 src/main/java/org/jabref/gui/openoffice/ConnectionLostException.java delete mode 100644 src/main/java/org/jabref/gui/openoffice/OOBibBase.java delete mode 100644 src/main/java/org/jabref/gui/openoffice/UndefinedCharacterFormatException.java delete mode 100644 src/main/java/org/jabref/logic/openoffice/OOUtil.java delete mode 100644 src/main/java/org/jabref/logic/openoffice/UndefinedBibtexEntry.java delete mode 100644 src/main/java/org/jabref/logic/openoffice/UndefinedParagraphFormatException.java diff --git a/src/main/java/org/jabref/gui/openoffice/BibEntryNotFoundException.java b/src/main/java/org/jabref/gui/openoffice/BibEntryNotFoundException.java deleted file mode 100644 index b3db5f8f9e7..00000000000 --- a/src/main/java/org/jabref/gui/openoffice/BibEntryNotFoundException.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.jabref.gui.openoffice; - -class BibEntryNotFoundException extends Exception { - - private final String citationKey; - - public BibEntryNotFoundException(String citationKey, String message) { - super(message); - - this.citationKey = citationKey; - } - - public String getCitationKey() { - return citationKey; - } -} diff --git a/src/main/java/org/jabref/gui/openoffice/ConnectionLostException.java b/src/main/java/org/jabref/gui/openoffice/ConnectionLostException.java deleted file mode 100644 index 36fc16e5e3f..00000000000 --- a/src/main/java/org/jabref/gui/openoffice/ConnectionLostException.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.jabref.gui.openoffice; - -/** - * This exception is used to indicate that connection to OpenOffice has been lost. - */ -class ConnectionLostException extends RuntimeException { - - public ConnectionLostException(String s) { - super(s); - } -} diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase.java deleted file mode 100644 index 540c5f9216b..00000000000 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase.java +++ /dev/null @@ -1,1424 +0,0 @@ -package org.jabref.gui.openoffice; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import org.jabref.architecture.AllowedToUseAwt; -import org.jabref.gui.DialogService; -import org.jabref.logic.bibtex.comparator.FieldComparator; -import org.jabref.logic.bibtex.comparator.FieldComparatorStack; -import org.jabref.logic.l10n.Localization; -import org.jabref.logic.layout.Layout; -import org.jabref.logic.openoffice.OOUtil; -import org.jabref.logic.openoffice.UndefinedBibtexEntry; -import org.jabref.logic.openoffice.UndefinedParagraphFormatException; -import org.jabref.logic.openoffice.style.OOBibStyle; -import org.jabref.logic.openoffice.style.OOPreFormatter; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.StandardField; -import org.jabref.model.openoffice.uno.CreationException; -import org.jabref.model.openoffice.uno.NoDocumentException; - -import com.sun.star.awt.Point; -import com.sun.star.beans.IllegalTypeException; -import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; -import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.beans.XPropertyContainer; -import com.sun.star.beans.XPropertySet; -import com.sun.star.comp.helper.BootstrapException; -import com.sun.star.container.NoSuchElementException; -import com.sun.star.container.XEnumeration; -import com.sun.star.container.XEnumerationAccess; -import com.sun.star.container.XNameAccess; -import com.sun.star.container.XNamed; -import com.sun.star.document.XDocumentPropertiesSupplier; -import com.sun.star.frame.XComponentLoader; -import com.sun.star.frame.XController; -import com.sun.star.frame.XDesktop; -import com.sun.star.frame.XModel; -import com.sun.star.lang.DisposedException; -import com.sun.star.lang.IllegalArgumentException; -import com.sun.star.lang.Locale; -import com.sun.star.lang.WrappedTargetException; -import com.sun.star.lang.XComponent; -import com.sun.star.lang.XMultiComponentFactory; -import com.sun.star.lang.XMultiServiceFactory; -import com.sun.star.text.XBookmarksSupplier; -import com.sun.star.text.XDocumentIndexesSupplier; -import com.sun.star.text.XFootnote; -import com.sun.star.text.XReferenceMarksSupplier; -import com.sun.star.text.XText; -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.text.XTextRangeCompare; -import com.sun.star.text.XTextSection; -import com.sun.star.text.XTextSectionsSupplier; -import com.sun.star.text.XTextViewCursor; -import com.sun.star.text.XTextViewCursorSupplier; -import com.sun.star.uno.Any; -import com.sun.star.uno.Type; -import com.sun.star.uno.UnoRuntime; -import com.sun.star.uno.XComponentContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class for manipulating the Bibliography of the currently start document in OpenOffice. - */ -@AllowedToUseAwt("Requires AWT for italics and bold") -class OOBibBase { - - private static final OOPreFormatter POSTFORMATTER = new OOPreFormatter(); - - private static final String BIB_SECTION_NAME = "JR_bib"; - private static final String BIB_SECTION_END_NAME = "JR_bib_end"; - private static final String BIB_CITATION = "JR_cite"; - private static final Pattern CITE_PATTERN = Pattern.compile(OOBibBase.BIB_CITATION + "\\d*_(\\d*)_(.*)"); - - private static final String CHAR_STYLE_NAME = "CharStyleName"; - - private static final int AUTHORYEAR_PAR = 1; - private static final int AUTHORYEAR_INTEXT = 2; - private static final int INVISIBLE_CIT = 3; - - private static final Logger LOGGER = LoggerFactory.getLogger(OOBibBase.class); - private XMultiServiceFactory mxDocFactory; - private XTextDocument mxDoc; - private XText text; - private final XDesktop xDesktop; - private XTextViewCursorSupplier xViewCursorSupplier; - private XComponent xCurrentComponent; - private XPropertySet propertySet; - - private XPropertyContainer userProperties; - private final boolean atEnd; - private final Comparator entryComparator; - private final Comparator yearAuthorTitleComparator; - private final FieldComparator authComp = new FieldComparator(StandardField.AUTHOR); - private final FieldComparator yearComp = new FieldComparator(StandardField.YEAR); - - private final FieldComparator titleComp = new FieldComparator(StandardField.TITLE); - private final List> authorYearTitleList = new ArrayList<>(3); - - private final List> yearAuthorTitleList = new ArrayList<>(3); - private final Map uniquefiers = new HashMap<>(); - private List sortedReferenceMarks; - - private final DialogService dialogService; - - public OOBibBase(Path loPath, boolean atEnd, DialogService dialogService) throws IllegalAccessException, InvocationTargetException, BootstrapException, CreationException, IOException, ClassNotFoundException { - - this.dialogService = dialogService; - - authorYearTitleList.add(authComp); - authorYearTitleList.add(yearComp); - authorYearTitleList.add(titleComp); - - yearAuthorTitleList.add(yearComp); - yearAuthorTitleList.add(authComp); - yearAuthorTitleList.add(titleComp); - - entryComparator = new FieldComparatorStack<>(authorYearTitleList); - yearAuthorTitleComparator = new FieldComparatorStack<>(yearAuthorTitleList); - - this.atEnd = atEnd; - - xDesktop = simpleBootstrap(loPath); - } - - public boolean isConnectedToDocument() { - return xCurrentComponent != null; - } - - public XTextDocument selectComponent(List list) { - List viewModel = list.stream().map(DocumentTitleViewModel::new).collect(Collectors.toList()); - // this whole method is part of a background task when auto-detecting instances, so we need to show dialog in FX thread - Optional selectedDocument = dialogService.showChoiceDialogAndWait(Localization.lang("Select document"), Localization.lang("Found documents:"), Localization.lang("Use selected document"), viewModel); - return selectedDocument.map(DocumentTitleViewModel::getXtextDocument).orElse(null); - } - - public Optional getCurrentDocumentTitle() { - return getDocumentTitle(mxDoc); - } - - private Optional getDocumentTitle(XTextDocument doc) { - if (doc == null) { - return Optional.empty(); - } else { - try { - return Optional.of(String.valueOf(OOUtil.getProperty(doc.getCurrentController().getFrame(), "Title"))); - } catch (UnknownPropertyException | WrappedTargetException e) { - LOGGER.warn("Could not get document title", e); - return Optional.empty(); - } - } - } - - public void selectDocument() throws NoDocumentException, NoSuchElementException, WrappedTargetException { - List textDocumentList = getTextDocuments(); - XTextDocument selected; - if (textDocumentList.isEmpty()) { - // No text documents found. - throw new NoDocumentException("No Writer documents found"); - } else if (textDocumentList.size() == 1) { - // Get the only one - selected = textDocumentList.get(0); - } else { - // Bring up a dialog - selected = selectComponent(textDocumentList); - } - - if (selected == null) { - return; - } - xCurrentComponent = UnoRuntime.queryInterface(XComponent.class, selected); - mxDoc = selected; - - UnoRuntime.queryInterface(XDocumentIndexesSupplier.class, xCurrentComponent); - - XModel xModel = UnoRuntime.queryInterface(XModel.class, xCurrentComponent); - XController xController = xModel.getCurrentController(); - xViewCursorSupplier = UnoRuntime.queryInterface(XTextViewCursorSupplier.class, xController); - - // get a reference to the body text of the document - text = mxDoc.getText(); - - // Access the text document's multi service factory: - mxDocFactory = UnoRuntime.queryInterface(XMultiServiceFactory.class, mxDoc); - - XDocumentPropertiesSupplier supp = UnoRuntime.queryInterface(XDocumentPropertiesSupplier.class, mxDoc); - userProperties = supp.getDocumentProperties().getUserDefinedProperties(); - propertySet = UnoRuntime.queryInterface(XPropertySet.class, userProperties); - } - - private List getTextDocuments() throws NoSuchElementException, WrappedTargetException { - List result = new ArrayList<>(); - XEnumerationAccess enumAccess = xDesktop.getComponents(); - XEnumeration componentEnumeration = enumAccess.createEnumeration(); - - // TODO: http://api.openoffice.org/docs/DevelopersGuide/OfficeDev/OfficeDev.xhtml#1_1_3_2_1_2_Frame_Hierarchies - - while (componentEnumeration.hasMoreElements()) { - Object nextElement = componentEnumeration.nextElement(); - XComponent component = UnoRuntime.queryInterface(XComponent.class, nextElement); - XTextDocument document = UnoRuntime.queryInterface(XTextDocument.class, component); - if (document != null) { - result.add(document); - } - } - return result; - } - - private XDesktop simpleBootstrap(Path loPath) - throws CreationException, BootstrapException { - - // Get the office component context: - XComponentContext xContext = org.jabref.gui.openoffice.Bootstrap.bootstrap(loPath); - // Get the office service manager: - XMultiComponentFactory xServiceManager = xContext.getServiceManager(); - // Create the desktop, which is the root frame of the - // hierarchy of frames that contain viewable components: - Object desktop; - try { - desktop = xServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", xContext); - } catch (Exception e) { - throw new CreationException(e.getMessage()); - } - XDesktop resultDesktop = UnoRuntime.queryInterface(XDesktop.class, desktop); - - UnoRuntime.queryInterface(XComponentLoader.class, desktop); - - return resultDesktop; - } - - public Optional getCustomProperty(String property) throws UnknownPropertyException, WrappedTargetException { - if (propertySet.getPropertySetInfo().hasPropertyByName(property)) { - return Optional.ofNullable(propertySet.getPropertyValue(property).toString()); - } - return Optional.empty(); - } - - public void updateSortedReferenceMarks() throws WrappedTargetException, NoSuchElementException { - sortedReferenceMarks = getSortedReferenceMarks(getReferenceMarks()); - } - - public void setCustomProperty(String property, String value) throws UnknownPropertyException, - NotRemoveableException, PropertyExistException, IllegalTypeException, IllegalArgumentException { - if (propertySet.getPropertySetInfo().hasPropertyByName(property)) { - userProperties.removeProperty(property); - } - if (value != null) { - userProperties.addProperty(property, com.sun.star.beans.PropertyAttribute.REMOVEABLE, - new Any(Type.STRING, value)); - } - } - - /** - * This method inserts a cite marker in the text for the given BibEntry, and may refresh the bibliography. - * - * @param entries The entries to cite. - * @param database The database the entry belongs to. - * @param style The bibliography style we are using. - * @param inParenthesis Indicates whether it is an in-text citation or a citation in parenthesis. This is not relevant if numbered citations are used. - * @param withText Indicates whether this should be a normal citation (true) or an empty (invisible) citation (false). - * @param sync Indicates whether the reference list should be refreshed. - * @throws IllegalTypeException - * @throws PropertyExistException - * @throws NotRemoveableException - * @throws UnknownPropertyException - * @throws UndefinedCharacterFormatException - * @throws NoSuchElementException - * @throws WrappedTargetException - * @throws IOException - * @throws PropertyVetoException - * @throws CreationException - * @throws BibEntryNotFoundException - * @throws UndefinedParagraphFormatException - */ - public void insertEntry(List entries, BibDatabase database, - List allBases, OOBibStyle style, - boolean inParenthesis, boolean withText, String pageInfo, boolean sync) - throws IllegalArgumentException, - UnknownPropertyException, NotRemoveableException, PropertyExistException, IllegalTypeException, - UndefinedCharacterFormatException, WrappedTargetException, NoSuchElementException, PropertyVetoException, - IOException, CreationException, BibEntryNotFoundException, UndefinedParagraphFormatException { - - try { - - XTextViewCursor xViewCursor = xViewCursorSupplier.getViewCursor(); - - if (entries.size() > 1) { - if (style.getBooleanCitProperty(OOBibStyle.MULTI_CITE_CHRONOLOGICAL)) { - entries.sort(yearAuthorTitleComparator); - } else { - entries.sort(entryComparator); - } - } - - String keyString = String.join(",", - entries.stream().map(entry -> entry.getCitationKey().orElse("")).collect(Collectors.toList())); - // Insert bookmark: - String bName = getUniqueReferenceMarkName(keyString, - withText ? inParenthesis ? OOBibBase.AUTHORYEAR_PAR : OOBibBase.AUTHORYEAR_INTEXT : OOBibBase.INVISIBLE_CIT); - - // If we should store metadata for page info, do that now: - if (pageInfo != null) { - LOGGER.info("Storing page info: " + pageInfo); - setCustomProperty(bName, pageInfo); - } - - xViewCursor.getText().insertString(xViewCursor, " ", false); - if (style.isFormatCitations()) { - XPropertySet xCursorProps = UnoRuntime.queryInterface(XPropertySet.class, xViewCursor); - String charStyle = style.getCitationCharacterFormat(); - try { - xCursorProps.setPropertyValue(CHAR_STYLE_NAME, charStyle); - } catch (UnknownPropertyException | PropertyVetoException | IllegalArgumentException | - WrappedTargetException ex) { - // Setting the character format failed, so we throw an exception that - // will result in an error message for the user. Before that, - // delete the space we inserted: - xViewCursor.goLeft((short) 1, true); - xViewCursor.setString(""); - throw new UndefinedCharacterFormatException(charStyle); - } - } - xViewCursor.goLeft((short) 1, false); - Map databaseMap = new HashMap<>(); - for (BibEntry entry : entries) { - databaseMap.put(entry, database); - } - String citeText = style.isNumberEntries() ? "-" : style.getCitationMarker(entries, databaseMap, - inParenthesis, null, null); - insertReferenceMark(bName, citeText, xViewCursor, withText, style); - - xViewCursor.collapseToEnd(); - xViewCursor.goRight((short) 1, false); - - XTextRange position = xViewCursor.getEnd(); - - if (sync) { - // To account for numbering and for uniqiefiers, we must refresh the cite markers: - updateSortedReferenceMarks(); - refreshCiteMarkers(allBases, style); - - // Insert it at the current position: - rebuildBibTextSection(allBases, style); - } - - // Go back to the relevant position: - xViewCursor.gotoRange(position, false); - } catch (DisposedException ex) { - // We need to catch this one here because the OpenOfficePanel class is - // loaded before connection, and therefore cannot directly reference - // or catch a DisposedException (which is in a OO JAR file). - throw new ConnectionLostException(ex.getMessage()); - } - } - - public List getJabRefReferenceMarks(XNameAccess nameAccess) { - String[] names = nameAccess.getElementNames(); - // Remove all reference marks that don't look like JabRef citations: - List result = new ArrayList<>(); - if (names != null) { - for (String name : names) { - if (CITE_PATTERN.matcher(name).find()) { - result.add(name); - } - } - } - return result; - } - - /** - * Refresh all cite markers in the document. - * - * @param databases The databases to get entries from. - * @param style The bibliography style to use. - * @return A list of those referenced citation keys that could not be resolved. - * @throws UndefinedCharacterFormatException - * @throws NoSuchElementException - * @throws IllegalArgumentException - * @throws WrappedTargetException - * @throws BibEntryNotFoundException - * @throws CreationException - * @throws IOException - * @throws PropertyVetoException - * @throws UnknownPropertyException - */ - public List refreshCiteMarkers(List databases, OOBibStyle style) - throws WrappedTargetException, IllegalArgumentException, NoSuchElementException, - UndefinedCharacterFormatException, UnknownPropertyException, PropertyVetoException, IOException, - CreationException, BibEntryNotFoundException { - try { - return refreshCiteMarkersInternal(databases, style); - } catch (DisposedException ex) { - // We need to catch this one here because the OpenOfficePanel class is - // loaded before connection, and therefore cannot directly reference - // or catch a DisposedException (which is in a OO JAR file). - throw new ConnectionLostException(ex.getMessage()); - } - } - - private List refreshCiteMarkersInternal(List databases, OOBibStyle style) - throws WrappedTargetException, IllegalArgumentException, NoSuchElementException, - UndefinedCharacterFormatException, UnknownPropertyException, PropertyVetoException, - CreationException, BibEntryNotFoundException { - - List cited = findCitedKeys(); - Map linkSourceBase = new HashMap<>(); - Map entries = findCitedEntries(databases, cited, linkSourceBase); - - XNameAccess xReferenceMarks = getReferenceMarks(); - - List names; - if (style.isSortByPosition()) { - // We need to sort the reference marks according to their order of appearance: - names = sortedReferenceMarks; - } else if (style.isNumberEntries()) { - // We need to sort the reference marks according to the sorting of the bibliographic - // entries: - SortedMap newMap = new TreeMap<>(entryComparator); - for (Map.Entry bibtexEntryBibtexDatabaseEntry : entries.entrySet()) { - newMap.put(bibtexEntryBibtexDatabaseEntry.getKey(), bibtexEntryBibtexDatabaseEntry.getValue()); - } - entries = newMap; - // Rebuild the list of cited keys according to the sort order: - cited.clear(); - for (BibEntry entry : entries.keySet()) { - cited.add(entry.getCitationKey().orElse(null)); - } - names = Arrays.asList(xReferenceMarks.getElementNames()); - } else { - names = sortedReferenceMarks; - } - - // Remove all reference marks that don't look like JabRef citations: - List tmp = new ArrayList<>(); - for (String name : names) { - if (CITE_PATTERN.matcher(name).find()) { - tmp.add(name); - } - } - names = tmp; - - Map numbers = new HashMap<>(); - int lastNum = 0; - // First compute citation markers for all citations: - String[] citMarkers = new String[names.size()]; - String[][] normCitMarkers = new String[names.size()][]; - String[][] bibtexKeys = new String[names.size()][]; - - int minGroupingCount = style.getIntCitProperty(OOBibStyle.MINIMUM_GROUPING_COUNT); - - int[] types = new int[names.size()]; - for (int i = 0; i < names.size(); i++) { - Matcher citeMatcher = CITE_PATTERN.matcher(names.get(i)); - if (citeMatcher.find()) { - String typeStr = citeMatcher.group(1); - int type = Integer.parseInt(typeStr); - types[i] = type; // Remember the type in case we need to uniquefy. - String[] keys = citeMatcher.group(2).split(","); - bibtexKeys[i] = keys; - BibEntry[] cEntries = new BibEntry[keys.length]; - for (int j = 0; j < cEntries.length; j++) { - BibDatabase database = linkSourceBase.get(keys[j]); - Optional tmpEntry = Optional.empty(); - if (database != null) { - tmpEntry = database.getEntryByCitationKey(keys[j]); - } - if (tmpEntry.isPresent()) { - cEntries[j] = tmpEntry.get(); - } else { - LOGGER.info("Citation key not found: '" + keys[j] + '\''); - LOGGER.info("Problem with reference mark: '" + names.get(i) + '\''); - throw new BibEntryNotFoundException(names.get(i), Localization - .lang("Could not resolve BibTeX entry for citation marker '%0'.", names.get(i))); - } - } - - String[] normCitMarker = new String[keys.length]; - String citationMarker; - if (style.isCitationKeyCiteMarkers()) { - StringBuilder sb = new StringBuilder(); - normCitMarkers[i] = new String[keys.length]; - for (int j = 0; j < keys.length; j++) { - normCitMarkers[i][j] = cEntries[j].getCitationKey().orElse(null); - sb.append(cEntries[j].getCitationKey().orElse("")); - if (j < (keys.length - 1)) { - sb.append(','); - } - } - citationMarker = sb.toString(); - } else if (style.isNumberEntries()) { - if (style.isSortByPosition()) { - // We have sorted the citation markers according to their order of appearance, - // so we simply count up for each marker referring to a new entry: - List num = new ArrayList<>(keys.length); - for (int j = 0; j < keys.length; j++) { - if (cEntries[j] instanceof UndefinedBibtexEntry) { - num.add(j, -1); - } else { - num.add(j, lastNum + 1); - if (numbers.containsKey(keys[j])) { - num.set(j, numbers.get(keys[j])); - } else { - numbers.put(keys[j], num.get(j)); - lastNum = num.get(j); - } - } - } - citationMarker = style.getNumCitationMarker(num, minGroupingCount, false); - for (int j = 0; j < keys.length; j++) { - normCitMarker[j] = style.getNumCitationMarker(Collections.singletonList(num.get(j)), - minGroupingCount, false); - } - } else { - // We need to find the number of the cited entry in the bibliography, - // and use that number for the cite marker: - List num = findCitedEntryIndex(names.get(i), cited); - - if (num.isEmpty()) { - throw new BibEntryNotFoundException(names.get(i), Localization - .lang("Could not resolve BibTeX entry for citation marker '%0'.", names.get(i))); - } else { - citationMarker = style.getNumCitationMarker(num, minGroupingCount, false); - } - - for (int j = 0; j < keys.length; j++) { - List list = new ArrayList<>(1); - list.add(num.get(j)); - normCitMarker[j] = style.getNumCitationMarker(list, minGroupingCount, false); - } - } - } else { - - if (cEntries.length > 1) { - if (style.getBooleanCitProperty(OOBibStyle.MULTI_CITE_CHRONOLOGICAL)) { - Arrays.sort(cEntries, yearAuthorTitleComparator); - } else { - Arrays.sort(cEntries, entryComparator); - } - // Update key list to match the new sorting: - for (int j = 0; j < cEntries.length; j++) { - bibtexKeys[i][j] = cEntries[j].getCitationKey().orElse(null); - } - } - - citationMarker = style.getCitationMarker(Arrays.asList(cEntries), entries, - type == OOBibBase.AUTHORYEAR_PAR, null, null); - // We need "normalized" (in parenthesis) markers for uniqueness checking purposes: - for (int j = 0; j < cEntries.length; j++) { - normCitMarker[j] = style.getCitationMarker(Collections.singletonList(cEntries[j]), entries, - true, null, new int[] {-1}); - } - } - citMarkers[i] = citationMarker; - normCitMarkers[i] = normCitMarker; - } - } - - uniquefiers.clear(); - if (!style.isCitationKeyCiteMarkers() && !style.isNumberEntries()) { - // See if there are duplicate citations marks referring to different entries. If so, we need to - // use uniquefiers: - Map> refKeys = new HashMap<>(); - Map> refNums = new HashMap<>(); - for (int i = 0; i < citMarkers.length; i++) { - String[] markers = normCitMarkers[i]; // compare normalized markers, since the actual markers can be different - for (int j = 0; j < markers.length; j++) { - String marker = markers[j]; - String currentKey = bibtexKeys[i][j]; - if (refKeys.containsKey(marker)) { - // Ok, we have seen this exact marker before. - if (!refKeys.get(marker).contains(currentKey)) { - // ... but not for this entry. - refKeys.get(marker).add(currentKey); - refNums.get(marker).add(i); - } - } else { - List l = new ArrayList<>(1); - l.add(currentKey); - refKeys.put(marker, l); - List l2 = new ArrayList<>(1); - l2.add(i); - refNums.put(marker, l2); - } - } - } - // Go through the collected lists and see where we need to uniquefy: - for (Map.Entry> stringListEntry : refKeys.entrySet()) { - List keys = stringListEntry.getValue(); - if (keys.size() > 1) { - // This marker appears for more than one unique entry: - int uniq = 'a'; - for (String key : keys) { - // Update the map of uniquefiers for the benefit of both the following generation of new - // citation markers, and for the method that builds the bibliography: - uniquefiers.put(key, String.valueOf((char) uniq)); - uniq++; - } - } - } - - // Finally, go through all citation markers, and update those referring to entries in our current list: - int maxAuthorsFirst = style.getIntCitProperty(OOBibStyle.MAX_AUTHORS_FIRST); - Set seenBefore = new HashSet<>(); - for (int j = 0; j < bibtexKeys.length; j++) { - boolean needsChange = false; - int[] firstLimAuthors = new int[bibtexKeys[j].length]; - String[] uniquif = new String[bibtexKeys[j].length]; - BibEntry[] cEntries = new BibEntry[bibtexKeys[j].length]; - for (int k = 0; k < bibtexKeys[j].length; k++) { - String currentKey = bibtexKeys[j][k]; - firstLimAuthors[k] = -1; - if (maxAuthorsFirst > 0) { - if (!seenBefore.contains(currentKey)) { - firstLimAuthors[k] = maxAuthorsFirst; - } - seenBefore.add(currentKey); - } - String uniq = uniquefiers.get(currentKey); - Optional tmpEntry = Optional.empty(); - if (uniq == null) { - if (firstLimAuthors[k] > 0) { - needsChange = true; - BibDatabase database = linkSourceBase.get(currentKey); - if (database != null) { - tmpEntry = database.getEntryByCitationKey(currentKey); - } - } else { - BibDatabase database = linkSourceBase.get(currentKey); - if (database != null) { - tmpEntry = database.getEntryByCitationKey(currentKey); - } - } - uniquif[k] = ""; - } else { - needsChange = true; - BibDatabase database = linkSourceBase.get(currentKey); - if (database != null) { - tmpEntry = database.getEntryByCitationKey(currentKey); - } - uniquif[k] = uniq; - } - if (tmpEntry.isPresent()) { - cEntries[k] = tmpEntry.get(); - } - } - if (needsChange) { - citMarkers[j] = style.getCitationMarker(Arrays.asList(cEntries), entries, - types[j] == OOBibBase.AUTHORYEAR_PAR, uniquif, firstLimAuthors); - } - } - } - - // Refresh all reference marks with the citation markers we computed: - boolean hadBibSection = getBookmarkRange(OOBibBase.BIB_SECTION_NAME) != null; - // Check if we are supposed to set a character format for citations: - boolean mustTestCharFormat = style.isFormatCitations(); - for (int i = 0; i < names.size(); i++) { - Object referenceMark = xReferenceMarks.getByName(names.get(i)); - XTextContent bookmark = UnoRuntime.queryInterface(XTextContent.class, referenceMark); - - XTextCursor cursor = bookmark.getAnchor().getText().createTextCursorByRange(bookmark.getAnchor()); - - if (mustTestCharFormat) { - // If we are supposed to set character format for citations, must run a test before we - // delete old citation markers. Otherwise, if the specified character format doesn't - // exist, we end up deleting the markers before the process crashes due to a the missing - // format, with catastrophic consequences for the user. - mustTestCharFormat = false; // need to do this only once - XPropertySet xCursorProps = UnoRuntime.queryInterface(XPropertySet.class, cursor); - String charStyle = style.getCitationCharacterFormat(); - try { - xCursorProps.setPropertyValue(CHAR_STYLE_NAME, charStyle); - } catch (UnknownPropertyException | PropertyVetoException | IllegalArgumentException | - WrappedTargetException ex) { - throw new UndefinedCharacterFormatException(charStyle); - } - } - - text.removeTextContent(bookmark); - - insertReferenceMark(names.get(i), citMarkers[i], cursor, types[i] != OOBibBase.INVISIBLE_CIT, style); - if (hadBibSection && (getBookmarkRange(OOBibBase.BIB_SECTION_NAME) == null)) { - // We have overwritten the marker for the start of the reference list. - // We need to add it again. - cursor.collapseToEnd(); - OOUtil.insertParagraphBreak(text, cursor); - insertBookMark(OOBibBase.BIB_SECTION_NAME, cursor); - } - } - - List unresolvedKeys = new ArrayList<>(); - for (BibEntry entry : entries.keySet()) { - if (entry instanceof UndefinedBibtexEntry) { - String key = ((UndefinedBibtexEntry) entry).getKey(); - if (!unresolvedKeys.contains(key)) { - unresolvedKeys.add(key); - } - } - } - return unresolvedKeys; - } - - private List getSortedReferenceMarks(final XNameAccess nameAccess) - throws WrappedTargetException, NoSuchElementException { - XTextViewCursorSupplier cursorSupplier = UnoRuntime.queryInterface(XTextViewCursorSupplier.class, - mxDoc.getCurrentController()); - - XTextViewCursor viewCursor = cursorSupplier.getViewCursor(); - XTextRange initialPos = viewCursor.getStart(); - List names = Arrays.asList(nameAccess.getElementNames()); - List positions = new ArrayList<>(names.size()); - for (String name : names) { - XTextContent textContent = UnoRuntime.queryInterface(XTextContent.class, nameAccess.getByName(name)); - XTextRange range = textContent.getAnchor(); - // Check if we are inside a footnote: - if (UnoRuntime.queryInterface(XFootnote.class, range.getText()) != null) { - // Find the linking footnote marker: - XFootnote footer = UnoRuntime.queryInterface(XFootnote.class, range.getText()); - // The footnote's anchor gives the correct position in the text: - range = footer.getAnchor(); - } - - positions.add(findPosition(viewCursor, range)); - } - Set set = new TreeSet<>(); - for (int i = 0; i < positions.size(); i++) { - set.add(new ComparableMark(names.get(i), positions.get(i))); - } - - List result = new ArrayList<>(set.size()); - for (ComparableMark mark : set) { - result.add(mark.getName()); - } - viewCursor.gotoRange(initialPos, false); - - return result; - } - - public XNameAccess getReferenceMarks() { - XReferenceMarksSupplier supplier = UnoRuntime.queryInterface(XReferenceMarksSupplier.class, xCurrentComponent); - return supplier.getReferenceMarks(); - } - - private String getUniqueReferenceMarkName(String bibtexKey, int type) { - XNameAccess xNamedRefMarks = getReferenceMarks(); - int i = 0; - String name = OOBibBase.BIB_CITATION + '_' + type + '_' + bibtexKey; - while (xNamedRefMarks.hasByName(name)) { - name = OOBibBase.BIB_CITATION + i + '_' + type + '_' + bibtexKey; - i++; - } - return name; - } - - public void rebuildBibTextSection(List databases, OOBibStyle style) - throws NoSuchElementException, WrappedTargetException, IllegalArgumentException, - CreationException, PropertyVetoException, UnknownPropertyException, UndefinedParagraphFormatException { - List cited = findCitedKeys(); - Map linkSourceBase = new HashMap<>(); - Map entries = findCitedEntries(databases, cited, linkSourceBase); // Although entries are redefined without use, this also updates linkSourceBase - - List names = sortedReferenceMarks; - - if (style.isSortByPosition()) { - // We need to sort the entries according to their order of appearance: - entries = getSortedEntriesFromSortedRefMarks(names, linkSourceBase); - } else { - SortedMap newMap = new TreeMap<>(entryComparator); - for (Map.Entry bibtexEntryBibtexDatabaseEntry : findCitedEntries(databases, cited, - linkSourceBase).entrySet()) { - newMap.put(bibtexEntryBibtexDatabaseEntry.getKey(), bibtexEntryBibtexDatabaseEntry.getValue()); - } - entries = newMap; - } - clearBibTextSectionContent2(); - populateBibTextSection(entries, style); - } - - private List findCitedKeys() throws NoSuchElementException, WrappedTargetException { - XNameAccess xNamedMarks = getReferenceMarks(); - String[] names = xNamedMarks.getElementNames(); - List keys = new ArrayList<>(); - for (String name1 : names) { - Object bookmark = xNamedMarks.getByName(name1); - UnoRuntime.queryInterface(XTextContent.class, bookmark); - - List newKeys = parseRefMarkName(name1); - for (String key : newKeys) { - if (!keys.contains(key)) { - keys.add(key); - } - } - } - - return keys; - } - - private Map findCitedEntries(List databases, List keys, - Map linkSourceBase) { - Map entries = new LinkedHashMap<>(); - for (String key : keys) { - boolean found = false; - for (BibDatabase database : databases) { - Optional entry = database.getEntryByCitationKey(key); - if (entry.isPresent()) { - entries.put(entry.get(), database); - linkSourceBase.put(key, database); - found = true; - break; - } - } - - if (!found) { - entries.put(new UndefinedBibtexEntry(key), null); - } - } - return entries; - } - - private Point findPosition(XTextViewCursor cursor, XTextRange range) { - cursor.gotoRange(range, false); - return cursor.getPosition(); - } - - /** - * Extract the list of citation keys from a reference mark name. - * - * @param name The reference mark name. - * @return The list of citation keys encoded in the name. - */ - public List parseRefMarkName(String name) { - List keys = new ArrayList<>(); - Matcher citeMatcher = CITE_PATTERN.matcher(name); - if (citeMatcher.find()) { - String[] keystring = citeMatcher.group(2).split(","); - for (String aKeystring : keystring) { - if (!keys.contains(aKeystring)) { - keys.add(aKeystring); - } - } - } - return keys; - } - - /** - * Resolve the citation key from a citation reference marker name, and look up the index of the key in a list of keys. - * - * @param citRefName The name of the ReferenceMark representing the citation. - * @param keys A List of citation keys representing the entries in the bibliography. - * @return the indices of the cited keys, -1 if a key is not found. Returns null if the ref name could not be resolved as a citation. - */ - private List findCitedEntryIndex(String citRefName, List keys) { - Matcher citeMatcher = CITE_PATTERN.matcher(citRefName); - if (citeMatcher.find()) { - List keyStrings = Arrays.asList(citeMatcher.group(2).split(",")); - List result = new ArrayList<>(keyStrings.size()); - for (String key : keyStrings) { - int ind = keys.indexOf(key); - result.add(ind == -1 ? -1 : 1 + ind); - } - return result; - } else { - return Collections.emptyList(); - } - } - - private Map getSortedEntriesFromSortedRefMarks(List names, - Map linkSourceBase) { - - Map newList = new LinkedHashMap<>(); - for (String name : names) { - Matcher citeMatcher = CITE_PATTERN.matcher(name); - if (citeMatcher.find()) { - String[] keys = citeMatcher.group(2).split(","); - for (String key : keys) { - BibDatabase database = linkSourceBase.get(key); - Optional origEntry = Optional.empty(); - if (database != null) { - origEntry = database.getEntryByCitationKey(key); - } - if (origEntry.isPresent()) { - if (!newList.containsKey(origEntry.get())) { - newList.put(origEntry.get(), database); - } - } else { - LOGGER.info("Citation key not found: '" + key + "'"); - LOGGER.info("Problem with reference mark: '" + name + "'"); - newList.put(new UndefinedBibtexEntry(key), null); - } - } - } - } - - return newList; - } - - public String getCitationContext(XNameAccess nameAccess, String refMarkName, int charBefore, int charAfter, - boolean htmlMarkup) - throws NoSuchElementException, WrappedTargetException { - Object referenceMark = nameAccess.getByName(refMarkName); - XTextContent bookmark = UnoRuntime.queryInterface(XTextContent.class, referenceMark); - - XTextCursor cursor = bookmark.getAnchor().getText().createTextCursorByRange(bookmark.getAnchor()); - String citPart = cursor.getString(); - int flex = 8; - for (int i = 0; i < charBefore; i++) { - try { - cursor.goLeft((short) 1, true); - if ((i >= (charBefore - flex)) && Character.isWhitespace(cursor.getString().charAt(0))) { - break; - } - } catch (IndexOutOfBoundsException ex) { - LOGGER.warn("Problem going left", ex); - } - } - int length = cursor.getString().length(); - int added = length - citPart.length(); - cursor.collapseToStart(); - for (int i = 0; i < (charAfter + length); i++) { - try { - cursor.goRight((short) 1, true); - if (i >= ((charAfter + length) - flex)) { - String strNow = cursor.getString(); - if (Character.isWhitespace(strNow.charAt(strNow.length() - 1))) { - break; - } - } - } catch (IndexOutOfBoundsException ex) { - LOGGER.warn("Problem going right", ex); - } - } - - String result = cursor.getString(); - if (htmlMarkup) { - result = result.substring(0, added) + "" + citPart + "" + result.substring(length); - } - return result.trim(); - } - - private void insertFullReferenceAtCursor(XTextCursor cursor, Map entries, OOBibStyle style, - String parFormat) - throws UndefinedParagraphFormatException, IllegalArgumentException, - UnknownPropertyException, PropertyVetoException, WrappedTargetException { - Map correctEntries; - // If we don't have numbered entries, we need to sort the entries before adding them: - if (style.isSortByPosition()) { - // Use the received map directly - correctEntries = entries; - } else { - // Sort map - Map newMap = new TreeMap<>(entryComparator); - newMap.putAll(entries); - correctEntries = newMap; - } - int number = 1; - for (Map.Entry entry : correctEntries.entrySet()) { - if (entry.getKey() instanceof UndefinedBibtexEntry) { - continue; - } - OOUtil.insertParagraphBreak(text, cursor); - if (style.isNumberEntries()) { - int minGroupingCount = style.getIntCitProperty(OOBibStyle.MINIMUM_GROUPING_COUNT); - OOUtil.insertTextAtCurrentLocation(text, cursor, - style.getNumCitationMarker(Collections.singletonList(number++), minGroupingCount, true), Collections.emptyList()); - } - Layout layout = style.getReferenceFormat(entry.getKey().getType()); - layout.setPostFormatter(POSTFORMATTER); - OOUtil.insertFullReferenceAtCurrentLocation(text, cursor, layout, parFormat, entry.getKey(), - entry.getValue(), uniquefiers.get(entry.getKey().getCitationKey().orElse(null))); - } - } - - private void createBibTextSection2(boolean end) - throws IllegalArgumentException, CreationException { - - XTextCursor mxDocCursor = text.createTextCursor(); - if (end) { - mxDocCursor.gotoEnd(false); - } - OOUtil.insertParagraphBreak(text, mxDocCursor); - // Create a new TextSection from the document factory and access it's XNamed interface - XNamed xChildNamed; - try { - xChildNamed = UnoRuntime.queryInterface(XNamed.class, - mxDocFactory.createInstance("com.sun.star.text.TextSection")); - } catch (Exception e) { - throw new CreationException(e.getMessage()); - } - // Set the new sections name to 'Child_Section' - xChildNamed.setName(OOBibBase.BIB_SECTION_NAME); - // Access the Child_Section's XTextContent interface and insert it into the document - XTextContent xChildSection = UnoRuntime.queryInterface(XTextContent.class, xChildNamed); - text.insertTextContent(mxDocCursor, xChildSection, false); - } - - private void clearBibTextSectionContent2() - throws NoSuchElementException, WrappedTargetException, IllegalArgumentException, CreationException { - - // Check if the section exists: - XTextSectionsSupplier supplier = UnoRuntime.queryInterface(XTextSectionsSupplier.class, mxDoc); - if (supplier.getTextSections().hasByName(OOBibBase.BIB_SECTION_NAME)) { - XTextSection section = (XTextSection) ((Any) supplier.getTextSections().getByName(OOBibBase.BIB_SECTION_NAME)) - .getObject(); - // Clear it: - XTextCursor cursor = text.createTextCursorByRange(section.getAnchor()); - cursor.gotoRange(section.getAnchor(), false); - cursor.setString(""); - } else { - createBibTextSection2(atEnd); - } - } - - private void populateBibTextSection(Map entries, OOBibStyle style) - throws NoSuchElementException, WrappedTargetException, PropertyVetoException, - UnknownPropertyException, UndefinedParagraphFormatException, IllegalArgumentException, CreationException { - XTextSectionsSupplier supplier = UnoRuntime.queryInterface(XTextSectionsSupplier.class, mxDoc); - XTextSection section = (XTextSection) ((Any) supplier.getTextSections().getByName(OOBibBase.BIB_SECTION_NAME)) - .getObject(); - XTextCursor cursor = text.createTextCursorByRange(section.getAnchor()); - OOUtil.insertTextAtCurrentLocation(text, cursor, (String) style.getProperty(OOBibStyle.TITLE), - (String) style.getProperty(OOBibStyle.REFERENCE_HEADER_PARAGRAPH_FORMAT)); - insertFullReferenceAtCursor(cursor, entries, style, - (String) style.getProperty(OOBibStyle.REFERENCE_PARAGRAPH_FORMAT)); - insertBookMark(OOBibBase.BIB_SECTION_END_NAME, cursor); - } - - private XTextContent insertBookMark(String name, XTextCursor position) - throws IllegalArgumentException, CreationException { - Object bookmark; - try { - bookmark = mxDocFactory.createInstance("com.sun.star.text.Bookmark"); - } catch (Exception e) { - throw new CreationException(e.getMessage()); - } - // name the bookmark - XNamed xNamed = UnoRuntime.queryInterface(XNamed.class, bookmark); - xNamed.setName(name); - // get XTextContent interface - XTextContent xTextContent = UnoRuntime.queryInterface(XTextContent.class, bookmark); - // insert bookmark at the end of the document - // instead of mxDocText.getEnd you could use a text cursor's XTextRange interface or any XTextRange - text.insertTextContent(position, xTextContent, true); - position.collapseToEnd(); - return xTextContent; - } - - private void insertReferenceMark(String name, String citationText, XTextCursor position, boolean withText, - OOBibStyle style) - throws UnknownPropertyException, WrappedTargetException, - PropertyVetoException, IllegalArgumentException, UndefinedCharacterFormatException, CreationException { - - // Check if there is "page info" stored for this citation. If so, insert it into - // the citation text before inserting the citation: - Optional pageInfo = getCustomProperty(name); - String citText; - if ((pageInfo.isPresent()) && !pageInfo.get().isEmpty()) { - citText = style.insertPageInfo(citationText, pageInfo.get()); - } else { - citText = citationText; - } - - Object bookmark; - try { - bookmark = mxDocFactory.createInstance("com.sun.star.text.ReferenceMark"); - } catch (Exception e) { - throw new CreationException(e.getMessage()); - } - // Name the reference - XNamed xNamed = UnoRuntime.queryInterface(XNamed.class, bookmark); - xNamed.setName(name); - - if (withText) { - position.setString(citText); - XPropertySet xCursorProps = UnoRuntime.queryInterface(XPropertySet.class, position); - - // Set language to [None]: - xCursorProps.setPropertyValue("CharLocale", new Locale("zxx", "", "")); - if (style.isFormatCitations()) { - String charStyle = style.getCitationCharacterFormat(); - try { - xCursorProps.setPropertyValue(CHAR_STYLE_NAME, charStyle); - } catch (UnknownPropertyException | PropertyVetoException | IllegalArgumentException | - WrappedTargetException ex) { - throw new UndefinedCharacterFormatException(charStyle); - } - } - } else { - position.setString(""); - } - - // get XTextContent interface - XTextContent xTextContent = UnoRuntime.queryInterface(XTextContent.class, bookmark); - - position.getText().insertTextContent(position, xTextContent, true); - - // Check if we should italicize the "et al." string in citations: - boolean italicize = style.getBooleanCitProperty(OOBibStyle.ITALIC_ET_AL); - if (italicize) { - String etAlString = style.getStringCitProperty(OOBibStyle.ET_AL_STRING); - int index = citText.indexOf(etAlString); - if (index >= 0) { - italicizeOrBold(position, true, index, index + etAlString.length()); - } - } - - position.collapseToEnd(); - } - - private void removeReferenceMark(String name) throws NoSuchElementException, WrappedTargetException { - XNameAccess xReferenceMarks = getReferenceMarks(); - if (xReferenceMarks.hasByName(name)) { - Object referenceMark = xReferenceMarks.getByName(name); - XTextContent bookmark = UnoRuntime.queryInterface(XTextContent.class, referenceMark); - text.removeTextContent(bookmark); - } - } - - /** - * Get the XTextRange corresponding to the named bookmark. - * - * @param name The name of the bookmark to find. - * @return The XTextRange for the bookmark. - * @throws WrappedTargetException - * @throws NoSuchElementException - */ - private XTextRange getBookmarkRange(String name) throws NoSuchElementException, WrappedTargetException { - XNameAccess xNamedBookmarks = getBookmarks(); - - // retrieve bookmark by name - if (!xNamedBookmarks.hasByName(name)) { - return null; - } - Object foundBookmark = xNamedBookmarks.getByName(name); - XTextContent xFoundBookmark = UnoRuntime.queryInterface(XTextContent.class, foundBookmark); - return xFoundBookmark.getAnchor(); - } - - private XNameAccess getBookmarks() { - // query XBookmarksSupplier from document model and get bookmarks collection - XBookmarksSupplier xBookmarksSupplier = UnoRuntime.queryInterface(XBookmarksSupplier.class, xCurrentComponent); - XNameAccess xNamedBookmarks = xBookmarksSupplier.getBookmarks(); - return xNamedBookmarks; - } - - private void italicizeOrBold(XTextCursor position, boolean italicize, int start, int end) - throws UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException { - XTextRange range = position.getStart(); - XTextCursor cursor = position.getText().createTextCursorByRange(range); - cursor.goRight((short) start, false); - cursor.goRight((short) (end - start), true); - XPropertySet xcp = UnoRuntime.queryInterface(XPropertySet.class, cursor); - if (italicize) { - xcp.setPropertyValue("CharPosture", com.sun.star.awt.FontSlant.ITALIC); - } else { - xcp.setPropertyValue("CharWeight", com.sun.star.awt.FontWeight.BOLD); - } - } - - public void combineCiteMarkers(List databases, OOBibStyle style) - throws IOException, WrappedTargetException, NoSuchElementException, IllegalArgumentException, - UndefinedCharacterFormatException, UnknownPropertyException, PropertyVetoException, CreationException, - BibEntryNotFoundException { - XNameAccess nameAccess = getReferenceMarks(); - // TODO: doesn't work for citations in footnotes/tables - List names = getSortedReferenceMarks(nameAccess); - - final XTextRangeCompare compare = UnoRuntime.queryInterface(XTextRangeCompare.class, text); - - int piv = 0; - boolean madeModifications = false; - while (piv < (names.size() - 1)) { - XTextRange range1 = UnoRuntime.queryInterface(XTextContent.class, nameAccess.getByName(names.get(piv))) - .getAnchor().getEnd(); - XTextRange range2 = UnoRuntime.queryInterface(XTextContent.class, nameAccess.getByName(names.get(piv + 1))) - .getAnchor().getStart(); - if (range1.getText() != range2.getText()) { - piv++; - continue; - } - XTextCursor mxDocCursor = range1.getText().createTextCursorByRange(range1); - mxDocCursor.goRight((short) 1, true); - boolean couldExpand = true; - while (couldExpand && (compare.compareRegionEnds(mxDocCursor, range2) > 0)) { - couldExpand = mxDocCursor.goRight((short) 1, true); - } - String cursorText = mxDocCursor.getString(); - // Check if the string contains no line breaks and only whitespace: - if ((cursorText.indexOf('\n') == -1) && cursorText.trim().isEmpty()) { - - // If we are supposed to set character format for citations, test this before - // making any changes. This way we can throw an exception before any reference - // marks are removed, preventing damage to the user's document: - if (style.isFormatCitations()) { - XPropertySet xCursorProps = UnoRuntime.queryInterface(XPropertySet.class, mxDocCursor); - String charStyle = style.getCitationCharacterFormat(); - try { - xCursorProps.setPropertyValue(CHAR_STYLE_NAME, charStyle); - } catch (UnknownPropertyException | PropertyVetoException | IllegalArgumentException | - WrappedTargetException ex) { - // Setting the character format failed, so we throw an exception that - // will result in an error message for the user: - throw new UndefinedCharacterFormatException(charStyle); - } - } - - List keys = parseRefMarkName(names.get(piv)); - keys.addAll(parseRefMarkName(names.get(piv + 1))); - removeReferenceMark(names.get(piv)); - removeReferenceMark(names.get(piv + 1)); - List entries = new ArrayList<>(); - for (String key : keys) { - for (BibDatabase database : databases) { - Optional entry = database.getEntryByCitationKey(key); - if (entry.isPresent()) { - entries.add(entry.get()); - break; - } - } - } - Collections.sort(entries, new FieldComparator(StandardField.YEAR)); - String keyString = String.join(",", entries.stream().map(entry -> entry.getCitationKey().orElse("")) - .collect(Collectors.toList())); - // Insert bookmark: - String bName = getUniqueReferenceMarkName(keyString, OOBibBase.AUTHORYEAR_PAR); - insertReferenceMark(bName, "tmp", mxDocCursor, true, style); - names.set(piv + 1, bName); - madeModifications = true; - } - piv++; - } - if (madeModifications) { - updateSortedReferenceMarks(); - refreshCiteMarkers(databases, style); - } - } - - /** - * Do the opposite of combineCiteMarkers. - * Combined markers are split, with a space inserted between. - */ - public void unCombineCiteMarkers(List databases, OOBibStyle style) - throws IOException, WrappedTargetException, NoSuchElementException, IllegalArgumentException, - UndefinedCharacterFormatException, UnknownPropertyException, PropertyVetoException, CreationException, - BibEntryNotFoundException { - XNameAccess nameAccess = getReferenceMarks(); - List names = getSortedReferenceMarks(nameAccess); - - final XTextRangeCompare compare = UnoRuntime.queryInterface(XTextRangeCompare.class, text); - - int pivot = 0; - boolean madeModifications = false; - while (pivot < (names.size())) { - XTextRange range1 = UnoRuntime.queryInterface(XTextContent.class, nameAccess.getByName(names.get(pivot))) - .getAnchor(); - - XTextCursor textCursor = range1.getText().createTextCursorByRange(range1); - - // If we are supposed to set character format for citations, test this before - // making any changes. This way we can throw an exception before any reference - // marks are removed, preventing damage to the user's document: - if (style.isFormatCitations()) { - XPropertySet xCursorProps = UnoRuntime.queryInterface(XPropertySet.class, textCursor); - String charStyle = style.getCitationCharacterFormat(); - try { - xCursorProps.setPropertyValue(CHAR_STYLE_NAME, charStyle); - } catch (UnknownPropertyException | PropertyVetoException | IllegalArgumentException | - WrappedTargetException ex) { - // Setting the character format failed, so we throw an exception that - // will result in an error message for the user: - throw new UndefinedCharacterFormatException(charStyle); - } - } - - List keys = parseRefMarkName(names.get(pivot)); - if (keys.size() > 1) { - removeReferenceMark(names.get(pivot)); - - // Insert bookmark for each key - int last = keys.size() - 1; - int i = 0; - for (String key : keys) { - String newName = getUniqueReferenceMarkName(key, OOBibBase.AUTHORYEAR_PAR); - insertReferenceMark(newName, "tmp", textCursor, true, style); - textCursor.collapseToEnd(); - if (i != last) { - textCursor.setString(" "); - textCursor.collapseToEnd(); - } - i++; - } - madeModifications = true; - } - pivot++; - } - if (madeModifications) { - updateSortedReferenceMarks(); - refreshCiteMarkers(databases, style); - } - } - - public BibDatabase generateDatabase(List databases) - throws NoSuchElementException, WrappedTargetException { - BibDatabase resultDatabase = new BibDatabase(); - List cited = findCitedKeys(); - List entriesToInsert = new ArrayList<>(); - - // For each cited key - for (String key : cited) { - // Loop through the available databases - for (BibDatabase loopDatabase : databases) { - Optional entry = loopDatabase.getEntryByCitationKey(key); - // If entry found - if (entry.isPresent()) { - BibEntry clonedEntry = (BibEntry) entry.get().clone(); - // Insert a copy of the entry - entriesToInsert.add(clonedEntry); - // Check if the cloned entry has a crossref field - clonedEntry.getField(StandardField.CROSSREF).ifPresent(crossref -> { - // If the crossref entry is not already in the database - if (!resultDatabase.getEntryByCitationKey(crossref).isPresent()) { - // Add it if it is in the current library - loopDatabase.getEntryByCitationKey(crossref).ifPresent(entriesToInsert::add); - } - }); - - // Be happy with the first found BibEntry and move on to next key - break; - } - } - } - resultDatabase.insertEntries(entriesToInsert); - return resultDatabase; - } - - private static class ComparableMark implements Comparable { - - private final String name; - private final Point position; - - public ComparableMark(String name, Point position) { - this.name = name; - this.position = position; - } - - @Override - public int compareTo(ComparableMark other) { - if (position.Y == other.position.Y) { - return position.X - other.position.X; - } else { - return position.Y - other.position.Y; - } - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (o instanceof ComparableMark) { - ComparableMark other = (ComparableMark) o; - return (this.position.X == other.position.X) && (this.position.Y == other.position.Y) - && Objects.equals(this.name, other.name); - } - return false; - } - - public String getName() { - return name; - } - - @Override - public int hashCode() { - return Objects.hash(position, name); - } - } - - private class DocumentTitleViewModel { - - private final XTextDocument xTextDocument; - private final String description; - - public DocumentTitleViewModel(XTextDocument xTextDocument) { - this.xTextDocument = xTextDocument; - this.description = getDocumentTitle(xTextDocument).orElse(""); - } - - public XTextDocument getXtextDocument() { - return xTextDocument; - } - - @Override - public String toString() { - return description; - } - } -} diff --git a/src/main/java/org/jabref/gui/openoffice/UndefinedCharacterFormatException.java b/src/main/java/org/jabref/gui/openoffice/UndefinedCharacterFormatException.java deleted file mode 100644 index 4ab29ca2fa5..00000000000 --- a/src/main/java/org/jabref/gui/openoffice/UndefinedCharacterFormatException.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.jabref.gui.openoffice; - -/** - * Exception used to indicate that the plugin attempted to set a character format that is - * not defined in the current OpenOffice document. - */ -class UndefinedCharacterFormatException extends Exception { - - private final String formatName; - - public UndefinedCharacterFormatException(String formatName) { - super(); - this.formatName = formatName; - } - - public String getFormatName() { - return formatName; - } -} diff --git a/src/main/java/org/jabref/logic/openoffice/OOUtil.java b/src/main/java/org/jabref/logic/openoffice/OOUtil.java deleted file mode 100644 index 9efab82773c..00000000000 --- a/src/main/java/org/jabref/logic/openoffice/OOUtil.java +++ /dev/null @@ -1,285 +0,0 @@ -package org.jabref.logic.openoffice; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.jabref.architecture.AllowedToUseAwt; -import org.jabref.logic.layout.Layout; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.Field; -import org.jabref.model.entry.field.UnknownField; - -import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.beans.XPropertySet; -import com.sun.star.lang.WrappedTargetException; -import com.sun.star.text.ControlCharacter; -import com.sun.star.text.XParagraphCursor; -import com.sun.star.text.XText; -import com.sun.star.text.XTextCursor; -import com.sun.star.uno.UnoRuntime; - -/** - * Utility methods for processing OO Writer documents. - */ -@AllowedToUseAwt("Requires AWT for changing document properties") -public class OOUtil { - - private static final String CHAR_STRIKEOUT = "CharStrikeout"; - private static final String CHAR_UNDERLINE = "CharUnderline"; - private static final String PARA_STYLE_NAME = "ParaStyleName"; - private static final String CHAR_CASE_MAP = "CharCaseMap"; - private static final String CHAR_POSTURE = "CharPosture"; - private static final String CHAR_WEIGHT = "CharWeight"; - private static final String CHAR_ESCAPEMENT_HEIGHT = "CharEscapementHeight"; - private static final String CHAR_ESCAPEMENT = "CharEscapement"; - - public enum Formatting { - BOLD, - ITALIC, - SMALLCAPS, - SUPERSCRIPT, - SUBSCRIPT, - UNDERLINE, - STRIKEOUT, - MONOSPACE - } - - private static final Pattern HTML_TAG = Pattern.compile(""); - - private static final Field UNIQUEFIER_FIELD = new UnknownField("uniq"); - - private OOUtil() { - // Just to hide the public constructor - } - - /** - * Insert a reference, formatted using a Layout, at the position of a given cursor. - * - * @param text The text to insert in. - * @param cursor The cursor giving the insert location. - * @param layout The Layout to format the reference with. - * @param parStyle The name of the paragraph style to use. - * @param entry The entry to insert. - * @param database The database the entry belongs to. - * @param uniquefier Uniqiefier letter, if any, to append to the entry's year. - */ - public static void insertFullReferenceAtCurrentLocation(XText text, XTextCursor cursor, - Layout layout, String parStyle, BibEntry entry, BibDatabase database, String uniquefier) - throws UndefinedParagraphFormatException, UnknownPropertyException, PropertyVetoException, - WrappedTargetException, IllegalArgumentException { - - // Backup the value of the uniq field, just in case the entry already has it: - Optional oldUniqVal = entry.getField(UNIQUEFIER_FIELD); - - // Set the uniq field with the supplied uniquefier: - if (uniquefier == null) { - entry.clearField(UNIQUEFIER_FIELD); - } else { - entry.setField(UNIQUEFIER_FIELD, uniquefier); - } - - // Do the layout for this entry: - String formattedText = layout.doLayout(entry, database); - - // Afterwards, reset the old value: - if (oldUniqVal.isPresent()) { - entry.setField(UNIQUEFIER_FIELD, oldUniqVal.get()); - } else { - entry.clearField(UNIQUEFIER_FIELD); - } - - // Insert the formatted text: - OOUtil.insertOOFormattedTextAtCurrentLocation(text, cursor, formattedText, parStyle); - } - - /** - * Insert a text with formatting indicated by HTML-like tags, into a text at the position given by a cursor. - * - * @param text The text to insert in. - * @param cursor The cursor giving the insert location. - * @param lText The marked-up text to insert. - * @param parStyle The name of the paragraph style to use. - * @throws WrappedTargetException - * @throws PropertyVetoException - * @throws UnknownPropertyException - * @throws IllegalArgumentException - */ - public static void insertOOFormattedTextAtCurrentLocation(XText text, XTextCursor cursor, String lText, - String parStyle) throws UndefinedParagraphFormatException, UnknownPropertyException, PropertyVetoException, - WrappedTargetException, IllegalArgumentException { - - XParagraphCursor parCursor = UnoRuntime.queryInterface( - XParagraphCursor.class, cursor); - XPropertySet props = UnoRuntime.queryInterface( - XPropertySet.class, parCursor); - - try { - props.setPropertyValue(PARA_STYLE_NAME, parStyle); - } catch (com.sun.star.lang.IllegalArgumentException ex) { - throw new UndefinedParagraphFormatException(parStyle); - } - - List formatting = new ArrayList<>(); - // We need to extract formatting. Use a simple regexp search iteration: - int piv = 0; - Matcher m = OOUtil.HTML_TAG.matcher(lText); - while (m.find()) { - String currentSubstring = lText.substring(piv, m.start()); - if (!currentSubstring.isEmpty()) { - OOUtil.insertTextAtCurrentLocation(text, cursor, currentSubstring, formatting); - } - String tag = m.group(); - // Handle tags: - if ("".equals(tag)) { - formatting.add(Formatting.BOLD); - } else if ("".equals(tag)) { - formatting.remove(Formatting.BOLD); - } else if ("".equals(tag) || "".equals(tag)) { - formatting.add(Formatting.ITALIC); - } else if ("".equals(tag) || "".equals(tag)) { - formatting.remove(Formatting.ITALIC); - } else if ("".equals(tag)) { - formatting.add(Formatting.MONOSPACE); - } else if ("".equals(tag)) { - formatting.remove(Formatting.MONOSPACE); - } else if ("".equals(tag)) { - formatting.add(Formatting.SMALLCAPS); - } else if ("".equals(tag)) { - formatting.remove(Formatting.SMALLCAPS); - } else if ("".equals(tag)) { - formatting.add(Formatting.SUPERSCRIPT); - } else if ("".equals(tag)) { - formatting.remove(Formatting.SUPERSCRIPT); - } else if ("".equals(tag)) { - formatting.add(Formatting.SUBSCRIPT); - } else if ("".equals(tag)) { - formatting.remove(Formatting.SUBSCRIPT); - } else if ("".equals(tag)) { - formatting.add(Formatting.UNDERLINE); - } else if ("".equals(tag)) { - formatting.remove(Formatting.UNDERLINE); - } else if ("".equals(tag)) { - formatting.add(Formatting.STRIKEOUT); - } else if ("".equals(tag)) { - formatting.remove(Formatting.STRIKEOUT); - } - - piv = m.end(); - } - - if (piv < lText.length()) { - OOUtil.insertTextAtCurrentLocation(text, cursor, lText.substring(piv), formatting); - } - - cursor.collapseToEnd(); - } - - public static void insertParagraphBreak(XText text, XTextCursor cursor) throws IllegalArgumentException { - text.insertControlCharacter(cursor, ControlCharacter.PARAGRAPH_BREAK, true); - cursor.collapseToEnd(); - } - - public static void insertTextAtCurrentLocation(XText text, XTextCursor cursor, String string, - List formatting) - throws UnknownPropertyException, PropertyVetoException, WrappedTargetException, - IllegalArgumentException { - text.insertString(cursor, string, true); - // Access the property set of the cursor, and set the currently selected text - // (which is the string we just inserted) to be bold - XPropertySet xCursorProps = UnoRuntime.queryInterface( - XPropertySet.class, cursor); - if (formatting.contains(Formatting.BOLD)) { - xCursorProps.setPropertyValue(CHAR_WEIGHT, - com.sun.star.awt.FontWeight.BOLD); - } else { - xCursorProps.setPropertyValue(CHAR_WEIGHT, - com.sun.star.awt.FontWeight.NORMAL); - } - - if (formatting.contains(Formatting.ITALIC)) { - xCursorProps.setPropertyValue(CHAR_POSTURE, - com.sun.star.awt.FontSlant.ITALIC); - } else { - xCursorProps.setPropertyValue(CHAR_POSTURE, - com.sun.star.awt.FontSlant.NONE); - } - - if (formatting.contains(Formatting.SMALLCAPS)) { - xCursorProps.setPropertyValue(CHAR_CASE_MAP, - com.sun.star.style.CaseMap.SMALLCAPS); - } else { - xCursorProps.setPropertyValue(CHAR_CASE_MAP, - com.sun.star.style.CaseMap.NONE); - } - - // TODO: the tag doesn't work - /* - if (formatting.contains(Formatting.MONOSPACE)) { - xCursorProps.setPropertyValue("CharFontPitch", - com.sun.star.awt.FontPitch.FIXED); - } - else { - xCursorProps.setPropertyValue("CharFontPitch", - com.sun.star.awt.FontPitch.VARIABLE); - } */ - if (formatting.contains(Formatting.SUBSCRIPT)) { - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT, - (byte) -101); - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT_HEIGHT, - (byte) 58); - } else if (formatting.contains(Formatting.SUPERSCRIPT)) { - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT, - (byte) 101); - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT_HEIGHT, - (byte) 58); - } else { - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT, - (byte) 0); - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT_HEIGHT, - (byte) 100); - } - - if (formatting.contains(Formatting.UNDERLINE)) { - xCursorProps.setPropertyValue(CHAR_UNDERLINE, com.sun.star.awt.FontUnderline.SINGLE); - } else { - xCursorProps.setPropertyValue(CHAR_UNDERLINE, com.sun.star.awt.FontUnderline.NONE); - } - - if (formatting.contains(Formatting.STRIKEOUT)) { - xCursorProps.setPropertyValue(CHAR_STRIKEOUT, com.sun.star.awt.FontStrikeout.SINGLE); - } else { - xCursorProps.setPropertyValue(CHAR_STRIKEOUT, com.sun.star.awt.FontStrikeout.NONE); - } - cursor.collapseToEnd(); - } - - public static void insertTextAtCurrentLocation(XText text, XTextCursor cursor, String string, String parStyle) - throws WrappedTargetException, PropertyVetoException, UnknownPropertyException, - UndefinedParagraphFormatException { - text.insertString(cursor, string, true); - XParagraphCursor parCursor = UnoRuntime.queryInterface( - XParagraphCursor.class, cursor); - // Access the property set of the cursor, and set the currently selected text - // (which is the string we just inserted) to be bold - XPropertySet props = UnoRuntime.queryInterface( - XPropertySet.class, parCursor); - try { - props.setPropertyValue(PARA_STYLE_NAME, parStyle); - } catch (IllegalArgumentException ex) { - throw new UndefinedParagraphFormatException(parStyle); - } - cursor.collapseToEnd(); - } - - public static Object getProperty(Object o, String property) - throws UnknownPropertyException, WrappedTargetException { - XPropertySet props = UnoRuntime.queryInterface( - XPropertySet.class, o); - return props.getPropertyValue(property); - } -} diff --git a/src/main/java/org/jabref/logic/openoffice/UndefinedBibtexEntry.java b/src/main/java/org/jabref/logic/openoffice/UndefinedBibtexEntry.java deleted file mode 100644 index 8a1a7cf5e8f..00000000000 --- a/src/main/java/org/jabref/logic/openoffice/UndefinedBibtexEntry.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.jabref.logic.openoffice; - -import org.jabref.logic.openoffice.style.OOBibStyle; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.StandardField; - -/** - * Subclass of BibEntry for representing entries referenced in a document that can't be found in JabRef's current database. - */ -public class UndefinedBibtexEntry extends BibEntry { - - private final String key; - - public UndefinedBibtexEntry(String key) { - this.key = key; - setField(StandardField.AUTHOR, OOBibStyle.UNDEFINED_CITATION_MARKER); - } - - public String getKey() { - return key; - } -} diff --git a/src/main/java/org/jabref/logic/openoffice/UndefinedParagraphFormatException.java b/src/main/java/org/jabref/logic/openoffice/UndefinedParagraphFormatException.java deleted file mode 100644 index 361f8d44f54..00000000000 --- a/src/main/java/org/jabref/logic/openoffice/UndefinedParagraphFormatException.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.jabref.logic.openoffice; - -/** - * Exception used to indicate that the plugin attempted to set a paragraph format that is not defined in the current OpenOffice document. - */ -public class UndefinedParagraphFormatException extends Exception { - - private final String formatName; - - public UndefinedParagraphFormatException(String formatName) { - super(); - this.formatName = formatName; - } - - public String getFormatName() { - return formatName; - } -} diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index 113cef246e2..0d81bdbd024 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -25,11 +25,6 @@ import org.jabref.logic.layout.LayoutFormatter; import org.jabref.logic.layout.LayoutFormatterPreferences; import org.jabref.logic.layout.LayoutHelper; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.Author; -import org.jabref.model.entry.AuthorList; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.FieldFactory; import org.jabref.model.entry.field.OrFields; import org.jabref.model.entry.field.StandardField; @@ -44,7 +39,6 @@ import org.jabref.model.openoffice.style.NonUniqueCitationMarker; import org.jabref.model.openoffice.style.PageInfo; import org.jabref.model.openoffice.util.OOListUtil; -import org.jabref.model.strings.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -447,365 +441,6 @@ public Layout getReferenceFormat(EntryType type) { } } - /* begin_old */ - /** - * Format a number-based citation marker for the given number. - * - * @param number The citation numbers. - * @return The text for the citation. - */ - public String getNumCitationMarker(List number, int minGroupingCount, boolean inList) { - String bracketBefore = getStringCitProperty(BRACKET_BEFORE); - if (inList && (citProperties.containsKey(BRACKET_BEFORE_IN_LIST))) { - bracketBefore = getStringCitProperty(BRACKET_BEFORE_IN_LIST); - } - String bracketAfter = getStringCitProperty(BRACKET_AFTER); - if (inList && (citProperties.containsKey(BRACKET_AFTER_IN_LIST))) { - bracketAfter = getStringCitProperty(BRACKET_AFTER_IN_LIST); - } - // Sort the numbers: - List lNum = new ArrayList<>(number); - Collections.sort(lNum); - StringBuilder sb = new StringBuilder(bracketBefore); - int combineFrom = -1; - int written = 0; - for (int i = 0; i < lNum.size(); i++) { - int i1 = lNum.get(i); - if (combineFrom < 0) { - // Check if next entry is the next in the ref list: - if ((i < (lNum.size() - 1)) && (lNum.get(i + 1) == (i1 + 1)) && (i1 > 0)) { - combineFrom = i1; - } else { - // Add single entry: - if (i > 0) { - sb.append(getStringCitProperty(CITATION_SEPARATOR)); - } - sb.append(lNum.get(i) > 0 ? String.valueOf(lNum.get(i)) : OOBibStyle.UNDEFINED_CITATION_MARKER); - written++; - } - } else { - // We are building a list of combined entries. - // Check if it ends here: - if ((i == (lNum.size() - 1)) || (lNum.get(i + 1) != (i1 + 1))) { - if (written > 0) { - sb.append(getStringCitProperty(CITATION_SEPARATOR)); - } - if ((minGroupingCount > 0) && (((i1 + 1) - combineFrom) >= minGroupingCount)) { - sb.append(combineFrom); - sb.append(getStringCitProperty(GROUPED_NUMBERS_SEPARATOR)); - sb.append(i1); - written++; - } else { - // Either we should never group, or there aren't enough - // entries in this case to group. Output all: - for (int jj = combineFrom; jj <= i1; jj++) { - sb.append(jj); - if (jj < i1) { - sb.append(getStringCitProperty(CITATION_SEPARATOR)); - } - written++; - } - } - combineFrom = -1; - } - // If it doesn't end here, just keep iterating. - } - } - sb.append(bracketAfter); - return sb.toString(); - } - /* end_old */ - - /* begin_old */ - /** - * Format the marker for the in-text citation according to this BIB style. Uniquefier letters are added as - * provided by the uniquefiers argument. If successive entries within the citation are uniquefied from each other, - * this method will perform a grouping of these entries. - * - * @param entries The list of JabRef BibEntry providing the data. - * @param database A map of BibEntry-BibDatabase pairs. - * @param inParenthesis Signals whether a parenthesized citation or an in-text citation is wanted. - * @param uniquefiers Strings to add behind the year for each entry in case it's needed to separate similar - * entries. - * @param unlimAuthors Boolean for each entry. If true, we should not use "et al" formatting regardless - * of the number of authors. Can be null to indicate that no entries should have unlimited names. - * @return The formatted citation. - */ - public String getCitationMarker(List entries, Map database, boolean inParenthesis, - String[] uniquefiers, int[] unlimAuthors) { - // Look for groups of uniquefied entries that should be combined in the output. - // E.g. (Olsen, 2005a, b) should be output instead of (Olsen, 2005a; Olsen, 2005b). - int piv = -1; - String tmpMarker = null; - if (uniquefiers != null) { - for (int i = 0; i < uniquefiers.length; i++) { - - if ((uniquefiers[i] == null) || uniquefiers[i].isEmpty()) { - // This entry has no uniquefier. - // Check if we just passed a group of more than one entry with uniquefier: - if ((piv > -1) && (i > (piv + 1))) { - // Do the grouping: - group(entries, uniquefiers, piv, i - 1); - } - - piv = -1; - } else { - BibEntry currentEntry = entries.get(i); - if (piv == -1) { - piv = i; - tmpMarker = getAuthorYearParenthesisMarker(Collections.singletonList(currentEntry), database, - null, unlimAuthors); - } else { - // See if this entry can go into a group with the previous one: - String thisMarker = getAuthorYearParenthesisMarker(Collections.singletonList(currentEntry), - database, null, unlimAuthors); - - String authorField = getStringCitProperty(AUTHOR_FIELD); - int maxAuthors = getIntCitProperty(MAX_AUTHORS); - String author = getCitationMarkerField(currentEntry, database.get(currentEntry), - authorField); - AuthorList al = AuthorList.parse(author); - int prevALim = unlimAuthors[i - 1]; // i always at least 1 here - if (!thisMarker.equals(tmpMarker) - || ((al.getNumberOfAuthors() > maxAuthors) && (unlimAuthors[i] != prevALim))) { - // No match. Update piv to exclude the previous entry. But first check if the - // previous entry was part of a group: - if ((piv > -1) && (i > (piv + 1))) { - // Do the grouping: - group(entries, uniquefiers, piv, i - 1); - } - tmpMarker = thisMarker; - piv = i; - } - } - } - - } - // Finished with the loop. See if the last entries form a group: - if (piv >= 0) { - // Do the grouping: - group(entries, uniquefiers, piv, uniquefiers.length - 1); - } - } - - if (inParenthesis) { - return getAuthorYearParenthesisMarker(entries, database, uniquefiers, unlimAuthors); - } else { - return getAuthorYearInTextMarker(entries, database, uniquefiers, unlimAuthors); - } - } - /* end_old */ - - /* begin_old */ - /** - * Modify entry and uniquefier arrays to facilitate a grouped presentation of uniquefied entries. - * - * @param entries The entry array. - * @param uniquefiers The uniquefier array. - * @param from The first index to group (inclusive) - * @param to The last index to group (inclusive) - */ - private void group(List entries, String[] uniquefiers, int from, int to) { - String separator = getStringCitProperty(UNIQUEFIER_SEPARATOR); - StringBuilder sb = new StringBuilder(uniquefiers[from]); - for (int i = from + 1; i <= to; i++) { - sb.append(separator); - sb.append(uniquefiers[i]); - entries.set(i, null); - } - uniquefiers[from] = sb.toString(); - } - /* end_old */ - - /* begin_old */ - /** - * This method produces (Author, year) style citation strings in many different forms. - * - * @param entries The list of BibEntry to get fields from. - * @param database A map of BibEntry-BibDatabase pairs. - * @param uniquifiers Optional parameter to separate similar citations. Elements can be null if not needed. - * @return The formatted citation. - */ - private String getAuthorYearParenthesisMarker(List entries, Map database, - String[] uniquifiers, int[] unlimAuthors) { - - String authorField = getStringCitProperty(AUTHOR_FIELD); // The bibtex field providing author names, e.g. "author" or "editor". - int maxA = getIntCitProperty(MAX_AUTHORS); // The maximum number of authors to write out in full without using etal. Set to - // -1 to always write out all authors. - String yearSep = getStringCitProperty(YEAR_SEPARATOR); // The String to separate authors from year, e.g. "; ". - String startBrace = getStringCitProperty(BRACKET_BEFORE); // The opening parenthesis. - String endBrace = getStringCitProperty(BRACKET_AFTER); // The closing parenthesis. - String citationSeparator = getStringCitProperty(CITATION_SEPARATOR); // The String to separate citations from each other. - String yearField = getStringCitProperty(YEAR_FIELD); // The bibtex field providing the year, e.g. "year". - String andString = getStringCitProperty(AUTHOR_LAST_SEPARATOR); // The String to add between the two last author names, e.g. " & ". - StringBuilder sb = new StringBuilder(startBrace); - for (int j = 0; j < entries.size(); j++) { - BibEntry currentEntry = entries.get(j); - - // Check if this entry has been nulled due to grouping with the previous entry(ies): - if (currentEntry == null) { - continue; - } - - if (j > 0) { - sb.append(citationSeparator); - } - - BibDatabase currentDatabase = database.get(currentEntry); - int unlimA = unlimAuthors == null ? -1 : unlimAuthors[j]; - int maxAuthors = unlimA > 0 ? unlimA : maxA; - - String author = getCitationMarkerField(currentEntry, currentDatabase, authorField); - String authorString = createAuthorList(author, maxAuthors, andString, yearSep); - sb.append(authorString); - String year = getCitationMarkerField(currentEntry, currentDatabase, yearField); - if (year != null) { - sb.append(year); - } - if ((uniquifiers != null) && (uniquifiers[j] != null)) { - sb.append(uniquifiers[j]); - } - } - sb.append(endBrace); - return sb.toString(); - } - /* end_old */ - - /* begin_old */ - /** - * This method produces "Author (year)" style citation strings in many different forms. - * - * @param entries The list of BibEntry to get fields from. - * @param database A map of BibEntry-BibDatabase pairs. - * @param uniquefiers Optional parameters to separate similar citations. Can be null if not needed. - * @return The formatted citation. - */ - private String getAuthorYearInTextMarker(List entries, Map database, - String[] uniquefiers, - int[] unlimAuthors) { - String authorField = getStringCitProperty(AUTHOR_FIELD); // The bibtex field providing author names, e.g. "author" or "editor". - int maxA = getIntCitProperty(MAX_AUTHORS); // The maximum number of authors to write out in full without using etal. Set to - // -1 to always write out all authors. - String yearSep = getStringCitProperty(IN_TEXT_YEAR_SEPARATOR); // The String to separate authors from year, e.g. "; ". - String startBrace = getStringCitProperty(BRACKET_BEFORE); // The opening parenthesis. - String endBrace = getStringCitProperty(BRACKET_AFTER); // The closing parenthesis. - String citationSeparator = getStringCitProperty(CITATION_SEPARATOR); // The String to separate citations from each other. - String yearField = getStringCitProperty(YEAR_FIELD); // The bibtex field providing the year, e.g. "year". - String andString = getStringCitProperty(AUTHOR_LAST_SEPARATOR_IN_TEXT); // The String to add between the two last author names, e.g. " & ". - - if (andString == null) { - // Use the default one if no explicit separator for text is defined - andString = getStringCitProperty(AUTHOR_LAST_SEPARATOR); - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < entries.size(); i++) { - BibEntry currentEntry = entries.get(i); - - // Check if this entry has been nulled due to grouping with the previous entry(ies): - if (currentEntry == null) { - continue; - } - - BibDatabase currentDatabase = database.get(currentEntry); - int unlimA = unlimAuthors == null ? -1 : unlimAuthors[i]; - int maxAuthors = unlimA > 0 ? unlimA : maxA; - - if (i > 0) { - sb.append(citationSeparator); - } - String author = getCitationMarkerField(currentEntry, currentDatabase, authorField); - String authorString = createAuthorList(author, maxAuthors, andString, yearSep); - sb.append(authorString); - sb.append(startBrace); - String year = getCitationMarkerField(currentEntry, currentDatabase, yearField); - if (year != null) { - sb.append(year); - } - if ((uniquefiers != null) && (uniquefiers[i] != null)) { - sb.append(uniquefiers[i]); - } - sb.append(endBrace); - } - return sb.toString(); - - } - /* end_old */ - - /* begin_old */ - /* moved to OOBibStyleGetCitationMarker */ - /** - * This method looks up a field for an entry in a database. Any number of backup fields can be used - * if the primary field is empty. - * - * @param entry The entry. - * @param database The database the entry belongs to. - * @param fields The field, or succession of fields, to look up. If backup fields are needed, separate - * field names by /. E.g. to use "author" with "editor" as backup, specify StandardField.orFields(StandardField.AUTHOR, StandardField.EDITOR). - * @return The resolved field content, or an empty string if the field(s) were empty. - */ - private String getCitationMarkerField(BibEntry entry, BibDatabase database, String fields) { - Objects.requireNonNull(entry, "Entry cannot be null"); - Objects.requireNonNull(database, "database cannot be null"); - - Set authorFields = FieldFactory.parseOrFields(getStringCitProperty(AUTHOR_FIELD)); - for (Field field : FieldFactory.parseOrFields(fields)) { - Optional content = entry.getResolvedFieldOrAlias(field, database); - - if ((content.isPresent()) && !content.get().trim().isEmpty()) { - if (authorFields.contains(field) && StringUtil.isInCurlyBrackets(content.get())) { - return "{" + fieldFormatter.format(content.get()) + "}"; - } - return fieldFormatter.format(content.get()); - } - } - // No luck? Return an empty string: - return ""; - } - /* end_old */ - - /* begin_old */ - /* moved to OOBibStyleGetCitationMarker */ - /** - * Look up the nth author and return the proper last name for citation markers. - * - * @param al The author list. - * @param number The number of the author to return. - * @return The author name, or an empty String if inapplicable. - */ - private String getAuthorLastName(AuthorList al, int number) { - StringBuilder sb = new StringBuilder(); - - if (al.getNumberOfAuthors() > number) { - Author a = al.getAuthor(number); - a.getVon().filter(von -> !von.isEmpty()).ifPresent(von -> sb.append(von).append(' ')); - sb.append(a.getLast().orElse("")); - } - - return sb.toString(); - } - /* end_old */ - - /* begin_old */ - /* to be removed */ - /** - * Take a finished citation and insert a string at the end (but inside the end bracket) - * separated by "PageInfoSeparator" - * - * @param citation - * @param pageInfo - * @return - */ - public String insertPageInfo(String citation, String pageInfo) { - String bracketAfter = getStringCitProperty(BRACKET_AFTER); - if (citation.endsWith(bracketAfter)) { - String first = citation.substring(0, citation.length() - bracketAfter.length()); - return first + getStringCitProperty(PAGE_INFO_SEPARATOR) + pageInfo + bracketAfter; - } else { - return citation + getStringCitProperty(PAGE_INFO_SEPARATOR) + pageInfo; - } - } - /* end_old */ - /** * Convenience method for checking the property for whether we use number citations or * author-year citations. @@ -931,39 +566,6 @@ public int hashCode() { return Objects.hash(path, name, citProperties, properties); } - /* begin_old */ - /* moved to OOBibStyleGetCitationMarker as formatAuthorList */ - private String createAuthorList(String author, int maxAuthors, String andString, - String yearSep) { - Objects.requireNonNull(author); - String etAlString = getStringCitProperty(ET_AL_STRING); // The String to represent authors that are not mentioned, e.g. " et al." - String authorSep = getStringCitProperty(AUTHOR_SEPARATOR); // The String to add between author names except the last two, e.g. ", ". - String oxfordComma = getStringCitProperty(OXFORD_COMMA); // The String to put after the second to last author in case of three or more authors - StringBuilder sb = new StringBuilder(); - AuthorList al = AuthorList.parse(author); - if (!al.isEmpty()) { - sb.append(getAuthorLastName(al, 0)); - } - if ((al.getNumberOfAuthors() > 1) && ((al.getNumberOfAuthors() <= maxAuthors) || (maxAuthors < 0))) { - int j = 1; - while (j < (al.getNumberOfAuthors() - 1)) { - sb.append(authorSep); - sb.append(getAuthorLastName(al, j)); - j++; - } - if (al.getNumberOfAuthors() > 2) { - sb.append(oxfordComma); - } - sb.append(andString); - sb.append(getAuthorLastName(al, al.getNumberOfAuthors() - 1)); - } else if (al.getNumberOfAuthors() > maxAuthors) { - sb.append(etAlString); - } - sb.append(yearSep); - return sb.toString(); - } - /* end_old */ - enum BibStyleMode { NONE, LAYOUT, diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 1e9bbace212..8e48a2486bd 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -1022,7 +1022,6 @@ Problem\ modifying\ citation=Problem modifying citation Problem\ collecting\ citations=Problem collecting citations Citation=Citation Connecting...=Connecting... -Could\ not\ resolve\ BibTeX\ entry\ for\ citation\ marker\ '%0'.=Could not resolve BibTeX entry for citation marker '%0'. Select\ style=Select style Journals=Journals Cite=Cite diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java index 03a0b535e34..d9e52a235ee 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java @@ -144,6 +144,22 @@ static String getCitationMarker2(OOBibStyle style, pageInfo); } + static String getCitationMarker2b(OOBibStyle style, + List entries, + Map entryDBMap, + boolean inParenthesis, + String[] uniquefiers, + Boolean[] isFirstAppearanceOfSource, + String[] pageInfo) { + return OOBibStyleTestHelper.getCitationMarker2b(style, + entries, + entryDBMap, + inParenthesis, + uniquefiers, + isFirstAppearanceOfSource, + pageInfo ); + } + /* * end helpers */ @@ -152,35 +168,16 @@ static String getCitationMarker2(OOBibStyle style, void testGetNumCitationMarker() throws IOException { OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, layoutFormatterPreferences); - assertEquals("[1] ", style.getNumCitationMarker(Arrays.asList(1), -1, true)); assertEquals("[1] ", runGetNumCitationMarker2a(style, Arrays.asList(1), -1, true)); - assertEquals("[1]", style.getNumCitationMarker(Arrays.asList(1), -1, false)); assertEquals("[1]", runGetNumCitationMarker2a(style, Arrays.asList(1), -1, false)); assertEquals("[1]", runGetNumCitationMarker2b(style, -1, numEntry("key", 1, null))); - assertEquals("[1] ", style.getNumCitationMarker(Arrays.asList(1), 0, true)); assertEquals("[1] ", runGetNumCitationMarker2a(style, Arrays.asList(1), 0, true)); - /* - * The following tests as for a numeric label for a - * bibliography entry containing more than one numbers. - * We do not need this, not reproduced. - */ - assertEquals("[1-3] ", style.getNumCitationMarker(Arrays.asList(1, 2, 3), 1, true)); - assertEquals("[1; 2; 3] ", style.getNumCitationMarker(Arrays.asList(1, 2, 3), 5, true)); - assertEquals("[1; 2; 3] ", style.getNumCitationMarker(Arrays.asList(1, 2, 3), -1, true)); - assertEquals("[1; 3; 12] ", style.getNumCitationMarker(Arrays.asList(1, 12, 3), 1, true)); - assertEquals("[3-5; 7; 10-12] ", style.getNumCitationMarker(Arrays.asList(12, 7, 3, 4, 11, 10, 5), 1, true)); - - String citation = style.getNumCitationMarker(Arrays.asList(1), -1, false); - assertEquals("[1; pp. 55-56]", style.insertPageInfo(citation, "pp. 55-56")); - CitationMarkerNumericEntry e2 = numEntry("key", 1, "pp. 55-56"); assertEquals(true, e2.getPageInfo().isPresent()); assertEquals("pp. 55-56", e2.getPageInfo().get().asString()); - citation = runGetNumCitationMarker2b(style, -1, e2); - assertEquals("[1; pp. 55-56]", citation); OOBibStyleTestHelper.testGetNumCitationMarkerExtra(style); } @@ -189,26 +186,6 @@ void testGetNumCitationMarker() throws IOException { void testGetNumCitationMarkerUndefined() throws IOException { OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, layoutFormatterPreferences); - /* - * Testing bibliography labels with multiple numbers again. - * Not reproduced. - */ - assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "; 2-4] ", - style.getNumCitationMarker(Arrays.asList(4, 2, 3, 0), 1, true)); - - assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "] ", - style.getNumCitationMarker(Arrays.asList(0), 1, true)); - - assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "; 1-3] ", - style.getNumCitationMarker(Arrays.asList(1, 2, 3, 0), 1, true)); - - assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "; " + OOBibStyle.UNDEFINED_CITATION_MARKER + "; " - + OOBibStyle.UNDEFINED_CITATION_MARKER + "] ", - style.getNumCitationMarker(Arrays.asList(0, 0, 0), 1, true)); - - /* - * We have these instead: - */ // unresolved citations look like [??key] assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "]", @@ -292,28 +269,22 @@ void testGetCitationMarker() throws IOException { assertEquals(3, style.getMaxAuthors()); assertEquals(-1, style.getMaxAuthorsFirst()); - assertEquals("[Boström et al., 2006]", - style.getCitationMarker(Collections.singletonList(entry), entryDBMap, true, null, null)); assertEquals("[Boström et al., 2006]", getCitationMarker2(style, Collections.singletonList(entry), entryDBMap, true, null, null, null)); - assertEquals("Boström et al. [2006]", - style.getCitationMarker(Collections.singletonList(entry), entryDBMap, false, null, new int[]{3})); assertEquals("Boström et al. [2006]", getCitationMarker2(style, Collections.singletonList(entry), entryDBMap, false, null, new Boolean[]{false}, null)); - assertEquals("[Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006]", - style.getCitationMarker(Collections.singletonList(entry), entryDBMap, true, null, new int[]{5})); assertEquals("[Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006]", getCitationMarker2(style, Collections.singletonList(entry), entryDBMap, true, null, - new Boolean[]{true} /* corresponds to -1, not 5 */, + new Boolean[]{true}, null)); } @@ -399,7 +370,6 @@ void testInstitutionAuthorMarker() throws IOException { database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); - assertEquals("[JabRef Development Team, 2016]", style.getCitationMarker(entries, entryDBMap, true, null, null)); assertEquals("[JabRef Development Team, 2016]", getCitationMarker2(style, @@ -420,10 +390,11 @@ void testVonAuthorMarker() throws IOException { entry.setField(StandardField.AUTHOR, "Alpha von Beta"); entry.setField(StandardField.TITLE, "JabRef Manual"); entry.setField(StandardField.YEAR, "2016"); + entry.setCitationKey("a1"); database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); - assertEquals("[von Beta, 2016]", style.getCitationMarker(entries, entryDBMap, true, null, null)); + assertEquals("[von Beta, 2016]", getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); } @Test @@ -438,10 +409,11 @@ void testNullAuthorMarker() throws IOException { BibEntry entry = new BibEntry(); entry.setType(StandardEntryType.Article); entry.setField(StandardField.YEAR, "2016"); + entry.setCitationKey("a1"); database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); - assertEquals("[, 2016]", style.getCitationMarker(entries, entryDBMap, true, null, null)); + assertEquals("[, 2016]", getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); } @Test @@ -456,10 +428,11 @@ void testNullYearMarker() throws IOException { BibEntry entry = new BibEntry(); entry.setType(StandardEntryType.Article); entry.setField(StandardField.AUTHOR, "Alpha von Beta"); + entry.setCitationKey("a1"); database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); - assertEquals("[von Beta, ]", style.getCitationMarker(entries, entryDBMap, true, null, null)); + assertEquals("[von Beta, ]", getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); } @Test @@ -473,10 +446,11 @@ void testEmptyEntryMarker() throws IOException { BibEntry entry = new BibEntry(); entry.setType(StandardEntryType.Article); + entry.setCitationKey("a1"); database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); - assertEquals("[, ]", style.getCitationMarker(entries, entryDBMap, true, null, null)); + assertEquals("[, ]", getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); } @Test @@ -492,17 +466,20 @@ void testGetCitationMarkerInParenthesisUniquefiers() throws IOException { entry1.setField(StandardField.AUTHOR, "Alpha Beta"); entry1.setField(StandardField.TITLE, "Paper 1"); entry1.setField(StandardField.YEAR, "2000"); + entry1.setCitationKey("a1"); entries.add(entry1); database.insertEntry(entry1); BibEntry entry3 = new BibEntry(); entry3.setField(StandardField.AUTHOR, "Alpha Beta"); entry3.setField(StandardField.TITLE, "Paper 2"); entry3.setField(StandardField.YEAR, "2000"); + entry3.setCitationKey("a3"); entries.add(entry3); database.insertEntry(entry3); BibEntry entry2 = new BibEntry(); entry2.setField(StandardField.AUTHOR, "Gamma Epsilon"); entry2.setField(StandardField.YEAR, "2001"); + entry2.setCitationKey("a2"); entries.add(entry2); database.insertEntry(entry2); for (BibEntry entry : database.getEntries()) { @@ -510,9 +487,12 @@ void testGetCitationMarkerInParenthesisUniquefiers() throws IOException { } assertEquals("[Beta, 2000; Beta, 2000; Epsilon, 2001]", - style.getCitationMarker(entries, entryDBMap, true, null, null)); + getCitationMarker2b(style, entries, entryDBMap, true, null, null, null)); assertEquals("[Beta, 2000a,b; Epsilon, 2001]", - style.getCitationMarker(entries, entryDBMap, true, new String[]{"a", "b", ""}, new int[]{1, 1, 1})); + getCitationMarker2(style, entries, entryDBMap, true, + new String[]{"a", "b", ""}, + new Boolean[]{false, false, false}, + null)); } @Test @@ -528,27 +508,33 @@ void testGetCitationMarkerInTextUniquefiers() throws IOException { entry1.setField(StandardField.AUTHOR, "Alpha Beta"); entry1.setField(StandardField.TITLE, "Paper 1"); entry1.setField(StandardField.YEAR, "2000"); + entry1.setCitationKey("a1"); entries.add(entry1); database.insertEntry(entry1); BibEntry entry3 = new BibEntry(); entry3.setField(StandardField.AUTHOR, "Alpha Beta"); entry3.setField(StandardField.TITLE, "Paper 2"); entry3.setField(StandardField.YEAR, "2000"); + entry3.setCitationKey("a3"); entries.add(entry3); database.insertEntry(entry3); BibEntry entry2 = new BibEntry(); entry2.setField(StandardField.AUTHOR, "Gamma Epsilon"); entry2.setField(StandardField.YEAR, "2001"); entries.add(entry2); + entry2.setCitationKey("a2"); database.insertEntry(entry2); for (BibEntry entry : database.getEntries()) { entryDBMap.put(entry, database); } assertEquals("Beta [2000]; Beta [2000]; Epsilon [2001]", - style.getCitationMarker(entries, entryDBMap, false, null, null)); + getCitationMarker2b(style, entries, entryDBMap, false, null, null, null)); assertEquals("Beta [2000a,b]; Epsilon [2001]", - style.getCitationMarker(entries, entryDBMap, false, new String[]{"a", "b", ""}, new int[]{1, 1, 1})); + getCitationMarker2(style, entries, entryDBMap, false, + new String[]{"a", "b", ""}, + new Boolean[]{false, false, false}, + null)); } @Test @@ -564,18 +550,21 @@ void testGetCitationMarkerInParenthesisUniquefiersThreeSameAuthor() throws IOExc entry1.setField(StandardField.AUTHOR, "Alpha Beta"); entry1.setField(StandardField.TITLE, "Paper 1"); entry1.setField(StandardField.YEAR, "2000"); + entry1.setCitationKey("a1"); entries.add(entry1); database.insertEntry(entry1); BibEntry entry2 = new BibEntry(); entry2.setField(StandardField.AUTHOR, "Alpha Beta"); entry2.setField(StandardField.TITLE, "Paper 2"); entry2.setField(StandardField.YEAR, "2000"); + entry2.setCitationKey("a2"); entries.add(entry2); database.insertEntry(entry2); BibEntry entry3 = new BibEntry(); entry3.setField(StandardField.AUTHOR, "Alpha Beta"); entry3.setField(StandardField.TITLE, "Paper 3"); entry3.setField(StandardField.YEAR, "2000"); + entry3.setCitationKey("a3"); entries.add(entry3); database.insertEntry(entry3); for (BibEntry entry : database.getEntries()) { @@ -583,7 +572,10 @@ void testGetCitationMarkerInParenthesisUniquefiersThreeSameAuthor() throws IOExc } assertEquals("[Beta, 2000a,b,c]", - style.getCitationMarker(entries, entryDBMap, true, new String[]{"a", "b", "c"}, new int[]{1, 1, 1})); + getCitationMarker2(style, entries, entryDBMap, true, + new String[]{"a", "b", "c"}, + new Boolean[]{false, false, false}, + null)); } @Test @@ -599,18 +591,21 @@ void testGetCitationMarkerInTextUniquefiersThreeSameAuthor() throws IOException entry1.setField(StandardField.AUTHOR, "Alpha Beta"); entry1.setField(StandardField.TITLE, "Paper 1"); entry1.setField(StandardField.YEAR, "2000"); + entry1.setCitationKey("a1"); entries.add(entry1); database.insertEntry(entry1); BibEntry entry2 = new BibEntry(); entry2.setField(StandardField.AUTHOR, "Alpha Beta"); entry2.setField(StandardField.TITLE, "Paper 2"); entry2.setField(StandardField.YEAR, "2000"); + entry2.setCitationKey("a2"); entries.add(entry2); database.insertEntry(entry2); BibEntry entry3 = new BibEntry(); entry3.setField(StandardField.AUTHOR, "Alpha Beta"); entry3.setField(StandardField.TITLE, "Paper 3"); entry3.setField(StandardField.YEAR, "2000"); + entry3.setCitationKey("a3"); entries.add(entry3); database.insertEntry(entry3); for (BibEntry entry : database.getEntries()) { @@ -618,7 +613,10 @@ void testGetCitationMarkerInTextUniquefiersThreeSameAuthor() throws IOException } assertEquals("Beta [2000a,b,c]", - style.getCitationMarker(entries, entryDBMap, false, new String[]{"a", "b", "c"}, new int[]{1, 1, 1})); + getCitationMarker2(style, entries, entryDBMap, false, + new String[]{"a", "b", "c"}, + new Boolean[]{false, false, false}, + null)); } @Test @@ -672,11 +670,12 @@ void testEmptyStringPropertyAndOxfordComma() throws Exception { entry.setField(StandardField.AUTHOR, "Alpha von Beta and Gamma Epsilon and Ypsilon Tau"); entry.setField(StandardField.TITLE, "JabRef Manual"); entry.setField(StandardField.YEAR, "2016"); + entry.setCitationKey("a1"); database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); assertEquals("von Beta, Epsilon, & Tau, 2016", - style.getCitationMarker(entries, entryDBMap, true, null, null)); + getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); } @Test diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java index 9fbe9579ccb..8ad6298ca7c 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java @@ -163,13 +163,14 @@ static CitationMarkerEntry makeCitationMarkerEntry(BibEntry entry, * Similar to old API. pageInfo is new, and unlimAuthors is * replaced with isFirstAppearanceOfSource */ - static String getCitationMarker2(OOBibStyle style, - List entries, - Map entryDBMap, - boolean inParenthesis, - String[] uniquefiers, - Boolean[] isFirstAppearanceOfSource, - String[] pageInfo) { + static String getCitationMarker2ab(OOBibStyle style, + List entries, + Map entryDBMap, + boolean inParenthesis, + String[] uniquefiers, + Boolean[] isFirstAppearanceOfSource, + String[] pageInfo, + NonUniqueCitationMarker nonunique) { if (uniquefiers == null) { uniquefiers = new String[entries.size()]; Arrays.fill(uniquefiers, null); @@ -194,7 +195,41 @@ static String getCitationMarker2(OOBibStyle style, } return style.createCitationMarker(citationMarkerEntries, inParenthesis, - NonUniqueCitationMarker.THROWS).asString(); + nonunique).asString(); + } + + static String getCitationMarker2(OOBibStyle style, + List entries, + Map entryDBMap, + boolean inParenthesis, + String[] uniquefiers, + Boolean[] isFirstAppearanceOfSource, + String[] pageInfo) { + return getCitationMarker2ab(style, + entries, + entryDBMap, + inParenthesis, + uniquefiers, + isFirstAppearanceOfSource, + pageInfo, + NonUniqueCitationMarker.THROWS); + } + + static String getCitationMarker2b(OOBibStyle style, + List entries, + Map entryDBMap, + boolean inParenthesis, + String[] uniquefiers, + Boolean[] isFirstAppearanceOfSource, + String[] pageInfo) { + return getCitationMarker2ab(style, + entries, + entryDBMap, + inParenthesis, + uniquefiers, + isFirstAppearanceOfSource, + pageInfo, + NonUniqueCitationMarker.FORGIVEN); } /* From 3dd6d095dd53990d14ecf2fcca3126b685282d40 Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 16:14:14 +0200 Subject: [PATCH 030/103] remove duplicate --- .../logic/openoffice/style/OOBibStyleTest.java | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java index 09a15675734..c66795f6096 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java @@ -157,23 +157,7 @@ static String getCitationMarker2b(OOBibStyle style, inParenthesis, uniquefiers, isFirstAppearanceOfSource, - pageInfo ); - } - - static String getCitationMarker2b(OOBibStyle style, - List entries, - Map entryDBMap, - boolean inParenthesis, - String[] uniquefiers, - Boolean[] isFirstAppearanceOfSource, - String[] pageInfo) { - return OOBibStyleTestHelper.getCitationMarker2b(style, - entries, - entryDBMap, - inParenthesis, - uniquefiers, - isFirstAppearanceOfSource, - pageInfo ); + pageInfo); } /* From e2ddc3510a9491b01074496e6ef0473979c8ceee Mon Sep 17 00:00:00 2001 From: Antal K Date: Sat, 19 Jun 2021 13:45:01 +0200 Subject: [PATCH 031/103] apply oobranch-[DEFGH]-update.patch --- .../org/jabref/gui/openoffice/OOBibBase2.java | 24 +- .../gui/openoffice/OOBibBaseConnect.java | 12 +- .../logic/openoffice/action/EditInsert.java | 17 +- .../logic/openoffice/action/EditMerge.java | 64 ++--- .../logic/openoffice/action/EditSeparate.java | 21 +- .../logic/openoffice/action/ExportCited.java | 2 +- .../logic/openoffice/action/Update.java | 6 +- .../logic/openoffice/backend/Backend52.java | 65 +++-- .../logic/openoffice/backend/Codec52.java | 32 +-- .../logic/openoffice/backend/GetContext.java | 8 +- .../NamedRangeManagerReferenceMark.java | 6 +- .../backend/NamedRangeReferenceMark.java | 164 ++++------- .../logic/openoffice/frontend/OOFrontend.java | 254 +++++++++--------- .../frontend/UpdateBibliography.java | 11 +- .../frontend/UpdateCitationMarkers.java | 4 +- .../logic/openoffice/style/OOBibStyle.java | 16 +- .../style/OOBibStyleGetCitationMarker.java | 12 +- .../style/OOBibStyleGetNumCitationMarker.java | 15 +- .../style/OOFormatBibliography.java | 25 +- .../logic/openoffice/style/OOProcess.java | 6 +- .../model/openoffice/backend/NamedRange.java | 8 +- .../model/openoffice/ootext/OOFormat.java | 59 ++-- .../model/openoffice/ootext/OOText.java | 28 +- .../model/openoffice/ootext/OOTextIntoOO.java | 120 ++++----- .../rangesort/FunctionalTextViewCursor.java | 52 ++-- .../rangesort/RangeOverlapBetween.java | 42 +-- .../rangesort/RangeOverlapWithin.java | 27 +- .../model/openoffice/rangesort/RangeSet.java | 7 +- .../model/openoffice/rangesort/RangeSort.java | 19 +- .../openoffice/rangesort/RangeSortVisual.java | 52 ++-- .../openoffice/rangesort/RangeSortable.java | 6 +- .../model/openoffice/style/Citation.java | 2 +- .../model/openoffice/style/CitationGroup.java | 9 +- .../openoffice/style/CitationGroupId.java | 3 +- .../openoffice/style/CitationGroups.java | 59 ++-- .../style/CitationLookupResult.java | 3 +- .../openoffice/style/CitationMarkerEntry.java | 10 +- .../style/CitationMarkerNormEntry.java | 7 +- .../model/openoffice/style/CitationPath.java | 4 +- .../model/openoffice/style/CitedKey.java | 11 +- .../openoffice/style/CompareCitation.java | 4 +- .../openoffice/style/CompareCitedKey.java | 4 +- .../style/NonUniqueCitationMarker.java | 6 +- .../model/openoffice/style/OODataModel.java | 12 +- .../model/openoffice/style/PageInfo.java | 2 +- .../model/openoffice/uno/UnoBookmark.java | 34 +-- .../jabref/model/openoffice/uno/UnoCast.java | 11 +- .../model/openoffice/uno/UnoCrossRef.java | 56 ++-- .../model/openoffice/uno/UnoCursor.java | 4 +- .../model/openoffice/uno/UnoNameAccess.java | 5 +- .../jabref/model/openoffice/uno/UnoNamed.java | 40 ++- .../model/openoffice/uno/UnoProperties.java | 2 +- .../model/openoffice/uno/UnoRedlines.java | 23 +- .../openoffice/uno/UnoReferenceMark.java | 50 ++-- .../model/openoffice/uno/UnoSelection.java | 16 +- .../jabref/model/openoffice/uno/UnoStyle.java | 19 +- .../model/openoffice/uno/UnoTextDocument.java | 11 +- .../model/openoffice/uno/UnoTextRange.java | 18 +- .../model/openoffice/uno/UnoTextSection.java | 26 +- .../jabref/model/openoffice/uno/UnoUndo.java | 11 +- .../uno/UnoUserDefinedProperty.java | 58 ++-- .../model/openoffice/util/OOResult.java | 29 +- .../model/openoffice/util/OOTuple3.java | 11 + .../openoffice/style/OOBibStyleTest.java | 22 +- .../style/OOBibStyleTestHelper.java | 16 +- 65 files changed, 805 insertions(+), 977 deletions(-) diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java index ca8324cda2a..f196bae6bc4 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java @@ -164,7 +164,7 @@ void showDialog(String title, OOError ex) { OOVoidResult collectResults(String title, List> results) { String msg = (results.stream() - .filter(e -> e.isError()) + .filter(OOVoidResult::isError) .map(e -> e.getError().getLocalizedMessage()) .collect(Collectors.joining("\n\n"))); if (msg.isEmpty()) { @@ -322,7 +322,7 @@ private static OOVoidResult checkIfOpenOfficeIsRecordingChanges(XTextDo } return OOVoidResult.error(new OOError(title, msg)); } - } catch (UnknownPropertyException | WrappedTargetException ex) { + } catch (WrappedTargetException ex) { String msg = Localization.lang("Error while checking if Writer" + " is recording changes or has recorded changes."); return OOVoidResult.error(new OOError(title, msg, ex)); @@ -372,10 +372,10 @@ OOVoidResult selectedBibEntryIsRequired(List entries, * Checks existence and also checks if it is not an internal name. */ private OOVoidResult checkStyleExistsInTheDocument(String familyName, - String styleName, - XTextDocument doc, - String labelInJstyleFile, - String pathToStyleFile) + String styleName, + XTextDocument doc, + String labelInJstyleFile, + String pathToStyleFile) throws NoSuchElementException, WrappedTargetException { @@ -394,9 +394,9 @@ private OOVoidResult checkStyleExistsInTheDocument(String familyName, labelInJstyleFile, styleName); default -> - throw new RuntimeException("Expected " + UnoStyle.CHARACTER_STYLES - + " or " + UnoStyle.PARAGRAPH_STYLES - + " for familyName"); + throw new IllegalArgumentException("Expected " + UnoStyle.CHARACTER_STYLES + + " or " + UnoStyle.PARAGRAPH_STYLES + + " for familyName"); } + "\n" + Localization.lang("Please create it in the document or change in the file:") @@ -419,9 +419,9 @@ private OOVoidResult checkStyleExistsInTheDocument(String familyName, styleName, internalName.get()); default -> - throw new RuntimeException("Expected " + UnoStyle.CHARACTER_STYLES - + " or " + UnoStyle.PARAGRAPH_STYLES - + " for familyName"); + throw new IllegalArgumentException("Expected " + UnoStyle.CHARACTER_STYLES + + " or " + UnoStyle.PARAGRAPH_STYLES + + " for familyName"); } + "\n" + Localization.lang("Please use the latter in the style file below" diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java b/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java index 03765f8ffd8..c9f6246062b 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java @@ -72,10 +72,10 @@ private XDesktop simpleBootstrap(Path loPath) Object desktop; try { desktop = sem.createInstanceWithContext("com.sun.star.frame.Desktop", context); - } catch (Exception e) { + } catch (com.sun.star.uno.Exception e) { throw new CreationException(e.getMessage()); } - return UnoCast.unoQI(XDesktop.class, desktop); + return UnoCast.cast(XDesktop.class, desktop).get(); } private static List getTextDocuments(XDesktop desktop) @@ -90,10 +90,10 @@ private static List getTextDocuments(XDesktop desktop) while (compEnum.hasMoreElements()) { Object next = compEnum.nextElement(); - XComponent comp = UnoCast.unoQI(XComponent.class, next); - XTextDocument doc = UnoCast.unoQI(XTextDocument.class, comp); - if (doc != null) { - result.add(doc); + XComponent comp = UnoCast.cast(XComponent.class, next).get(); + Optional doc = UnoCast.cast(XTextDocument.class, comp); + if (doc.isPresent()) { + result.add(doc.get()); } } return result; diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java index 277b92bec76..1345f1f2a99 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java @@ -43,28 +43,21 @@ public class EditInsert { * * In the document we store citations by their citation key. * - * If the citation key is missing, the best we can do is to notify - * the user. Or the programmer, that we cannot accept such input. + * If the citation key is missing, the best we can do is to notify the user. Or the programmer, + * that we cannot accept such input. * */ private static String insertEntryGetCitationKey(BibEntry entry) { Optional key = entry.getCitationKey(); if (key.isEmpty()) { - throw new RuntimeException("insertEntryGetCitationKey:" - + " cannot cite entries without citation key"); + throw new IllegalArgumentException("insertEntryGetCitationKey: cannot cite entries without citation key"); } return key.get(); } - /* + /** * @param cursor Where to insert. - * - * @param sync If not empty, update citation markers and, - * depending on the embedded options, the - * bibliography. - * - * @param fcursor If sync.isPresent(), it must provide a - * FunctionalTextViewCursor. Otherwise not used. + * @param pageInfo A single pageInfo for a list of entries. This is what we get from the GUI. */ public static void insertCitationGroup(XTextDocument doc, OOFrontend fr, diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java index 823610c51cf..4cd225eb1a8 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java @@ -107,14 +107,10 @@ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend fr, OOBi } private static class JoinableGroupData { - /* - * A list of consecutive citation groups only separated by spaces. - */ + /** A list of consecutive citation groups only separated by spaces. */ List group; - /* - * A cursor covering the XTextRange of each entry in group - * (and the spaces between them) - */ + + /** A cursor covering the XTextRange of each entry in group (and the spaces between them) */ XTextCursor groupCursor; JoinableGroupData(List group, XTextCursor groupCursor) { @@ -128,21 +124,21 @@ private static class ScanState { // Citation groups in the current group List currentGroup; - // A cursor that covers the Citation groups in currentGroup, - // including the space between them. - // Null if currentGroup.isEmpty() + // A cursor that covers the Citation groups in currentGroup, including the space between + // them. + // null if currentGroup.isEmpty() XTextCursor currentGroupCursor; // A cursor starting at the end of the last CitationGroup in - // currentGroup. Null if currentGroup.isEmpty() + // currentGroup. null if currentGroup.isEmpty() XTextCursor cursorBetween; // The last element of currentGroup. - // Null if currentGroup.isEmpty() + // null if currentGroup.isEmpty() CitationGroup prev; // The XTextRange for prev. - // Null if currentGroup.isEmpty() + // null if currentGroup.isEmpty() XTextRange prevRange; ScanState() { @@ -164,9 +160,8 @@ void reset() { * @param cg The CitationGroup to test * @param currentRange The XTextRange corresponding to cg. * - * @return false if cannot add, true if can. If returned true, - * then state.cursorBetween and state.currentGroupCursor are - * expanded to end at the start of currentRange. + * @return false if cannot add, true if can. If returned true, then state.cursorBetween and + * state.currentGroupCursor are expanded to end at the start of currentRange. */ private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextRange currentRange) { @@ -186,8 +181,7 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextR if (state.prev != null) { - // Even if we combine AUTHORYEAR_INTEXT citations, we - // would not mix them with AUTHORYEAR_PAR + // Even if we combine AUTHORYEAR_INTEXT citations, we would not mix them with AUTHORYEAR_PAR if (cg.citationType != state.prev.citationType) { return false; } @@ -196,8 +190,7 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextR return false; } - // Sanity check: the current range should start later than - // the previous. + // Sanity check: the current range should start later than the previous. int textOrder = UnoTextRange.compareStarts(state.prevRange, currentRange); if (textOrder != (-1)) { String msg = @@ -208,8 +201,7 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextR currentRange.getString(), ((textOrder == 0) ? "they start at the same position" - : ("the start of the latter precedes" - + " the start of the first"))); + : "the start of the latter precedes the start of the first")); LOGGER.warn(msg); return false; } @@ -224,14 +216,13 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextR // assume: currentGroupCursor.getEnd() == cursorBetween.getEnd() if (UnoTextRange.compareEnds(state.cursorBetween, state.currentGroupCursor) != 0) { - String msg = ("MergeCitationGroups:" - + " cursorBetween.end != currentGroupCursor.end"); - throw new RuntimeException(msg); + String msg = ("MergeCitationGroups: cursorBetween.end != currentGroupCursor.end"); + throw new IllegalStateException(msg); } /* - * Try to expand state.currentGroupCursor and state.cursorBetween by going right - * to reach rangeStart. + * Try to expand state.currentGroupCursor and state.cursorBetween by going right to reach + * rangeStart. */ XTextRange rangeStart = currentRange.getStart(); boolean couldExpand = true; @@ -257,12 +248,10 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextR // These two should move in sync: if (UnoTextRange.compareEnds(state.cursorBetween, state.currentGroupCursor) != 0) { - String msg = ("MergeCitationGroups:" - + " cursorBetween.end != currentGroupCursor.end" - + " (during expand)"); - throw new RuntimeException(msg); + String msg = ("MergeCitationGroups: cursorBetween.end != currentGroupCursor.end (during expand)"); + throw new IllegalStateException(msg); } - } // while + } if (!couldExpand) { return false; @@ -304,7 +293,7 @@ private static void addToCurrentGroup(ScanState state, CitationGroup cg, XTextRa if (UnoTextRange.compareEnds(state.cursorBetween, state.currentGroupCursor) != 0) { String msg = ("MergeCitationGroups: cursorBetween.end != currentGroupCursor.end"); - throw new RuntimeException(msg); + throw new IllegalStateException(msg); } /* Store data about last entry in currentGroup */ @@ -321,9 +310,7 @@ private static List scan(XTextDocument doc, OOFrontend fr) WrappedTargetException { List result = new ArrayList<>(); - List cgs = - fr.getCitationGroupsSortedWithinPartitions(doc, - false /* mapFootnotesToFootnoteMarks */); + List cgs = fr.getCitationGroupsSortedWithinPartitions(doc, false /* mapFootnotesToFootnoteMarks */); if (cgs.isEmpty()) { return result; } @@ -333,7 +320,7 @@ private static List scan(XTextDocument doc, OOFrontend fr) for (CitationGroup cg : cgs) { XTextRange currentRange = (fr.getMarkRange(doc, cg) - .orElseThrow(RuntimeException::new)); + .orElseThrow(IllegalStateException::new)); /* * Decide if we add cg to the group. False when the group is empty. @@ -341,8 +328,7 @@ private static List scan(XTextDocument doc, OOFrontend fr) boolean addToGroup = checkAddToGroup(state, cg, currentRange); /* - * Even if we do not add it to an existing group, - * we might use it to start a new group. + * Even if we do not add it to an existing group, we might use it to start a new group. * * Can it start a new group? */ diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java index 31c23ed52d0..0293159d34f 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java @@ -65,7 +65,7 @@ public static boolean separateCitations(XTextDocument doc, XTextRange range1 = (fr .getMarkRange(doc, cg) - .orElseThrow(RuntimeException::new)); + .orElseThrow(IllegalStateException::new)); XTextCursor textCursor = range1.getText().createTextCursorByRange(range1); List cits = cg.citationsInStorageOrder; @@ -82,16 +82,15 @@ public static boolean separateCitations(XTextDocument doc, boolean insertSpaceAfter = (i != last); Citation cit = cits.get(i); - UpdateCitationMarkers.createAndFillCitationGroup( - fr, - doc, - List.of(cit.citationKey), - List.of(cit.getPageInfo()), - cg.citationType, - OOText.fromString(cit.citationKey), - textCursor, - style, - insertSpaceAfter); + UpdateCitationMarkers.createAndFillCitationGroup(fr, + doc, + List.of(cit.citationKey), + List.of(cit.getPageInfo()), + cg.citationType, + OOText.fromString(cit.citationKey), + textCursor, + style, + insertSpaceAfter); textCursor.collapseToEnd(); } diff --git a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java index 8d344688c68..ef7985d666a 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java +++ b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java @@ -41,7 +41,7 @@ public static class GenerateDatabaseResult { * If a key is not found, it is added to result.unresolvedKeys * * Cross references (in StandardField.CROSSREF) are followed (not recursively): - * if the referenced entry is found, it is included in the result. + * If the referenced entry is found, it is included in the result. * If it is not found, it is silently ignored. */ public static GenerateDatabaseResult generateDatabase(XTextDocument doc, List databases) diff --git a/src/main/java/org/jabref/logic/openoffice/action/Update.java b/src/main/java/org/jabref/logic/openoffice/action/Update.java index 151e4b6575b..675afb2a79f 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/Update.java +++ b/src/main/java/org/jabref/logic/openoffice/action/Update.java @@ -20,13 +20,13 @@ import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextDocument; -/* +/** * Update document: citation marks and bibliography */ public class Update { - /* - * @return unresolvedKeys + /** + * @return the list of unresolved citation keys */ private static List updateDocument(XTextDocument doc, OOFrontend fr, diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java index d7c1b62086a..cf91ad1043e 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java @@ -67,8 +67,8 @@ public List getJabRefReferenceMarkNames(XTextDocument doc) } /** - * Names of custom properties belonging to us, but without a - * corresponding reference mark. These can be deleted. + * Names of custom properties belonging to us, but without a corresponding reference mark. + * These can be deleted. * * @param citationGroupNames These are the names that are used. * @@ -178,16 +178,14 @@ public CitationGroup readCitationGroupFromDocumentOrThrow(XTextDocument doc, Str } /** - * Create a reference mark with the given name, at the - * end of position. + * Create a reference mark with the given name, at the end of position. * - * On return {@code position} is collapsed, and is after the - * inserted space, or at the end of the reference mark. + * On return {@code position} is collapsed, and is after the inserted space, or at the end of + * the reference mark. * * @param position Collapsed to its end. - * @param insertSpaceAfter We insert a space after the mark, that - * carries on format of characters from - * the original position. + * @param insertSpaceAfter We insert a space after the mark, that carries on format of + * characters from the original position. */ public CitationGroup createCitationGroup(XTextDocument doc, List citationKeys, @@ -206,7 +204,7 @@ public CitationGroup createCitationGroup(XTextDocument doc, Objects.requireNonNull(pageInfos); if (pageInfos.size() != citationKeys.size()) { - throw new RuntimeException("pageInfos.size != citationKeys.size"); + throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); } // Get a new refMarkName @@ -237,7 +235,7 @@ public CitationGroup createCitationGroup(XTextDocument doc, } } break; - case JabRef53: + case JabRef60: cit.setPageInfo(pageInfo); break; } @@ -257,7 +255,7 @@ public CitationGroup createCitationGroup(XTextDocument doc, if (pageInfo.isPresent()) { String pageInfoString = OOText.toString(pageInfo.get()); - UnoUserDefinedProperty.createStringProperty(doc, refMarkName, pageInfoString); + UnoUserDefinedProperty.setStringProperty(doc, refMarkName, pageInfoString); } else { // do not inherit from trash UnoUserDefinedProperty.removeIfExists(doc, refMarkName); @@ -269,16 +267,15 @@ public CitationGroup createCitationGroup(XTextDocument doc, this.cgidToNamedRange.put(cgid, namedRange); return cg; default: - throw new RuntimeException("Backend52 requires JabRef52 dataModel"); + throw new IllegalStateException("Backend52 requires JabRef52 dataModel"); } } /** - * @return A list with a nullable pageInfo entry for each citation in - * joinableGroups. + * @return A list with a nullable pageInfo entry for each citation in joinableGroups. * - * TODO: JabRef52 combinePageInfos is not reversible. Should warn - * user to check the result. Or ask what to do. + * TODO: JabRef52 combinePageInfos is not reversible. Should warn user to check the result. Or + * ask what to do. */ public static List> combinePageInfosCommon(OODataModel dataModel, List joinableGroup) { @@ -296,20 +293,20 @@ public CitationGroup createCitationGroup(XTextDocument doc, .collect(Collectors.joining("; "))); int nCitations = (joinableGroup.stream() - .map(cg -> cg.numberOfCitations()) + .map(CitationGroup::numberOfCitations) .mapToInt(Integer::intValue).sum()); if ("".equals(cgPageInfo)) { cgPageInfo = null; } return OODataModel.fakePageInfos(cgPageInfo, nCitations); - case JabRef53: + case JabRef60: return (joinableGroup.stream() .flatMap(cg -> (cg.citationsInStorageOrder.stream() .map(Citation::getPageInfo))) .collect(Collectors.toList())); default: - throw new RuntimeException("unhandled dataModel here"); + throw new IllegalArgumentException("unhandled dataModel here"); } } @@ -323,8 +320,8 @@ public List> combinePageInfos(List joinableGroup private NamedRange getNamedRangeOrThrow(CitationGroup cg) { NamedRange namedRange = this.cgidToNamedRange.get(cg.cgid); if (namedRange == null) { - LOGGER.warn("getNamedRange: could not lookup namedRange"); - throw new RuntimeException("getNamedRange: could not lookup namedRange"); + String msg = "getNamedRange: could not lookup namedRange"; + throw new IllegalStateException("getNamedRange: could not lookup namedRange"); } return namedRange; } @@ -346,9 +343,7 @@ public void removeCitationGroup(CitationGroup cg, XTextDocument doc) } /** - * * @return Optional.empty if the reference mark is missing. - * */ public Optional getMarkRange(CitationGroup cg, XTextDocument doc) throws @@ -360,8 +355,8 @@ public Optional getMarkRange(CitationGroup cg, XTextDocument doc) } /** - * Cursor for the reference marks as is, not prepared for filling, - * but does not need cleanFillCursorForCitationGroup either. + * Cursor for the reference marks as is: not prepared for filling, but does not need + * cleanFillCursorForCitationGroup either. */ public Optional getRawCursorForCitationGroup(CitationGroup cg, XTextDocument doc) throws @@ -403,14 +398,14 @@ public List getCitationEntries(XTextDocument doc, CitationGroups switch (dataModel) { case JabRef52: // One context per CitationGroup: Backend52 (DataModel.JabRef52) - // For DataModel.JabRef53 (Backend53) we need one context per Citation + // For DataModel.JabRef60 (Backend60) we need one context per Citation int n = cgs.numberOfCitationGroups(); List citations = new ArrayList<>(n); for (CitationGroup cg : cgs.getCitationGroupsUnordered()) { String name = cg.cgid.citationGroupIdAsString(); XTextCursor cursor = (this .getRawCursorForCitationGroup(cg, doc) - .orElseThrow(RuntimeException::new)); + .orElseThrow(IllegalStateException::new)); String context = GetContext.getCursorStringWithContext(cursor, 30, 30, true); Optional pageInfo = (cg.numberOfCitations() > 0 ? (getPageInfoFromData(cg) @@ -420,11 +415,11 @@ public List getCitationEntries(XTextDocument doc, CitationGroups citations.add(entry); } return citations; - case JabRef53: + case JabRef60: // xx - throw new RuntimeException("getCitationEntries for JabRef53 is not implemented yet"); + throw new IllegalStateException("getCitationEntries for JabRef60 is not implemented yet"); default: - throw new RuntimeException("getCitationEntries: unhandled dataModel "); + throw new IllegalStateException("getCitationEntries: unhandled dataModel "); } } @@ -449,15 +444,15 @@ public void applyCitationEntries(XTextDocument doc, List citation pageInfo = PageInfo.normalizePageInfo(pageInfo); if (pageInfo.isPresent()) { String name = entry.getRefMarkName(); - UnoUserDefinedProperty.createStringProperty(doc, name, pageInfo.get().asString()); + UnoUserDefinedProperty.setStringProperty(doc, name, pageInfo.get().toString()); } } break; - case JabRef53: + case JabRef60: // xx - throw new RuntimeException("applyCitationEntries for JabRef53 is not implemented yet"); + throw new IllegalStateException("applyCitationEntries for JabRef60 is not implemented yet"); default: - throw new RuntimeException("applyCitationEntries: unhandled dataModel "); + throw new IllegalStateException("applyCitationEntries: unhandled dataModel "); } } diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java index 352df27cdeb..e4405dc6115 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java @@ -16,7 +16,6 @@ * How and what is encoded in a mark names. * * - pageInfo does not appear here. It is not encoded in the mark name. - * - Does not depend on the type of marks (reference mark of bookmark) used. */ class Codec52 { private static final String BIB_CITATION = "JR_cite"; @@ -27,7 +26,6 @@ class Codec52 { /** * This is what we get back from parsing a refMarkName. - * */ public static class ParsedMarkName { /** "", "0", "1" ... */ @@ -46,9 +44,8 @@ public static class ParsedMarkName { } } - /* - * Integer representation was written into the document in - * JabRef52, keep it for compatibility. + /** + * Integer representation was written into the document in JabRef52, keep it for compatibility. */ public static CitationType CitationTypeFromInt(int i) { switch (i) { @@ -59,7 +56,7 @@ public static CitationType CitationTypeFromInt(int i) { case 3: return CitationType.INVISIBLE_CIT; default: - throw new RuntimeException("Invalid CitationType code"); + throw new IllegalArgumentException("Invalid CitationType code"); } } @@ -72,21 +69,18 @@ public static int CitationTypeToInt(CitationType i) { case INVISIBLE_CIT: return 3; default: - throw new RuntimeException("Invalid CitationType"); + throw new IllegalArgumentException("Invalid CitationType"); } } /** - * Produce a reference mark name for JabRef for the given citation - * key and citationType that does not yet appear among the reference - * marks of the document. + * Produce a reference mark name for JabRef for the given citation key and citationType that + * does not yet appear among the reference marks of the document. * * @param bibtexKey The citation key. - * @param citationType Encodes the effect of withText and - * inParenthesis options. + * @param citationType Encodes the effect of withText and inParenthesis options. * - * The first occurrence of bibtexKey gets no serial number, the - * second gets 0, the third 1 ... + * The first occurrence of bibtexKey gets no serial number, the second gets 0, the third 1 ... * * Or the first unused in this series, after removals. */ @@ -97,10 +91,10 @@ public static String getUniqueMarkName(Set usedNames, NoDocumentException { int i = 0; - int j = CitationTypeToInt(citationType); - String name = BIB_CITATION + '_' + j + '_' + bibtexKey; + int citTypeCode = CitationTypeToInt(citationType); + String name = BIB_CITATION + '_' + citTypeCode + '_' + bibtexKey; while (usedNames.contains(name)) { - name = BIB_CITATION + i + '_' + j + '_' + bibtexKey; + name = BIB_CITATION + i + '_' + citTypeCode + '_' + bibtexKey; i++; } return name; @@ -121,8 +115,8 @@ public static Optional parseMarkName(String refMarkName) { List keys = Arrays.asList(citeMatcher.group(3).split(",")); String i = citeMatcher.group(1); - int j = Integer.parseInt(citeMatcher.group(2)); - CitationType citationType = CitationTypeFromInt(j); + int citTypeCode = Integer.parseInt(citeMatcher.group(2)); + CitationType citationType = CitationTypeFromInt(citTypeCode); return (Optional.of(new Codec52.ParsedMarkName(i, citationType, keys))); } diff --git a/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java b/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java index 468d630e756..4cde12ad236 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java @@ -27,8 +27,8 @@ private GetContext() { * @param cursor * @param charBefore Number of characters requested. * @param charAfter Number of characters requested. - * @param htmlMarkup If true, the text belonging to the - * reference mark is surrounded by bold html tag. + * @param htmlMarkup If true, the text belonging to the reference mark is surrounded by bold + * html tag. * */ public static String getCursorStringWithContext(XTextCursor cursor, @@ -46,8 +46,8 @@ public static String getCursorStringWithContext(XTextCursor cursor, for (int i = 0; i < charBefore; i++) { try { cursor.goLeft((short) 1, true); - // If we are close to charBefore and see a space, - // then cut here. Might avoid cutting a word in half. + // If we are close to charBefore and see a space, then cut here. Might avoid cutting + // a word in half. if ((i >= (charBefore - flex)) && Character.isWhitespace(cursor.getString().charAt(0))) { break; diff --git a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java index 157dd87cf0c..d82ad08378e 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java @@ -23,11 +23,7 @@ public NamedRange nrmCreate(XTextDocument doc, boolean withoutBrackets) throws CreationException { - return NamedRangeReferenceMark.create(doc, - refMarkName, - position, - insertSpaceAfter, - withoutBrackets); + return NamedRangeReferenceMark.create(doc, refMarkName, position, insertSpaceAfter, withoutBrackets); } @Override 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 38ac716d9ac..63d5f917fc5 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java @@ -47,11 +47,11 @@ String getId() { } /** - * Insert {@code n} spaces in a way that reference - * marks just before or just after the cursor are not affected. + * Insert {@code n} spaces in a way that reference marks just before or just after the cursor + * are not affected. * - * This is based on the observation, that starting two - * new paragraphs separates us from a reference mark on either side. + * This is based on the observation, that starting two new paragraphs separates us from + * reference marks on either side. * * The pattern used is: * {@code safeInsertSpaces(n): para, para, left, space(n), right-delete, left(n), left-delete} @@ -61,8 +61,6 @@ String getId() { * * @return a new cursor, covering the just-inserted spaces. * - * This could be generalized to insert arbitrary text safely - * between two reference marks. But we do not need that now. */ private static XTextCursor safeInsertSpacesBetweenReferenceMarks(XTextRange position, int n) { // Start with an empty cursor at position.getStart(); @@ -129,19 +127,14 @@ static NamedRangeReferenceMark create(XTextDocument doc, throws CreationException { - createReprInDocument(doc, - refMarkName, - position, - insertSpaceAfter, - withoutBrackets); + createReprInDocument(doc, refMarkName, position, insertSpaceAfter, withoutBrackets); return new NamedRangeReferenceMark(refMarkName); } /** * @return Optional.empty if there is no corresponding range. */ - static Optional getFromDocument(XTextDocument doc, - String refMarkName) + static Optional getFromDocument(XTextDocument doc, String refMarkName) throws NoDocumentException, WrappedTargetException { @@ -160,7 +153,7 @@ public void nrRemoveFromDocument(XTextDocument doc) WrappedTargetException, NoDocumentException, NoSuchElementException { - UnoReferenceMark.remove(doc, this.nrGetRangeName()); + UnoReferenceMark.removeIfExists(doc, this.nrGetRangeName()); } @Override @@ -185,11 +178,11 @@ public Optional nrGetMarkRange(XTextDocument doc) } /** - * Cursor for the reference marks as is, not prepared for filling, - * but does not need nrCleanFillCursor either. + * Cursor for the reference marks as is, not prepared for filling, but does not need + * nrCleanFillCursor either. * * @return Optional.empty() if reference mark is missing from the document, - * otherwise an XTextCursor for getMarkRange + * otherwise an XTextCursor for getMarkRange * * See: getRawCursorForCitationGroup */ @@ -230,11 +223,11 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) String name = this.nrGetRangeName(); - final boolean debugThisFun = false; final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; final short leftLength = (short) left.length(); final short rightLength = (short) right.length(); + final boolean debugThisFun = false; XTextCursor full = null; String fullText = null; @@ -242,86 +235,62 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) Optional markAsTextContent = UnoReferenceMark.getAsTextContent(doc, name); if (markAsTextContent.isEmpty()) { - String msg = String.format("nrGetFillCursor:" - + " markAsTextContent(%s).isEmpty (attempt %d)", - name, - i); - throw new RuntimeException(msg); + String msg = String.format("nrGetFillCursor: markAsTextContent(%s).isEmpty (attempt %d)", name, i); + throw new IllegalStateException(msg); } full = UnoCursor.getTextCursorOfTextContentAnchor(markAsTextContent.get()).orElse(null); if (full == null) { String msg = String.format("nrGetFillCursor: full == null (attempt %d)", i); - throw new RuntimeException(msg); + throw new IllegalStateException(msg); } fullText = full.getString(); - if (debugThisFun) { - System.out.printf("nrGetFillCursor: fulltext = '%s'%n", fullText); - } + LOGGER.debug("nrGetFillCursor: fulltext = '{}'", fullText); if (fullText.length() >= 2) { - if (debugThisFun) { - System.out.printf("nrGetFillCursor: (attempt: %d) fulltext.length() >= 2," - + " break loop%n", i); - } + LOGGER.debug("nrGetFillCursor: (attempt: {}) fulltext.length() >= 2, break loop%n", i); break; } else { // (fullText.length() < 2) if (i == 2) { - String msg = String.format("nrGetFillCursor:" - + " (fullText.length() < 2) (attempt %d)", - i); - throw new RuntimeException(msg); + String msg = String.format("nrGetFillCursor: (fullText.length() < 2) (attempt %d)", i); + throw new IllegalStateException(msg); } // too short, recreate - if (true || debugThisFun) { - System.out.println("nrGetFillCursor: too short, recreate"); - } + LOGGER.warn("nrGetFillCursor: too short, recreate"); + full.setString(""); - try { - UnoReferenceMark.remove(doc, name); - } catch (NoSuchElementException ex) { - String msg = String.format("nrGetFillCursor got NoSuchElementException" - + " for '%s'", - name); - LOGGER.warn(msg); - } - createReprInDocument(doc, - name, - full, - false, /* insertSpaceAfter */ - false /* withoutBrackets */); + UnoReferenceMark.removeIfExists(doc, name); + + final boolean insertSpaceAfter = false; + final boolean withoutBrackets = false; + createReprInDocument(doc, name, full, insertSpaceAfter, withoutBrackets); } } if (full == null) { - throw new RuntimeException("nrGetFillCursorFor: full == null (after loop)"); + throw new IllegalStateException("nrGetFillCursorFor: full == null (after loop)"); } if (fullText == null) { - throw new RuntimeException("nrGetFillCursor: fullText == null (after loop)"); + throw new IllegalStateException("nrGetFillCursor: fullText == null (after loop)"); } fullText = full.getString(); if (fullText.length() < 2) { - throw new RuntimeException("nrGetFillCursor: fullText.length() < 2 (after loop)'%n"); + throw new IllegalStateException("nrGetFillCursor: fullText.length() < 2 (after loop)'%n"); } XTextCursor beta = full.getText().createTextCursorByRange(full); beta.collapseToStart(); beta.goRight((short) 1, false); beta.goRight((short) (fullText.length() - 2), true); - if (debugThisFun) { - System.out.printf("nrGetFillCursor: beta(1) covers '%s'%n", beta.getString()); - } + LOGGER.debug("nrGetFillCursor: beta(1) covers '{}'", beta.getString()); + if (fullText.startsWith(left) && fullText.endsWith(right)) { beta.setString(""); } else { - if (debugThisFun) { - String msg = String.format("nrGetFillCursor: recreating brackets for '%s'", fullText); - // LOGGER.warn(msg); - System.out.println(msg); - } + LOGGER.debug("nrGetFillCursor: recreating brackets for '{}'", fullText); // we have at least two characters inside XTextCursor alpha = full.getText().createTextCursorByRange(full); @@ -336,47 +305,40 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) String paddingy = "y"; String paddingz = "z"; beta.setString(paddingx + left + paddingy + right + paddingz); - if (debugThisFun) { - System.out.printf("nrGetFillCursor: beta(2) covers '%s'%n", beta.getString()); - } + LOGGER.debug("nrGetFillCursor: beta(2) covers '{}'", beta.getString()); + // move beta to before the right bracket beta.collapseToEnd(); beta.goLeft((short) (rightLength + 1), false); // remove middle padding beta.goLeft((short) 1, true); - if (debugThisFun) { - System.out.printf("nrGetFillCursor: beta(3) covers '%s'%n", beta.getString()); - } + LOGGER.debug("nrGetFillCursor: beta(3) covers '{}'", beta.getString()); + // only drop paddingy later: beta.setString(""); // drop the initial character and paddingx alpha.collapseToStart(); alpha.goRight((short) (1 + 1), true); - if (debugThisFun) { - System.out.printf("nrGetFillCursor: alpha(4) covers '%s'%n", alpha.getString()); - } + LOGGER.debug("nrGetFillCursor: alpha(4) covers '{}'", alpha.getString()); + alpha.setString(""); // drop the last character and paddingz omega.collapseToEnd(); omega.goLeft((short) (1 + 1), true); - if (debugThisFun) { - System.out.printf("nrGetFillCursor: omega(5) covers '%s'%n", omega.getString()); - } + LOGGER.debug("nrGetFillCursor: omega(5) covers '{}'", omega.getString()); + omega.setString(""); // drop paddingy now - if (debugThisFun) { - System.out.printf("nrGetFillCursor: beta(6) covers '%s'%n", beta.getString()); - } + LOGGER.debug("nrGetFillCursor: beta(6) covers '{}'", beta.getString()); + beta.setString(""); // should be OK now. if (debugThisFun) { alpha.goRight(leftLength, true); - System.out.printf("nrGetFillCursor: alpha(7) covers '%s', should be '%s'%n", - alpha.getString(), left); + LOGGER.debug("nrGetFillCursor: alpha(7) covers '{}', should be '{}'", alpha.getString(), left); omega.goLeft(rightLength, true); - System.out.printf("nrGetFillCursor: omega(8) covers '%s', should be '%s'%n", - omega.getString(), right); + LOGGER.debug("nrGetFillCursor: omega(8) covers '%s', should be '%s'%n", omega.getString(), right); } } @@ -385,7 +347,7 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) } /* - * Throw RuntimeException if the brackets are not there. + * Throw IllegalStateException if the brackets are not there. */ public static void checkFillCursor(XTextCursor cursor) { final String left = REFERENCE_MARK_LEFT_BRACKET; @@ -403,10 +365,9 @@ public static void checkFillCursor(XTextCursor cursor) { alpha.goLeft(leftLength, true); if (!left.equals(alpha.getString())) { String msg = String.format("checkFillCursor:" - + " ('%s') is not prefixed with" - + " REFERENCE_MARK_LEFT_BRACKET, has '%s'", + + " ('%s') is not prefixed with REFERENCE_MARK_LEFT_BRACKET, has '%s'", cursor.getString(), alpha.getString()); - throw new RuntimeException(msg); + throw new IllegalStateException(msg); } } @@ -414,17 +375,16 @@ public static void checkFillCursor(XTextCursor cursor) { omega.goRight(rightLength, true); if (!right.equals(omega.getString())) { String msg = String.format("checkFillCursor:" - + " ('%s') is not followed by" - + " REFERENCE_MARK_RIGHT_BRACKET, has '%s'", + + " ('%s') is not followed by REFERENCE_MARK_RIGHT_BRACKET, has '%s'", cursor.getString(), omega.getString()); - throw new RuntimeException(msg); + throw new IllegalStateException(msg); } } } /** - * Remove brackets, but if the result would become empty, leave - * them; if the result would be a single characer, leave the left bracket. + * Remove brackets, but if the result would become empty, leave them; if the result would be a + * single characer, leave the left bracket. * * See: cleanFillCursorForCitationGroup */ @@ -435,13 +395,11 @@ public void nrCleanFillCursor(XTextDocument doc) WrappedTargetException, CreationException { - // alwaysRemoveBrackets : full compatibility with JabRef 5.2: - // brackets are temporary, only exist between nrGetFillCursor - // and nrCleanFillCursor. + // alwaysRemoveBrackets : full compatibility with JabRef 5.2: brackets are temporary, only + // exist between nrGetFillCursor and nrCleanFillCursor. final boolean alwaysRemoveBrackets = false; - // removeBracketsFromEmpty is intended to force removal if we - // are working on an "Empty citation" (INVISIBLE_CIT). + // removeBracketsFromEmpty is intended to force removal if we are working on an "Empty citation" (INVISIBLE_CIT). final boolean removeBracketsFromEmpty = false; final String left = REFERENCE_MARK_LEFT_BRACKET; @@ -451,28 +409,24 @@ public void nrCleanFillCursor(XTextDocument doc) String name = this.nrGetRangeName(); - XTextCursor full = this.nrGetRawCursor(doc).orElseThrow(RuntimeException::new); + XTextCursor full = this.nrGetRawCursor(doc).orElseThrow(IllegalStateException::new); final String fullText = full.getString(); final int fullTextLength = fullText.length(); if (!fullText.startsWith(left)) { - String msg = String.format("nrCleanFillCursor:" - + " (%s) does not start with REFERENCE_MARK_LEFT_BRACKET", - name); - throw new RuntimeException(msg); + String msg = String.format("nrCleanFillCursor: (%s) does not start with REFERENCE_MARK_LEFT_BRACKET", name); + throw new IllegalStateException(msg); } if (!fullText.endsWith(right)) { - String msg = String.format("nrCleanFillCursor:" - + " (%s) does not end with REFERENCE_MARK_RIGHT_BRACKET", - name); - throw new RuntimeException(msg); + String msg = String.format("nrCleanFillCursor: (%s) does not end with REFERENCE_MARK_RIGHT_BRACKET", name); + throw new IllegalStateException(msg); } final int contentLength = (fullTextLength - (leftLength + rightLength)); if (contentLength < 0) { String msg = String.format("nrCleanFillCursor: length(%s) < 0", name); - throw new RuntimeException(msg); + throw new IllegalStateException(msg); } boolean removeRight = ((contentLength >= 1) diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java index fd0523a4bf8..6a4f741b793 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java @@ -57,9 +57,7 @@ public OOFrontend(XTextDocument doc) NoDocumentException, WrappedTargetException { - // TODO: dataModel should come from looking at the - // document and preferences. - // + // TODO: dataModel should come from looking at the document and preferences. this.backend = new Backend52(); // Get the citationGroupNames @@ -98,24 +96,19 @@ public Optional healthReport(XTextDocument doc) } /** - * Creates a list of {@code RangeSortable} values for - * our {@code CitationGroup} values. Originally designed to be - * passed to {@code visualSort}. + * Creates a list of {@code RangeSortable} values for our {@code CitationGroup} + * values. Originally designed to be passed to {@code visualSort}. * - * The elements of the returned list are actually of type - * {@code RangeSortEntry}. + * The elements of the returned list are actually of type {@code RangeSortEntry}. * - * The result is sorted within {@code XTextRange.getText()} - * partitions of the citation groups according to their {@code XTextRange} - * (before mapping to footnote marks). + * The result is sorted within {@code XTextRange.getText()} partitions of the citation groups + * according to their {@code XTextRange} (before mapping to footnote marks). * - * In the result, RangeSortable.getIndexInPosition() contains - * unique indexes within the original partition (not after - * mapFootnotesToFootnoteMarks). + * In the result, RangeSortable.getIndexInPosition() contains unique indexes within the original + * partition (not after mapFootnotesToFootnoteMarks). * - * @param mapFootnotesToFootnoteMarks If true, replace ranges in - * footnotes with the range of the corresponding footnote - * mark. This is used for numbering the citations. + * @param mapFootnotesToFootnoteMarks If true, replace ranges in footnotes with the range of the + * corresponding footnote mark. This is used for numbering the citations. * */ private List> @@ -128,27 +121,24 @@ public Optional healthReport(XTextDocument doc) for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { XTextRange range = (this .getMarkRange(doc, cg) - .orElseThrow(RuntimeException::new)); + .orElseThrow(IllegalStateException::new)); sortables.add(new RangeSortEntry<>(range, 0, cg)); } /* * At this point we are almost ready to return sortables. * - * But we may want to number citations in a footnote - * as if it appeared where the footnote mark is. + * But we may want to number citations in a footnote as if it appeared where the footnote + * mark is. * - * The following code replaces ranges within footnotes with - * the range for the corresponding footnote mark. + * The following code replaces ranges within footnotes with the range for the corresponding + * footnote mark. * - * This brings further ambiguity if we have multiple - * citation groups within the same footnote: for the comparison - * they become indistinguishable. Numbering between them is - * not controlled. Also combineCiteMarkers will see them in - * the wrong order (if we use this comparison), and will not - * be able to merge. To avoid these, we sort textually within - * each .getText() partition and add indexInPosition - * accordingly. + * This brings further ambiguity if we have multiple citation groups within the same + * footnote: for the comparison they become indistinguishable. Numbering between them is + * not controlled. Also combineCiteMarkers will see them in the wrong order (if we use this + * comparison), and will not be able to merge. To avoid these, we sort textually within + * each .getText() partition and add indexInPosition accordingly. * */ @@ -174,53 +164,45 @@ public Optional healthReport(XTextDocument doc) } } result.add(sortable); - } + } } return result.stream().map(e -> e).collect(Collectors.toList()); } /** - * @param mapFootnotesToFootnoteMarks If true, sort reference - * marks in footnotes as if they appeared at the - * corresponding footnote mark. + * @param mapFootnotesToFootnoteMarks If true, sort reference marks in footnotes as if they + * appeared at the corresponding footnote mark. * * @return citation groups sorted by their visual positions. * - * Limitation: for two column layout visual (top-down, - * left-right) order does not match the expected (textual) - * order. + * Limitation: for two column layout visual (top-down, left-right) order does not match the + * expected (textual) order. * */ - private List - getVisuallySortedCitationGroups(XTextDocument doc, - boolean mapFootnotesToFootnoteMarks, - FunctionalTextViewCursor fcursor) + private List getVisuallySortedCitationGroups(XTextDocument doc, + boolean mapFootnotesToFootnoteMarks, + FunctionalTextViewCursor fcursor) throws WrappedTargetException, NoDocumentException, JabRefException { - List> sortables = - createVisualSortInput(doc, mapFootnotesToFootnoteMarks); + List> sortables = createVisualSortInput(doc, mapFootnotesToFootnoteMarks); - List> sorted = - RangeSortVisual.visualSort(sortables, - doc, - fcursor); + List> sorted = RangeSortVisual.visualSort(sortables, doc, fcursor); - List result = - (sorted.stream().map(e -> e.getContent()).collect(Collectors.toList())); + List result = (sorted.stream() + .map(RangeSortable::getContent) + .collect(Collectors.toList())); return result; } /** - * Return citation groups in visual order within (but not across) - * XText partitions. + * Return citation groups in visual order within (but not across) XText partitions. * - * This is (1) sufficient for combineCiteMarkers which looks for - * consecutive XTextRanges within each XText, (2) not confused by - * multicolumn layout or multipage display. + * This is (1) sufficient for combineCiteMarkers which looks for consecutive XTextRanges within + * each XText, (2) not confused by multicolumn layout or multipage display. */ public List getCitationGroupsSortedWithinPartitions(XTextDocument doc, boolean mapFootnotesToFootnoteMarks) @@ -236,19 +218,17 @@ public Optional healthReport(XTextDocument doc) } /** - * Create a citation group for the given citation keys, at the - * end of position. + * Create a citation group for the given citation keys, at the end of position. * - * On return {@code position} is collapsed, and is after the - * inserted space, or at the end of the reference mark. + * On return {@code position} is collapsed, and is after the inserted space, or at the end of + * the reference mark. * * @param citationKeys In storage order * @param pageInfos In storage order * @param citationType * @param position Collapsed to its end. - * @param insertSpaceAfter If true, we insert a space after the mark, that - * carries on format of characters from - * the original position. + * @param insertSpaceAfter If true, we insert a space after the mark, that carries on format of + * characters from the original position. */ public CitationGroup createCitationGroup(XTextDocument doc, List citationKeys, @@ -267,7 +247,7 @@ public CitationGroup createCitationGroup(XTextDocument doc, Objects.requireNonNull(pageInfos); if (pageInfos.size() != citationKeys.size()) { - throw new RuntimeException("pageInfos.size != citationKeys.size"); + throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); } CitationGroup cg = backend.createCitationGroup(doc, citationKeys, @@ -357,8 +337,8 @@ public List> citationRanges(XTextDocument new ArrayList<>(citationGroups.numberOfCitationGroups()); for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { - XTextRange range = this.getMarkRange(doc, cg).orElseThrow(RuntimeException::new); - String description = cg.cgid.citationGroupIdAsString(); // cg.cgRangeStorage.nrGetRangeName(); + XTextRange range = this.getMarkRange(doc, cg).orElseThrow(IllegalStateException::new); + String description = cg.cgid.citationGroupIdAsString(); result.add(new RangeForOverlapCheck<>(range, cg.cgid, RangeForOverlapCheck.REFERENCE_MARK_KIND, @@ -404,56 +384,88 @@ public List> viewCursorRanges(XTextDocumen } /** - * @return A range for each footnote mark where the footnote - * contains at least one citation group. + * @return A range for each footnote mark where the footnote contains at least one citation group. * - * Purpose: We do not want markers of footnotes containing - * reference marks to overlap with reference - * marks. Overwriting these footnote marks might kill our - * reference marks in the footnote. + * Purpose: We do not want markers of footnotes containing reference marks to overlap with + * reference marks. Overwriting these footnote marks might kill our reference marks in the + * footnote. * - * Note: Here we directly communicate to the document, not - * through the backend. This is because mapping ranges to - * footnote marks does not depend on how do we mark or - * structure those ranges. + * Note: Here we directly communicate to the document, not through the backend. This is because + * mapping ranges to footnote marks does not depend on how do we mark or structure those + * ranges. */ public List> - footnoteMarkRanges(XTextDocument doc, - List> citationRanges) + footnoteMarkRanges(XTextDocument doc, List> citationRanges) throws NoDocumentException, WrappedTargetException { - // Avoid inserting the same mark twice. - // Could use RangeSet if we had that. - RangeSet seen = new RangeSet(); + if (false) { + // Avoid inserting the same mark twice. + RangeSet seen = new RangeSet(); - List> result = new ArrayList<>(); + List> result = new ArrayList<>(); + + for (RangeForOverlapCheck citationRange : citationRanges) { - for (RangeForOverlapCheck citationRange : citationRanges) { + Optional footnoteMarkRange = UnoTextRange.getFootnoteMarkRange(citationRange.range); - Optional footnoteMarkRange = - UnoTextRange.getFootnoteMarkRange(citationRange.range); + if (footnoteMarkRange.isEmpty()) { + // not in footnote + continue; + } - if (footnoteMarkRange.isEmpty()) { - // not in footnote - continue; + boolean seenContains = seen.contains(footnoteMarkRange.get()); + if (!seenContains) { + seen.add(footnoteMarkRange.get()); + result.add(new RangeForOverlapCheck<>(footnoteMarkRange.get(), + citationRange.idWithinKind, + RangeForOverlapCheck.FOOTNOTE_MARK_KIND, + "FootnoteMark for " + citationRange.format())); + } } + return result; + } else { + + // RangeSet.add involves a few comparisons anf getText, which is probably costly. + // + // (On the other hand we only insert ranges of footnotes, which probably limits the sizes + // of its partitions) + // + // We can avoid using RangeSet by partitioning only and using a single range from + // each partition to get at the corresponding footnotemark range. + + List> result = new ArrayList<>(); + RangeSort.RangePartitions> partitions = + RangeSort.partitionRanges(citationRanges); + + // Now it is sufficient to check a single entry from each partition. + // Each partition corresponds to an XText, and each footnote has a single XText. + // (This latter ignores the possibility of XTextContents inserted into footnotes.) + // Also: different footnotes cannot share a footnotemark range, we are not creating duplicates. + for (List> partition : partitions.getPartitions()) { + if (partition.isEmpty()) { + continue; + } + RangeForOverlapCheck citationRange = partition.get(0); + + Optional footnoteMarkRange = UnoTextRange.getFootnoteMarkRange(citationRange.range); + + if (footnoteMarkRange.isEmpty()) { + // not in footnote + continue; + } - boolean seenContains = seen.contains(footnoteMarkRange.get()); - if (!seenContains) { - seen.add(footnoteMarkRange.get()); result.add(new RangeForOverlapCheck<>(footnoteMarkRange.get(), citationRange.idWithinKind, RangeForOverlapCheck.FOOTNOTE_MARK_KIND, "FootnoteMark for " + citationRange.format())); } + return result; } - return result; } - static String - rangeOverlapsToMessage(List>> overlaps) { + static String rangeOverlapsToMessage(List>> overlaps) { if (overlaps.size() == 0) { return "(*no overlaps*)"; @@ -481,6 +493,7 @@ public List> viewCursorRanges(XTextDocumen * Check for any overlap between userRanges and protected ranges. * * Assume userRanges is small (usually 1 elements for checking the cursor) + * * Returns on first problem found. */ public OOVoidResult @@ -500,11 +513,10 @@ public List> viewCursorRanges(XTextDocumen ranges.addAll(footnoteMarkRanges(doc, citationRanges)); List>> overlaps = - RangeOverlapBetween.findFirst( - doc, - userRanges, - ranges, - requireSeparation); + RangeOverlapBetween.findFirst(doc, + userRanges, + ranges, + requireSeparation); if (overlaps.size() == 0) { return OOVoidResult.ok(); @@ -518,11 +530,10 @@ public List> viewCursorRanges(XTextDocumen * @param reportAtMost Limit number of overlaps reported (0 for no limit) * */ - public OOVoidResult - checkRangeOverlaps(XTextDocument doc, - List> userRanges, - boolean requireSeparation, - int reportAtMost) + public OOVoidResult checkRangeOverlaps(XTextDocument doc, + List> userRanges, + boolean requireSeparation, + int reportAtMost) throws NoDocumentException, WrappedTargetException { @@ -550,33 +561,29 @@ public List> viewCursorRanges(XTextDocumen * * Called from: ManageCitationsDialogViewModel constructor. * - * @return A list with entries corresponding to citations in the - * text, in arbitrary order (same order as from - * getJabRefReferenceMarkNames). + * @return A list with entries corresponding to citations in the text, in arbitrary order (same + * order as from getJabRefReferenceMarkNames). * - * Note: visual or alphabetic order could be more - * manageable for the user. We could provide these - * here, but switching between them needs change on - * GUI (adding a toggle or selector). + * Note: visual or alphabetic order could be more manageable for the user. We + * could provide these here, but switching between them needs change on GUI + * (adding a toggle or selector). * - * Note: CitationEntry implements Comparable, where - * compareTo() and equals() are based on refMarkName. - * The order used in the "Manage citations" dialog + * Note: CitationEntry implements Comparable, where compareTo() and equals() are + * based on refMarkName. The order used in the "Manage citations" dialog * does not seem to use that. * - * The 1st is labeled "Citation" (show citation in bold, - * and some context around it). + * The 1st is labeled "Citation" (show citation in bold, and some context + * around it). * - * The columns can be sorted by clicking on the column title. - * For the "Citation" column, the sorting is based on the content, - * (the context before the citation), not on the citation itself. + * The columns can be sorted by clicking on the column title. For the + * "Citation" column, the sorting is based on the content, (the context + * before the citation), not on the citation itself. * - * In the "Extra information ..." column some visual indication - * of the editable part could be helpful. + * In the "Extra information ..." column some visual indication of the + * editable part could be helpful. * - * Wish: selecting an entry (or a button in the line) in - * the GUI could move the cursor in the document to - * the entry. + * Wish: selecting an entry (or a button in the line) in the GUI could move the cursor + * in the document to the entry. */ public List getCitationEntries(XTextDocument doc) throws @@ -608,8 +615,7 @@ public void imposeGlobalOrder(XTextDocument doc, FunctionalTextViewCursor fcurso boolean mapFootnotesToFootnoteMarks = true; List sortedCitationGroups = getVisuallySortedCitationGroups(doc, mapFootnotesToFootnoteMarks, fcursor); - List sortedCitationGroupIds = - OOListUtil.map(sortedCitationGroups, cg -> cg.cgid); + List sortedCitationGroupIds = OOListUtil.map(sortedCitationGroups, cg -> cg.cgid); citationGroups.setGlobalOrder(sortedCitationGroupIds); } } 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 ef1a4c42dc5..2d0de320ca6 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java @@ -47,7 +47,6 @@ public static void rebuildBibTextSection(XTextDocument doc, throws NoSuchElementException, WrappedTargetException, - IllegalArgumentException, CreationException, PropertyVetoException, UnknownPropertyException, @@ -69,8 +68,7 @@ public static void rebuildBibTextSection(XTextDocument doc, */ private static void createBibTextSection2(XTextDocument doc) throws - CreationException, - IllegalArgumentException { + CreationException { // Always creating at the end of the document. // Alternatively, we could receive a cursor. @@ -89,7 +87,6 @@ private static void createBibTextSection2(XTextDocument doc) private static void clearBibTextSectionContent2(XTextDocument doc) throws CreationException, - IllegalArgumentException, NoDocumentException, WrappedTargetException { @@ -124,7 +121,7 @@ private static void populateBibTextSection(XTextDocument doc, UnknownPropertyException, WrappedTargetException { - XTextRange sectionRange = getBibliographyRange(doc).orElseThrow(RuntimeException::new); + XTextRange sectionRange = getBibliographyRange(doc).orElseThrow(IllegalStateException::new); XTextCursor cursor = doc.getText().createTextCursorByRange(sectionRange); @@ -138,13 +135,13 @@ private static void populateBibTextSection(XTextDocument doc, cursor.collapseToEnd(); // remove the inital empty paragraph from the section. - sectionRange = getBibliographyRange(doc).orElseThrow(RuntimeException::new); + sectionRange = getBibliographyRange(doc).orElseThrow(IllegalStateException::new); XTextCursor initialParagraph = doc.getText().createTextCursorByRange(sectionRange); initialParagraph.collapseToStart(); initialParagraph.goRight((short) 1, true); initialParagraph.setString(""); - UnoBookmark.remove(doc, BIB_SECTION_END_NAME); + UnoBookmark.removeIfExists(doc, BIB_SECTION_END_NAME); UnoBookmark.create(doc, BIB_SECTION_END_NAME, cursor, true); cursor.collapseToEnd(); diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java index 7d864ab1063..b3f90d380a7 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java @@ -102,7 +102,7 @@ public static void fillCitationMarkInCursor(XTextDocument doc, OOText citationText2 = style.decorateCitationMarker(citationText); // inject a ZERO_WIDTH_SPACE to hold the initial character format final String ZERO_WIDTH_SPACE = "\u200b"; - citationText2 = OOText.fromString(ZERO_WIDTH_SPACE + citationText2.asString()); + citationText2 = OOText.fromString(ZERO_WIDTH_SPACE + citationText2.toString()); OOTextIntoOO.write(doc, cursor, citationText2); } else { cursor.setString(""); @@ -150,7 +150,7 @@ public static void createAndFillCitationGroup(OOFrontend fr, Objects.requireNonNull(pageInfos); if (pageInfos.size() != citationKeys.size()) { - throw new RuntimeException("pageInfos.size != citationKeys.size"); + throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); } CitationGroup cg = fr.createCitationGroup(doc, citationKeys, diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index 113cef246e2..feccb727f53 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -517,20 +517,6 @@ public String getNumCitationMarker(List number, int minGroupingCount, b /* end_old */ /* begin_old */ - /** - * Format the marker for the in-text citation according to this BIB style. Uniquefier letters are added as - * provided by the uniquefiers argument. If successive entries within the citation are uniquefied from each other, - * this method will perform a grouping of these entries. - * - * @param entries The list of JabRef BibEntry providing the data. - * @param database A map of BibEntry-BibDatabase pairs. - * @param inParenthesis Signals whether a parenthesized citation or an in-text citation is wanted. - * @param uniquefiers Strings to add behind the year for each entry in case it's needed to separate similar - * entries. - * @param unlimAuthors Boolean for each entry. If true, we should not use "et al" formatting regardless - * of the number of authors. Can be null to indicate that no entries should have unlimited names. - * @return The formatted citation. - */ public String getCitationMarker(List entries, Map database, boolean inParenthesis, String[] uniquefiers, int[] unlimAuthors) { // Look for groups of uniquefied entries that should be combined in the output. @@ -1115,7 +1101,7 @@ public OOText getNumCitationMarkerForBibliography(CitationMarkerNumericBibEntry // not null, check size if (pageInfos.size() != nCitations) { - throw new RuntimeException("normalizePageInfos: pageInfos.size() != nCitations"); + throw new IllegalArgumentException("normalizePageInfos: pageInfos.size() != nCitations"); } // not null, normalize elementwise 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 ee2bba27e7e..e501cd4aaaf 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java @@ -65,10 +65,10 @@ private static String markupAuthorName(OOBibStyle style, String name) { * to mark their omission. * Set to -1 to write out all authors. * - * maxAuthors=0 is pointless, now throws RuntimeException + * maxAuthors=0 is pointless, now throws IllegalArgumentException * (Earlier it behaved as maxAuthors=1) * - * maxAuthors less than -1 : throw RuntimeException + * maxAuthors less than -1 : throw IllegalArgumentException * * @param andString For "A, B[ and ]C" * @@ -129,10 +129,10 @@ private static String formatAuthorList(OOBibStyle style, // To reduce ambiguity, throw on unexpected values of maxAuthors if (maxAuthors == 0 && nAuthors != 0) { - throw new RuntimeException("maxAuthors = 0 in formatAuthorList"); + throw new IllegalArgumentException("maxAuthors = 0 in formatAuthorList"); } if (maxAuthors < -1) { - throw new RuntimeException("maxAuthors < -1 in formatAuthorList"); + throw new IllegalArgumentException("maxAuthors < -1 in formatAuthorList"); } // emitAllAuthors == false means use "et al." @@ -724,8 +724,8 @@ static OOText getNormalizedCitationMarker(OOBibStyle style, if (uniqueLetterDoesNotMakeUnique && nonUniqueCitationMarkerHandling.equals(NonUniqueCitationMarker.THROWS)) { - throw new RuntimeException("different citation keys," - + " but same normalizedMarker and uniqueLetter"); + throw new IllegalArgumentException("different citation keys," + + " but same normalizedMarker and uniqueLetter"); } final boolean pageInfoInhibitsJoin = (bothPageInfosAreEmpty diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java index 376c4478421..8d8422fbc51 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java @@ -91,7 +91,7 @@ private static void emitBlock(List block, final int blockSize = block.size(); if (blockSize == 0) { - throw new RuntimeException("The block is empty"); + throw new IllegalArgumentException("The block is empty"); } if (blockSize == 1) { @@ -117,17 +117,16 @@ private static void emitBlock(List block, */ if (block.stream().anyMatch(x -> x.getPageInfo().isPresent())) { - throw new RuntimeException("Found pageInfo in a block with more than one elements"); + throw new IllegalArgumentException("Found pageInfo in a block with more than one elements"); } if (block.stream().anyMatch(x -> x.getNumber().isEmpty())) { - throw new RuntimeException("Found unresolved entry" - + " in a block with more than one elements"); + throw new IllegalArgumentException("Found unresolved entry in a block with more than one elements"); } for (int j = 1; j < blockSize; j++) { if ((block.get(j).getNumber().get() - block.get(j - 1).getNumber().get()) != 1) { - throw new RuntimeException("Numbers are not consecutive"); + throw new IllegalArgumentException("Numbers are not consecutive"); } } @@ -139,7 +138,7 @@ private static void emitBlock(List block, int first = block.get(0).getNumber().get(); int last = block.get(blockSize - 1).getNumber().get(); if (last != (first + blockSize - 1)) { - throw new RuntimeException("blockSize and length of num range differ"); + throw new IllegalArgumentException("blockSize and length of num range differ"); } // Emit: "first-last" @@ -221,7 +220,7 @@ public static OOText getNumCitationMarker2(OOBibStyle style, final CitationMarkerNumericEntry current = sorted.get(i); if (current.getNumber().isPresent() && current.getNumber().get() < 0) { - throw new RuntimeException("getNumCitationMarker2: found negative value"); + throw new IllegalArgumentException("getNumCitationMarker2: found negative number"); } if (currentBlock.size() == 0) { @@ -259,7 +258,7 @@ public static OOText getNumCitationMarker2(OOBibStyle style, } if (nextBlock.size() != 0) { - throw new RuntimeException("impossible: (nextBlock.size() != 0) after loop"); + throw new IllegalStateException("impossible: (nextBlock.size() != 0) after loop"); } if (currentBlock.size() > 0) { diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java b/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java index c9ae527dcec..6c22c8abb09 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java @@ -36,7 +36,7 @@ public static OOText formatBibliography(CitationGroups cgs, OOText title = style.getFormattedBibliographyTitle(); OOText body = formatBibliographyBody(cgs, bibliography, style, alwaysAddCitedOnPages); - return OOText.fromString(title.asString() + body.asString()); + return OOText.fromString(title.toString() + body.toString()); } /** @@ -51,7 +51,7 @@ public static OOText formatBibliographyBody(CitationGroups cgs, for (CitedKey ck : bibliography.values()) { OOText entryText = formatBibliographyEntry(cgs, ck, style, alwaysAddCitedOnPages); - stringBuilder.append(entryText.asString()); + stringBuilder.append(entryText.toString()); } return OOText.fromString(stringBuilder.toString()); @@ -68,18 +68,18 @@ public static OOText formatBibliographyEntry(CitationGroups cgs, // insert marker "[1]" if (style.isNumberEntries()) { - sb.append(style.getNumCitationMarkerForBibliography(ck).asString()); + sb.append(style.getNumCitationMarkerForBibliography(ck).toString()); } else { // !style.isNumberEntries() : emit no prefix // Note: We might want [citationKey] prefix for style.isCitationKeyCiteMarkers(); } // Add entry body - sb.append(formatBibliographyEntryBody(ck, style).asString()); + sb.append(formatBibliographyEntryBody(ck, style).toString()); // Add "Cited on pages" if (ck.getLookupResult().isEmpty() || alwaysAddCitedOnPages) { - sb.append(formatCitedOnPages(cgs, ck).asString()); + sb.append(formatCitedOnPages(cgs, ck).toString()); } // Add paragraph @@ -169,14 +169,17 @@ private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey ck) { List citationGroups = new ArrayList<>(); for (CitationPath p : ck.getCitationPaths()) { CitationGroupId cgid = p.group; - CitationGroup cg = cgs.getCitationGroupOrThrow(cgid); - citationGroups.add(cg); + Optional cg = cgs.getCitationGroup(cgid); + if (cg.isEmpty()) { + throw new IllegalStateException(); + } + citationGroups.add(cg.get()); } // sort the citationGroups according to their indexInGlobalOrder citationGroups.sort((a, b) -> { - Integer aa = a.getIndexInGlobalOrder().orElseThrow(RuntimeException::new); - Integer bb = b.getIndexInGlobalOrder().orElseThrow(RuntimeException::new); + Integer aa = a.getIndexInGlobalOrder().orElseThrow(IllegalStateException::new); + Integer bb = b.getIndexInGlobalOrder().orElseThrow(IllegalStateException::new); return (aa.compareTo(bb)); }); @@ -185,9 +188,9 @@ private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey ck) { if (i > 0) { sb.append(", "); } - String markName = cg.getReferenceMarkNameForLinking().orElseThrow(RuntimeException::new); + String markName = cg.getReferenceMarkNameForLinking().orElseThrow(IllegalStateException::new); OOText xref = OOFormat.formatReferenceToPageNumberOfReferenceMark(markName); - sb.append(xref.asString()); + sb.append(xref.toString()); i++; } sb.append(suffix); diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java index 6f7709aac10..05475fcdfac 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java @@ -66,12 +66,10 @@ public static Comparator comparatorForMulticite(OOBibStyle style) { * Fill cgs.bibliography and cgs.citationGroupsUnordered//CitationMarker * according to style. */ - public static void produceCitationMarkers(CitationGroups cgs, - List databases, - OOBibStyle style) { + public static void produceCitationMarkers(CitationGroups cgs, List databases, OOBibStyle style) { if (!cgs.hasGlobalOrder()) { - throw new RuntimeException("produceCitationMarkers: globalOrder is misssing in cgs"); + throw new IllegalStateException("produceCitationMarkers: globalOrder is misssing in cgs"); } cgs.lookupCitations(databases); diff --git a/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java index e5c54773b07..d8e1832b6ef 100644 --- a/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java +++ b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java @@ -24,8 +24,8 @@ public Optional nrGetMarkRange(XTextDocument doc) WrappedTargetException; /** - * Cursor for the reference marks as is, not prepared for filling, - * but does not need nrCleanFillCursor either. + * Cursor for the reference marks as is, not prepared for filling, but does not need + * nrCleanFillCursor either. */ public Optional nrGetRawCursor(XTextDocument doc) throws @@ -44,8 +44,8 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) CreationException; /** - * Remove brackets, but if the result would become empty, leave - * them; if the result would be a single characer, leave the left bracket. + * Remove brackets, but if the result would become empty, leave them; if the result would be a + * single characer, leave the left bracket. * */ public void nrCleanFillCursor(XTextDocument doc) diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java index 472ca519161..be5ee399e55 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java @@ -1,9 +1,16 @@ package org.jabref.model.openoffice.ootext; +/** + * Helper functions to produce some of the markup as understood by OOTextIntoOO.write + * + * These do not cover all tags, only those needed to embed markup + * from Layout and citation marker formatters into citation markers and + * bibliography. + */ public class OOFormat { /** - * Mark {@code s} as using a character locale known to OO. + * Mark {@code ootext} as using a character locale known to OO. * * @param locale language[-country[-territory]] * @@ -11,63 +18,61 @@ public class OOFormat { * * The country part is optional. * - * The territory part is not only optional, the allowed "codes are - * vendor and browser-specific", so probably best to avoid them if possible. + * The territory part is not only optional, the allowed "codes are vendor and browser-specific", + * so probably best to avoid them if possible. * */ - public static OOText setLocale(OOText s, String locale) { - return OOText.fromString(String.format("", locale) + s.asString() + ""); + public static OOText setLocale(OOText ootext, String locale) { + return OOText.fromString(String.format("", locale) + ootext.toString() + ""); } /** - * Mark {@code s} as using the character locale "zxx", which means - * "no language", "no linguistic content". + * Mark {@code ootext} as using the character locale "zxx", which means "no language", "no + * linguistic content". * * Used around citation marks, probably to turn off spellchecking. * */ - public static OOText setLocaleNone(OOText s) { - return OOFormat.setLocale(s, "zxx"); + public static OOText setLocaleNone(OOText ootext) { + return OOFormat.setLocale(ootext, "zxx"); } /** - * Mark {@code s} using a character style {@code charStyle} + * Mark {@code ootext} using a character style {@code charStyle} * - * @param charStyle Name of a character style known to OO. May be - * empty for "Standard", which in turn means do not override any properties. + * @param charStyle Name of a character style known to OO. May be empty for "Standard", which in + * turn means do not override any properties. * */ - public static OOText setCharStyle(OOText s, String charStyle) { + public static OOText setCharStyle(OOText ootext, String charStyle) { return OOText.fromString(String.format("", charStyle) - + s.asString() - + ""); + + ootext.toString() + + ""); } /** - * Mark {@code s} as part of a paragraph with style {@code paraStyle} + * Mark {@code ootext} as part of a paragraph with style {@code paraStyle} */ - public static OOText paragraph(OOText s, String paraStyle) { + public static OOText paragraph(OOText ootext, String paraStyle) { if (paraStyle == null || "".equals(paraStyle)) { - return paragraph(s); + return paragraph(ootext); } String startTag = String.format("

", paraStyle); - return OOText.fromString(startTag + s.asString() + "

"); + return OOText.fromString(startTag + ootext.toString() + "

"); } /** - * Mark {@code s} as part of a paragraph. + * Mark {@code ootext} as part of a paragraph. */ - public static OOText paragraph(OOText s) { - return OOText.fromString("

" + s.asString() + "

"); + public static OOText paragraph(OOText ootext) { + return OOText.fromString("

" + ootext.toString() + "

"); } /** - * Format an OO cross-reference showing the target's page number - * as label to a reference mark. + * Format an OO cross-reference showing the target's page number as label to a reference mark. */ public static OOText formatReferenceToPageNumberOfReferenceMark(String referencMarkName) { - String s = String.format("", - referencMarkName); - return OOText.fromString(s); + String string = String.format("", referencMarkName); + return OOText.fromString(string); } } diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOText.java b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java index a568a7c6e8a..ad0b9fb448d 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOText.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java @@ -5,9 +5,8 @@ /** * Text with HTML-like markup as understood by OOTextIntoOO.write * - * Some of the tags can be added using OOFormat methods. Others come - * from the layout engine, either by interpreting LaTeX markup or from - * settings in the jstyle file. + * Some of the tags can be added using OOFormat methods. Others come from the layout engine, either + * by interpreting LaTeX markup or from settings in the jstyle file. */ public class OOText { @@ -19,38 +18,39 @@ private OOText(String data) { } /* null input is passed through */ - public static OOText fromString(String s) { - if (s == null) { + public static OOText fromString(String string) { + if (string == null) { return null; } - return new OOText(s); + return new OOText(string); } /* null input is passed through */ - public static String toString(OOText s) { - if (s == null) { + public static String toString(OOText ootext) { + if (ootext == null) { return null; } - return s.data; + return ootext.data; } - public String asString() { + @Override + public String toString() { return data; } /* Object.equals */ @Override - public boolean equals(Object o) { + public boolean equals(Object object) { - if (o == this) { + if (object == this) { return true; } - if (!(o instanceof OOText)) { + if (!(object instanceof OOText)) { return false; } - OOText c = (OOText) o; + OOText c = (OOText) object; return data.equals(c.data); } diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java index 298329f3a43..0758d515446 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java @@ -32,7 +32,6 @@ import com.sun.star.beans.XPropertySet; import com.sun.star.beans.XPropertySetInfo; import com.sun.star.beans.XPropertyState; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.Locale; import com.sun.star.lang.WrappedTargetException; import com.sun.star.style.CaseMap; @@ -45,8 +44,7 @@ import org.slf4j.LoggerFactory; /** - * Interpret OOText into an OpenOffice or LibreOffice writer - * document. + * Interpret OOText into an OpenOffice or LibreOffice writer document. */ @AllowedToUseAwt("Requires AWT for changing document properties") public class OOTextIntoOO { @@ -148,24 +146,17 @@ private OOTextIntoOO() { */ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) throws - UnknownPropertyException, PropertyVetoException, WrappedTargetException, - IllegalArgumentException, - NoSuchElementException, CreationException { - final boolean debugThisFun = false; - Objects.requireNonNull(doc); Objects.requireNonNull(ootext); Objects.requireNonNull(position); String lText = OOText.toString(ootext); - if (debugThisFun) { - System.out.println(lText); - } + LOGGER.debug(lText); XText text = position.getText(); XTextCursor cursor = text.createTextCursorByRange(position); @@ -242,15 +233,11 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) //

if (value != null && !value.equals("")) { if (setParagraphStyle(cursor, value)) { - if (debugThisFun) { - // Presumably tested already: - LOGGER.warn(String.format("oo:ParaStyleName=\"%s\" failed", value)); - } + // Presumably tested already: + LOGGER.debug(String.format("oo:ParaStyleName=\"%s\" failed", value)); } } else { - if (debugThisFun) { - LOGGER.warn(String.format("oo:ParaStyleName inherited")); - } + LOGGER.debug(String.format("oo:ParaStyleName inherited")); } break; default: @@ -359,10 +346,10 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) */ public static void removeDirectFormatting(XTextCursor cursor) { - XMultiPropertyStates mpss = UnoCast.unoQI(XMultiPropertyStates.class, cursor); + XMultiPropertyStates mpss = UnoCast.cast(XMultiPropertyStates.class, cursor).get(); - XPropertySet propertySet = UnoCast.unoQI(XPropertySet.class, cursor); - XPropertyState xPropertyState = UnoCast.unoQI(XPropertyState.class, cursor); + XPropertySet propertySet = UnoCast.cast(XPropertySet.class, cursor).get(); + XPropertyState xPropertyState = UnoCast.cast(XPropertyState.class, cursor).get(); try { // Special handling @@ -370,7 +357,6 @@ public static void removeDirectFormatting(XTextCursor cursor) { xPropertyState.setPropertyToDefault("CharCaseMap"); } catch (UnknownPropertyException | PropertyVetoException | - IllegalArgumentException | WrappedTargetException ex) { LOGGER.warn("exception caught", ex); } @@ -378,8 +364,8 @@ public static void removeDirectFormatting(XTextCursor cursor) { mpss.setAllPropertiesToDefault(); /* - * Now that we have called setAllPropertiesToDefault, check which properties - * are not set to default and try to correct what we can and seem necessary. + * Now that we have called setAllPropertiesToDefault, check which properties are not set to + * default and try to correct what we can and seem necessary. * * Note: tested with LibreOffice : 6.4.6.2 */ @@ -396,7 +382,7 @@ public static void removeDirectFormatting(XTextCursor cursor) { "ParaStyleName"); // query again, just in case it matters - propertySet = UnoCast.unoQI(XPropertySet.class, cursor); + propertySet = UnoCast.cast(XPropertySet.class, cursor).get(); XPropertySetInfo propertySetInfo = propertySet.getPropertySetInfo(); // check the result @@ -409,7 +395,7 @@ public static void removeDirectFormatting(XTextCursor cursor) { continue; } } catch (UnknownPropertyException ex) { - throw new RuntimeException("Unexpected UnknownPropertyException"); + throw new java.lang.IllegalStateException("Unexpected UnknownPropertyException"); } if (knownToFail.contains(p.Name)) { continue; @@ -421,8 +407,8 @@ public static void removeDirectFormatting(XTextCursor cursor) { static class MyPropertyStack { /* - * We only try to control these. Should include all character - * properties we set, and maybe their interdependencies. + * We only try to control these. Should include all character properties we set, and maybe + * their interdependencies. * * For a list of properties see: * https://www.openoffice.org/api/docs/common/ref/com/sun/star/style/CharacterProperties.html @@ -479,17 +465,15 @@ static class MyPropertyStack { final String[] goodNames; /** - * Maintain a stack of layers, each containing a description - * of the desired state of properties. Each description is an - * ArrayList of property values, Optional.empty() encoding - * "not directly set". + * Maintain a stack of layers, each containing a description of the desired state of + * properties. Each description is an ArrayList of property values, Optional.empty() + * encoding "not directly set". */ final Stack>> layers; - MyPropertyStack(XTextCursor cursor) - throws UnknownPropertyException { + MyPropertyStack(XTextCursor cursor) { - XPropertySet propertySet = UnoCast.unoQI(XPropertySet.class, cursor); + XPropertySet propertySet = UnoCast.cast(XPropertySet.class, cursor).get(); XPropertySetInfo propertySetInfo = propertySet.getPropertySetInfo(); /* @@ -515,8 +499,7 @@ static class MyPropertyStack { goodNames[ entry.getValue() ] = entry.getKey(); } - // XMultiPropertySet.setPropertyValues() - // requires alphabetically sorted property names. + // XMultiPropertySet.setPropertyValues() requires alphabetically sorted property names. // We adjust here: Arrays.sort(goodNames); for (int i = 0; i < goodSize; i++) { @@ -524,12 +507,17 @@ static class MyPropertyStack { } /* - * Get the initial state of the properties and add add the first layer. + * Get the initial state of the properties and add the first layer. */ - XMultiPropertyStates mpss = UnoCast.unoQI(XMultiPropertyStates.class, cursor); - PropertyState[] propertyStates = mpss.getPropertyStates(goodNames); + XMultiPropertyStates mpss = UnoCast.cast(XMultiPropertyStates.class, cursor).get(); + PropertyState[] propertyStates = null; + try { + propertyStates = mpss.getPropertyStates(goodNames); + } catch (UnknownPropertyException ex) { + throw new java.lang.IllegalStateException("Caught unexpected UnknownPropertyException"); + } - XMultiPropertySet mps = UnoCast.unoQI(XMultiPropertySet.class, cursor); + XMultiPropertySet mps = UnoCast.cast(XMultiPropertySet.class, cursor).get(); Object[] initialValues = mps.getPropertyValues(goodNames); ArrayList> initialValuesOpt = new ArrayList<>(goodSize); @@ -547,9 +535,8 @@ static class MyPropertyStack { } /** - * Given a list of property name, property value pairs, - * construct and push a new layer describing the intended - * state after these have been applied. + * Given a list of property name, property value pairs, construct and push a new layer + * describing the intended state after these have been applied. * * Opening tags usually call this. */ @@ -582,11 +569,12 @@ void popLayer() { /** * Apply the current desired formatting state to a cursor. + * * The idea is to minimize the number of calls to OpenOffice. */ void apply(XTextCursor cursor) { - XMultiPropertySet mps = UnoCast.unoQI(XMultiPropertySet.class, cursor); - XMultiPropertyStates mpss = UnoCast.unoQI(XMultiPropertyStates.class, cursor); + XMultiPropertySet mps = UnoCast.cast(XMultiPropertySet.class, cursor).get(); + XMultiPropertyStates mpss = UnoCast.cast(XMultiPropertyStates.class, cursor).get(); ArrayList> topLayer = layers.peek(); try { // select values to be set @@ -608,11 +596,9 @@ void apply(XTextCursor cursor) { mpss.setPropertiesToDefault(delNamesArray); mps.setPropertyValues(namesArray, values.toArray()); } catch (UnknownPropertyException ex) { - LOGGER.warn("UnknownPropertyException in MyPropertyStack.apply"); + LOGGER.warn("UnknownPropertyException in MyPropertyStack.apply", ex); } catch (PropertyVetoException ex) { LOGGER.warn("PropertyVetoException in MyPropertyStack.apply"); - } catch (IllegalArgumentException ex) { - LOGGER.warn("IllegalArgumentException in MyPropertyStack.apply"); } catch (WrappedTargetException ex) { LOGGER.warn("WrappedTargetException in MyPropertyStack.apply"); } @@ -648,18 +634,18 @@ private static List> parseAttributes(String s) { } /* - * We rely on property values being either DIRECT_VALUE or - * DEFAULT_VALUE (not AMBIGUOUS_VALUE). If the cursor covers a homogeneous region, - * or is collapsed, then this is true. + * We rely on property values being either DIRECT_VALUE or DEFAULT_VALUE (not + * AMBIGUOUS_VALUE). If the cursor covers a homogeneous region, or is collapsed, then this is + * true. */ private static boolean isPropertyDefault(XTextCursor cursor, String propertyName) throws UnknownPropertyException { - XPropertyState xPropertyState = UnoCast.unoQI(XPropertyState.class, cursor); + XPropertyState xPropertyState = UnoCast.cast(XPropertyState.class, cursor).get(); PropertyState state = xPropertyState.getPropertyState(propertyName); if (state == PropertyState.AMBIGUOUS_VALUE) { - throw new RuntimeException("PropertyState.AMBIGUOUS_VALUE" - + " (expected properties for a homogeneous cursor)"); + throw new java.lang.IllegalArgumentException("PropertyState.AMBIGUOUS_VALUE" + + " (expected properties for a homogeneous cursor)"); } return state == PropertyState.DEFAULT_VALUE; } @@ -723,7 +709,7 @@ private static List> setCharLocale(Locale value) { */ private static List> setCharLocale(String value) { if (value == null || "".equals(value)) { - throw new RuntimeException("setCharLocale \"\" or null"); + throw new java.lang.IllegalArgumentException("setCharLocale \"\" or null"); } String[] parts = value.split("-"); String language = (parts.length > 0) ? parts[0] : ""; @@ -735,8 +721,8 @@ private static List> setCharLocale(String value) { /* * SuperScript and SubScript. * - * @param relative If true, calculate the new values relative to - * the current values. This allows subscript-in-superscript. + * @param relative If true, calculate the new values relative to the current values. This allows + * subscript-in-superscript. */ private static List> setCharEscapement(Optional value, Optional height, @@ -796,22 +782,28 @@ public static boolean setParagraphStyle(XTextCursor cursor, String paragraphStyl final boolean FAIL = true; final boolean PASS = false; - XParagraphCursor paragraphCursor = UnoCast.unoQI(XParagraphCursor.class, cursor); - XPropertySet propertySet = UnoCast.unoQI(XPropertySet.class, paragraphCursor); + XParagraphCursor paragraphCursor = UnoCast.cast(XParagraphCursor.class, cursor).get(); + XPropertySet propertySet = UnoCast.cast(XPropertySet.class, paragraphCursor).get(); try { propertySet.setPropertyValue(PARA_STYLE_NAME, paragraphStyle); return PASS; } catch (UnknownPropertyException | PropertyVetoException - | IllegalArgumentException + | com.sun.star.lang.IllegalArgumentException | WrappedTargetException ex) { return FAIL; } } - private static void insertParagraphBreak(XText text, XTextCursor cursor) - throws IllegalArgumentException { - text.insertControlCharacter(cursor, ControlCharacter.PARAGRAPH_BREAK, true); + private static void insertParagraphBreak(XText text, XTextCursor cursor) { + try { + text.insertControlCharacter(cursor, ControlCharacter.PARAGRAPH_BREAK, true); + } catch (com.sun.star.lang.IllegalArgumentException ex) { + // Assuming it means wrong code for ControlCharacter. + // https://api.libreoffice.org/docs/idl/ref/ does not tell. + // If my assumption is correct, we never get here. + throw new java.lang.IllegalArgumentException("Caught unexpected com.sun.star.lang.IllegalArgumentException", ex); + } } } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java b/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java index 3f780274b0f..e08a7f4a2ad 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java @@ -13,23 +13,21 @@ import com.sun.star.text.XTextViewCursor; /* - * A problem with XTextViewCursor: if it is not in text, then we get a - * crippled version that does not support viewCursor.getStart() or - * viewCursor.gotoRange(range,false), and will throw an exception - * instead. + * A problem with XTextViewCursor: if it is not in text, then we get a crippled version that does + * not support viewCursor.getStart() or viewCursor.gotoRange(range,false), and will throw an + * exception instead. * - * Here we manipulate the cursor via XSelectionSupplier.getSelection and - * XSelectionSupplier.select to move it to the text. + * Here we manipulate the cursor via XSelectionSupplier.getSelection and XSelectionSupplier.select + * to move it to the text. * * Seems to work when the user selected a frame or image. * In these cases restoring the selection works, too. * - * When the cursor is in a comment (referred to as "annotation" in OO - * API) then initialSelection is null, and select() fails to - * get a functional viewCursor. + * When the cursor is in a comment (referred to as "annotation" in OO API) then initialSelection is + * null, and select() fails to get a functional viewCursor. * - * If FunctionalTextViewCursor.get() reports error, we have to ask the - * user to move the cursor into the text part of the document. + * If FunctionalTextViewCursor.get() reports error, we have to ask the user to move the cursor into + * the text part of the document. * * Usage: * @@ -45,19 +43,13 @@ */ public class FunctionalTextViewCursor { - /* - * The initial position of the cursor or null. - */ + /* The initial position of the cursor or null. */ private XTextRange initialPosition; - /* - * The initial selection in the document or null. - */ + /* The initial selection in the document or null. */ private XServiceInfo initialSelection; - /* - * The view cursor, potentially moved from its original location. - */ + /* The view cursor, potentially moved from its original location. */ private XTextViewCursor viewCursor; private FunctionalTextViewCursor(XTextRange initialPosition, @@ -71,12 +63,10 @@ private FunctionalTextViewCursor(XTextRange initialPosition, /* * Get a functional XTextViewCursor or an error message. * - * The cursor position may differ from the location - * provided by the user. + * The cursor position may differ from the location provided by the user. * - * On failure the constructor restores the selection. On success, - * the caller may want to call instance.restore() after finished - * using the cursor. + * On failure the constructor restores the selection. On success, the caller may want to call + * instance.restore() after finished using the cursor. */ public static OOResult get(XTextDocument doc) { @@ -89,9 +79,7 @@ public static OOResult get(XTextDocument doc) try { initialPosition = UnoCursor.createTextCursorByRange(viewCursor); viewCursor.getStart(); - return OOResult.ok(new FunctionalTextViewCursor(initialPosition, - initialSelection, - viewCursor)); + return OOResult.ok(new FunctionalTextViewCursor(initialPosition, initialSelection, viewCursor)); } catch (com.sun.star.uno.RuntimeException ex) { // bad cursor viewCursor = null; @@ -100,8 +88,7 @@ public static OOResult get(XTextDocument doc) } if (initialSelection == null) { - String errorMessage = ("Selection is not available:" - + " cannot provide a functional view cursor"); + String errorMessage = ("Selection is not available: cannot provide a functional view cursor"); return OOResult.error(errorMessage); } else if (!Arrays.stream(initialSelection.getSupportedServiceNames()) .anyMatch("com.sun.star.text.TextRanges"::equals)) { @@ -149,10 +136,7 @@ private static void restore(XTextDocument doc, } } - /* - * Restore initial state of viewCursor (possibly by restoring - * selection) if possible. - */ + /* Restore initial state of viewCursor (possibly by restoring selection) if possible. */ public void restore(XTextDocument doc) { FunctionalTextViewCursor.restore(doc, initialPosition, initialSelection); } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java index 35d2d006fab..9a3ef1c9968 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java @@ -19,7 +19,8 @@ private RangeOverlapBetween() { } /** * Check for any overlap between two sets of XTextRange values. * - * Assume fewHolders is small (usually 1 elements for checking the cursor) + * Assume fewHolders is small (usually a single element, for checking the cursor) + * * Returns on first problem found. */ public static @@ -34,16 +35,22 @@ List> findFirst(XTextDocument doc, return result; } - List> fewTuples = - new ArrayList<>(fewHolders.size()); - - for (V aHolder : fewHolders) { - XText aText = aHolder.getRange().getText(); - fewTuples.add(new OOTuple3<>(aText, - UnoCast.unoQI(XTextRangeCompare.class, aText), - aHolder)); + /* + * Cache all we need to know about fewHolders. We are trying to minimize the number of calls + * to LO. + */ + List> fewTuples = new ArrayList<>(fewHolders.size()); + + for (V aHolder : fewHolders) { + XText aText = aHolder.getRange().getText(); + fewTuples.add(new OOTuple3<>(aText, + UnoCast.cast(XTextRangeCompare.class, aText).get(), + aHolder)); } + /* + * We only go through manyHolders once: fewTuples is in the inner loop. + */ for (V bHolder : manyHolders) { XTextRange bRange = bHolder.getRange(); XText bText = bRange.getText(); @@ -58,25 +65,24 @@ List> findFirst(XTextDocument doc, if (aText != bText) { continue; } - int abEndToStart = -1 * cmp.compareRegionStarts(aRange.getEnd(), bRangeStart); + int abEndToStart = UnoTextRange.compareStartsUnsafe(cmp, aRange.getEnd(), bRangeStart); if (abEndToStart < 0 || (!includeTouching && (abEndToStart == 0))) { continue; } - int baEndToStart = -1 * cmp.compareRegionStarts(bRangeEnd, aRange.getStart()); + int baEndToStart = UnoTextRange.compareStartsUnsafe(cmp, bRangeEnd, aRange.getStart()); if (baEndToStart < 0 || (!includeTouching && (baEndToStart == 0))) { continue; } - boolean equal = UnoTextRange.compareStartsThenEnds(aRange, bRange) == 0; + boolean equal = UnoTextRange.compareStartsThenEndsUnsafe(cmp, aRange, bRange) == 0; boolean touching = (abEndToStart == 0 || baEndToStart == 0); - // In case of two equal collapsed ranges there is an - // ambiguity : TOUCH or EQUAL_RANGE ? + // In case of two equal collapsed ranges there is an ambiguity : TOUCH or EQUAL_RANGE ? + // // We return EQUAL_RANGE - RangeOverlapKind kind = - (equal ? RangeOverlapKind.EQUAL_RANGE - : (touching ? RangeOverlapKind.TOUCH - : RangeOverlapKind.OVERLAP)); + RangeOverlapKind kind = (equal ? RangeOverlapKind.EQUAL_RANGE + : (touching ? RangeOverlapKind.TOUCH + : RangeOverlapKind.OVERLAP)); List valuesForOverlappingRanges = new ArrayList<>(); valuesForOverlappingRanges.add(aHolder); diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java index 62ee6d82ca0..e4df2d8278c 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java @@ -15,17 +15,21 @@ public class RangeOverlapWithin { private RangeOverlapWithin() { } /** - * Report identical, overlapping or touching ranges between - * elements of rangeHolders. + * Report identical, overlapping or touching ranges between elements of rangeHolders. * - * For overlapping and touching, only report consecutive ranges - * and only with a single sample of otherwise identical ranges. + * For overlapping and touching, only report consecutive ranges and only with a single sample of + * otherwise identical ranges. + * + * @param rangeHolders represent the ranges to be checked. + * + * Note: for each rangeHolder, rangeHolder.getRange() is called multiple times. + * To avoid repeated work, they should keep a copy of the range instead of + * getting it each time from the document. * * @param reportAtMost Limit the number of records returned to atMost. * Zero {@code reportAtMost} means no limit. * - * @param includeTouching Should the result contain ranges - * sharing only a boundary? + * @param includeTouching Should the result contain ranges sharing only a boundary? */ public static List> findOverlappingRanges(XTextDocument doc, @@ -43,14 +47,13 @@ List> findOverlappingRanges(XTextDocument doc, /** * Report identical, overlapping or touching ranges. * - * For overlapping and touching, only report consecutive ranges - * and only with a single sample of otherwise identical ranges. + * For overlapping and touching, only report consecutive ranges and only with a single sample of + * otherwise identical ranges. * * @param atMost Limit the number of records returned to atMost. * Zero {@code atMost} means no limit. * - * @param includeTouching Should the result contain ranges - * sharing only a boundary? + * @param includeTouching Should the result contain ranges sharing only a boundary? */ public static List> findOverlappingRanges(RangeSort.RangePartitions input, @@ -64,8 +67,8 @@ List> findOverlappingRanges(RangeSort.RangePartitions input, if (partition.size() == 0) { continue; } - XTextRangeCompare cmp = UnoCast.unoQI(XTextRangeCompare.class, - partition.get(0).getRange().getText()); + XTextRangeCompare cmp = UnoCast.cast(XTextRangeCompare.class, + partition.get(0).getRange().getText()).get(); for (int i = 0; i < (partition.size() - 1); i++) { V aHolder = partition.get(i); diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java index f7fbe37ba25..e389c902b90 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java @@ -29,7 +29,12 @@ public boolean contains(XTextRange range) { return partitions.get(partitionKey).contains(range); } - /* return false if already contained */ + /* + * return false if already contained + * + * Beware: using UnoTextRange::compareStartsThenEnds as comparator involves range.getText() + * twice on each comparison. This makes it costly to use this class. + */ public boolean add(XTextRange range) { TreeSet partition = partitions.get(range.getText()); if (partition == null) { diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java index 2f5daa0e1aa..1b4fc327598 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java @@ -23,7 +23,7 @@ public static class HolderComparatorWithinPartition implements Comparator - void sortWithinPartition(List rangeHolders) { + /* + * Sort a list of RangeHolder values known to share the same getText(). + * + * Note: RangeHolder.getRange() is called many times. + */ + public static void sortWithinPartition(List rangeHolders) { if (rangeHolders.isEmpty()) { return; } @@ -70,8 +74,7 @@ public List> getPartitions() { } } - public static - RangePartitions partitionRanges(List holders) { + public static RangePartitions partitionRanges(List holders) { RangePartitions result = new RangePartitions<>(); for (V holder : holders) { result.add(holder); @@ -79,8 +82,10 @@ RangePartitions partitionRanges(List holders) { return result; } - public static - RangePartitions partitionAndSortRanges(List holders) { + /* + * Note: RangeHolder.getRange() is called many times. + */ + public static RangePartitions partitionAndSortRanges(List holders) { RangePartitions result = partitionRanges(holders); for (List partition : result.getPartitions()) { sortWithinPartition(partition); diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java index 2131c3cecb9..969f9fed44e 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java @@ -21,11 +21,10 @@ * * Requires functional XTextViewCursor. * - * Problem: for multicolumn layout and when viewing pages side-by-side - * in LO, the (top-down,left-to-right) order interpreted - * as-on-the-screen: an XTextRange at the top of the second - * column or second page is sorted before one at the bottom - * of the first column of the first page. + * Problem: for multicolumn layout and when viewing pages side-by-side in LO, the + * (top-down,left-to-right) order interpreted as-on-the-screen: an XTextRange at the top of + * the second column or second page is sorted before an XTextRange at the bottom of the + * first column of the first page. */ public class RangeSortVisual { @@ -36,8 +35,7 @@ public class RangeSortVisual { * * Requires a functional {@code XTextViewCursor}. * - * @return The input, sorted by the elements XTextRange and - * getIndexInPosition. + * @return The input, sorted by the elements XTextRange and getIndexInPosition. */ public static List> visualSort(List> inputs, XTextDocument doc, @@ -49,12 +47,9 @@ public static List> visualSort(List> input final int inputSize = inputs.size(); if (UnoScreenRefresh.hasControllersLocked(doc)) { - LOGGER.warn("visualSort:" - + " with ControllersLocked, viewCursor.gotoRange" - + " is probably useless"); - throw new RuntimeException("visualSort:" - + " with ControllersLocked, viewCursor.gotoRange" - + " is probably useless"); + final String msg = "visualSort: with ControllersLocked, viewCursor.gotoRange is probably useless"; + LOGGER.warn(msg); + throw new IllegalStateException(msg); } XTextViewCursor viewCursor = fcursor.getViewCursor(); @@ -62,13 +57,12 @@ public static List> visualSort(List> input // find coordinates List positions = new ArrayList<>(inputSize); for (RangeSortable v : inputs) { - positions.add(findPositionOfTextRange(v.getRange(), - viewCursor)); + positions.add(findPositionOfTextRange(v.getRange(), viewCursor)); } fcursor.restore(doc); if (positions.size() != inputSize) { - throw new RuntimeException("visualSort: positions.size() != inputSize"); + throw new IllegalStateException("visualSort: positions.size() != inputSize"); } // order by position @@ -82,7 +76,7 @@ public static List> visualSort(List> input Collections.sort(set); if (set.size() != inputSize) { - throw new RuntimeException("visualSort: set.size() != inputSize"); + throw new IllegalStateException("visualSort: set.size() != inputSize"); } // collect ordered result @@ -92,26 +86,24 @@ public static List> visualSort(List> input } if (result.size() != inputSize) { - throw new RuntimeException("visualSort: result.size() != inputSize"); + throw new IllegalStateException("visualSort: result.size() != inputSize"); } return result; } /** - * Given a location, return its position: coordinates relative to - * the top left position of the first page of the document. + * Given a location, return its position: coordinates relative to the top left position of the + * first page of the document. * - * Note: for text layouts with two or more columns, this gives the - * wrong order: top-down/left-to-right does not match - * reading order. + * Note: for text layouts with two or more columns, this gives the wrong order: + * top-down/left-to-right does not match reading order. * - * Note: The "relative to the top left position of the first page" - * is meant "as it appears on the screen". + * Note: The "relative to the top left position of the first page" is meant "as it appears on + * the screen". * - * In particular: when viewing pages side-by-side, the top - * half of the right page is higher than the lower half of - * the left page. Again, top-down/left-to-right does not + * In particular: when viewing pages side-by-side, the top half of the right page is + * higher than the lower half of the left page. Again, top-down/left-to-right does not * match reading order. * * @param range Location. @@ -126,8 +118,8 @@ private static Point findPositionOfTextRange(XTextRange range, XTextViewCursor c /** * A reference mark name paired with its visual position. * - * Comparison is based on (Y,X,indexInPosition): vertical compared - * first, horizontal second, indexInPosition third. + * Comparison is based on (Y,X,indexInPosition): vertical compared first, horizontal second, + * indexInPosition third. * * Used for sorting reference marks by their visual positions. */ diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java index 66e17a5b35b..c3eab225889 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java @@ -9,14 +9,12 @@ public interface RangeSortable extends RangeHolder { /** The XTextRange * - * For citation marks in footnotes this may be the range of the - * footnote mark. + * For citation marks in footnotes this may be the range of the footnote mark. */ public XTextRange getRange(); /** - * For citation marks in footnotes this may provide order within - * the footnote. + * For citation marks in footnotes this may provide order within the footnote. */ public int getIndexInPosition(); diff --git a/src/main/java/org/jabref/model/openoffice/style/Citation.java b/src/main/java/org/jabref/model/openoffice/style/Citation.java index f0b732a9240..3f949237e07 100644 --- a/src/main/java/org/jabref/model/openoffice/style/Citation.java +++ b/src/main/java/org/jabref/model/openoffice/style/Citation.java @@ -112,7 +112,7 @@ public void setUniqueLetter(Optional uniqueLetter) { public void setPageInfo(Optional v) { Optional vv = PageInfo.normalizePageInfo(v); if (!vv.equals(v)) { - throw new RuntimeException("setPageInfo argument is not normalized"); + throw new IllegalArgumentException("setPageInfo argument is not normalized"); } this.pageInfo = vv; } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java index 075c55cc2ef..2986a6f4501 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java @@ -36,15 +36,14 @@ public class CitationGroup { * A name of a reference mark to link to by formatCitedOnPages. * May be initially empty, if backend does not use reference marks. * - * produceCitationMarkers might want fill it to support - * cross-references to citation groups from the bibliography. + * produceCitationMarkers might want fill it to support cross-references to citation groups from + * the bibliography. */ private Optional referenceMarkNameForLinking; /* - * Indices into citations: citations[localOrder[i]] provides ith - * citation according to the currently imposed local order for - * presentation. + * Indices into citations: citations[localOrder[i]] provides ith citation according to the + * currently imposed local order for presentation. * * Initialized to (0..(nCitations-1)) in the constructor. */ diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java index bac1e3c1387..6ba6b760cb6 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java @@ -10,8 +10,7 @@ public CitationGroupId(String id) { } /** - * CitationEntry needs some string identifying the group - * that it can pass back later. + * CitationEntry needs some string identifying the group that it can pass back later. */ public String citationGroupIdAsString() { return id; diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java index f68aa4f115c..bd0cca64e13 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java @@ -20,8 +20,7 @@ /** * CitationGroups : the set of citation groups in the document. * - * This is the main input (as well as output) for creating citation - * markers and bibliography. + * This is the main input (as well as output) for creating citation markers and bibliography. * */ public class CitationGroups { @@ -56,8 +55,7 @@ public int numberOfCitationGroups() { } /** - * For each citation in {@code where} - * call {@code fun.accept(new Pair(citation, value));} + * For each citation in {@code where} call {@code fun.accept(new Pair(citation, value));} */ public void distributeToCitations(List where, Consumer> fun, @@ -84,21 +82,19 @@ public void lookupCitations(List databases) { if (true) { // collect-lookup-distribute // - // CitationDatabaseLookupResult for the same citation key - // is the same object. Until we insert a new citation from the GUI. + // CitationDatabaseLookupResult for the same citation key is the same object. Until we + // insert a new citation from the GUI. CitedKeys cks = getCitedKeysUnordered(); cks.lookupInDatabases(databases); cks.distributeLookupResults(this); } else { // lookup each citation directly // - // CitationDatabaseLookupResult for the same citation key - // may be a different object: CitedKey.addPath has to use equals, - // so CitationDatabaseLookupResult has to override Object.equals, - // which depends on BibEntry.equals and BibDatabase.equals - // doing the right thing. Seems to work. But what we gained - // from avoiding collect-and-distribute may be lost in more - // complicated consistency checking in addPath. + // CitationDatabaseLookupResult for the same citation key may be a different object: + // CitedKey.addPath has to use equals, so CitationDatabaseLookupResult has to override + // Object.equals, which depends on BibEntry.equals and BibDatabase.equals doing the + // right thing. Seems to work. But what we gained from avoiding collect-and-distribute + // may be lost in more complicated consistency checking in addPath. // for (CitationGroup cg : getCitationGroupsUnordered()) { for (Citation cit : cg.citationsInStorageOrder) { @@ -117,22 +113,21 @@ public List getCitationGroupsUnordered() { */ public List getCitationGroupsInGlobalOrder() { if (globalOrder.isEmpty()) { - throw new RuntimeException("getCitationGroupsInGlobalOrder: not ordered yet"); + throw new IllegalStateException("getCitationGroupsInGlobalOrder: not ordered yet"); } return OOListUtil.map(globalOrder.get(), cgid -> citationGroupsUnordered.get(cgid)); } /** - * Impose an order of citation groups by providing the order - * of their citation group idendifiers. + * Impose an order of citation groups by providing the order of their citation group + * idendifiers. * * Also set indexInGlobalOrder for each citation group. */ public void setGlobalOrder(List globalOrder) { Objects.requireNonNull(globalOrder); if (globalOrder.size() != numberOfCitationGroups()) { - throw new RuntimeException("setGlobalOrder:" - + " globalOrder.size() != numberOfCitationGroups()"); + throw new IllegalStateException("setGlobalOrder: globalOrder.size() != numberOfCitationGroups()"); } this.globalOrder = Optional.of(globalOrder); @@ -158,8 +153,8 @@ public void imposeLocalOrder(Comparator entryComparator) { } /** - * Collect citations into a list of cited sources using neither - * CitationGroup.globalOrder or Citation.localOrder + * Collect citations into a list of cited sources using neither CitationGroup.globalOrder or + * Citation.localOrder */ public CitedKeys getCitedKeysUnordered() { LinkedHashMap res = new LinkedHashMap<>(); @@ -185,7 +180,7 @@ public CitedKeys getCitedKeysUnordered() { public CitedKeys getCitedKeysSortedInOrderOfAppearance() { LinkedHashMap res = new LinkedHashMap<>(); if (!hasGlobalOrder()) { - throw new RuntimeException("getSortedCitedKeys: no globalOrder"); + throw new IllegalStateException("getSortedCitedKeys: no globalOrder"); } for (CitationGroup cg : getCitationGroupsInGlobalOrder()) { for (int i : cg.getLocalOrder()) { @@ -224,8 +219,8 @@ public List getUnresolvedKeys() { public void createNumberedBibliographySortedInOrderOfAppearance() { if (!bibliography.isEmpty()) { - throw new RuntimeException("createNumberedBibliographySortedInOrderOfAppearance:" - + " already have a bibliography"); + throw new IllegalStateException("createNumberedBibliographySortedInOrderOfAppearance:" + + " already have a bibliography"); } CitedKeys citedKeys = getCitedKeysSortedInOrderOfAppearance(); citedKeys.numberCitedKeysInCurrentOrder(); @@ -238,8 +233,7 @@ public void createNumberedBibliographySortedInOrderOfAppearance() { */ public void createPlainBibliographySortedByComparator(Comparator entryComparator) { if (!bibliography.isEmpty()) { - throw new RuntimeException("createPlainBibliographySortedByComparator:" - + " already have a bibliography"); + throw new IllegalStateException("createPlainBibliographySortedByComparator: already have a bibliography"); } CitedKeys citedKeys = getCitedKeysUnordered(); citedKeys.sortByComparator(entryComparator); @@ -251,8 +245,7 @@ public void createPlainBibliographySortedByComparator(Comparator entry */ public void createNumberedBibliographySortedByComparator(Comparator entryComparator) { if (!bibliography.isEmpty()) { - throw new RuntimeException("createNumberedBibliographySortedByComparator:" - + " already have a bibliography"); + throw new IllegalStateException("createNumberedBibliographySortedByComparator: already have a bibliography"); } CitedKeys citedKeys = getCitedKeysUnordered(); citedKeys.sortByComparator(entryComparator); @@ -270,18 +263,6 @@ public Optional getCitationGroup(CitationGroupId cgid) { return Optional.ofNullable(cg); } - /** - * Call this when the citation group is unquestionably there. - */ - public CitationGroup getCitationGroupOrThrow(CitationGroupId cgid) { - CitationGroup cg = citationGroupsUnordered.get(cgid); - if (cg == null) { - throw new RuntimeException("getCitationGroupOrThrow:" - + " the requested CitationGroup is not available"); - } - return cg; - } - /* * @return true if all citation groups have referenceMarkNameForLinking */ diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java b/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java index 866a0de34c3..b17ec100ee2 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java @@ -23,8 +23,7 @@ public CitationLookupResult(BibEntry entry, BibDatabase database) { * Consequently, {@code this.database.equals(that.database)} below * is equivalent to {@code this.database == that.database}. * - * Since within each GUI call we use a fixed list of - * databases, it is OK. + * Since within each GUI call we use a fixed list of databases, it is OK. */ @Override public boolean equals(Object o) { diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationMarkerEntry.java b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerEntry.java index 4ab2c626b68..5fcb9bcc1a8 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationMarkerEntry.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerEntry.java @@ -5,8 +5,7 @@ import org.jabref.model.openoffice.ootext.OOText; /** - * This is what we need for createCitationMarker to produce author-year - * citation markers. + * This is what we need for createCitationMarker to produce author-year citation markers. */ public interface CitationMarkerEntry extends CitationMarkerNormEntry { @@ -17,14 +16,13 @@ public interface CitationMarkerEntry extends CitationMarkerNormEntry { /** * pageInfo for this citation, provided by the user. - * May be empty, for none. + * May be empty, for none. */ Optional getPageInfo(); /** - * @return true if this citation is the first appearance of the - * source cited. Some styles use different limit on the number of - * authors shown in this case. + * @return true if this citation is the first appearance of the source cited. Some styles use + * different limit on the number of authors shown in this case. */ boolean getIsFirstAppearanceOfSource(); } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNormEntry.java b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNormEntry.java index e9df5ec961f..a2581b38b60 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNormEntry.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNormEntry.java @@ -3,16 +3,13 @@ import java.util.Optional; /** - * This is what we need to produce normalized author-year citation - * markers. + * This is what we need to produce normalized author-year citation markers. */ public interface CitationMarkerNormEntry { /** Citation key. This is what we usually get from the document. * - * Used if getBibEntry() and/or getDatabase() returns - * empty, which indicates failure to lookup in the databases. - * + * Used if getLookupResult() returns empty, which indicates failure to lookup in the databases. */ String getCitationKey(); diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationPath.java b/src/main/java/org/jabref/model/openoffice/style/CitationPath.java index 05aeb6547f6..0920ea20feb 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationPath.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationPath.java @@ -1,8 +1,8 @@ package org.jabref.model.openoffice.style; /** - * Identifies a citation with the citation group containing it and - * its storage index within. + * Identifies a citation with the identifier of the citation group containing it and its storage + * index within. */ public class CitationPath { diff --git a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java index 08b2ffb1bb8..f577867c539 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java @@ -11,9 +11,8 @@ /** * Cited keys are collected from the citations in citation groups. * - * They contain backreferences to the corresponding citations in - * {@code where}. This allows the extra information generated using - * CitedKeys to be distributed back to the in-text citations. + * They contain backreferences to the corresponding citations in {@code where}. This allows the + * extra information generated using CitedKeys to be distributed back to the in-text citations. */ public class CitedKey implements ComparableCitedKey, @@ -106,13 +105,13 @@ void addPath(CitationPath p, Citation cit) { // Check consistency if (!cit.getLookupResult().equals(this.db)) { - throw new RuntimeException("CitedKey.addPath: mismatch on cit.db"); + throw new IllegalStateException("CitedKey.addPath: mismatch on cit.db"); } if (!cit.getNumber().equals(this.number)) { - throw new RuntimeException("CitedKey.addPath: mismatch on cit.number"); + throw new IllegalStateException("CitedKey.addPath: mismatch on cit.number"); } if (!cit.getUniqueLetter().equals(this.uniqueLetter)) { - throw new RuntimeException("CitedKey.addPath: mismatch on cit.uniqueLetter"); + throw new IllegalStateException("CitedKey.addPath: mismatch on cit.uniqueLetter"); } } diff --git a/src/main/java/org/jabref/model/openoffice/style/CompareCitation.java b/src/main/java/org/jabref/model/openoffice/style/CompareCitation.java index 916f8ec610c..966715b11a8 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CompareCitation.java +++ b/src/main/java/org/jabref/model/openoffice/style/CompareCitation.java @@ -5,8 +5,8 @@ import org.jabref.model.entry.BibEntry; /* - * Given a Comparator provide a Comparator - * that can handle unresolved citation keys and takes pageInfo into account. + * Given a Comparator provide a Comparator that can handle unresolved + * citation keys and takes pageInfo into account. */ public class CompareCitation implements Comparator { diff --git a/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java b/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java index 439d0556c2d..a5484560316 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java +++ b/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java @@ -6,8 +6,8 @@ import org.jabref.model.entry.BibEntry; /* - * Given a Comparator provide a Comparator - * that also handles unresolved citation keys. + * Given a Comparator provide a Comparator that also handles + * unresolved citation keys. */ public class CompareCitedKey implements Comparator { diff --git a/src/main/java/org/jabref/model/openoffice/style/NonUniqueCitationMarker.java b/src/main/java/org/jabref/model/openoffice/style/NonUniqueCitationMarker.java index e7d988ee216..34300734d2f 100644 --- a/src/main/java/org/jabref/model/openoffice/style/NonUniqueCitationMarker.java +++ b/src/main/java/org/jabref/model/openoffice/style/NonUniqueCitationMarker.java @@ -1,15 +1,15 @@ package org.jabref.model.openoffice.style; /** - * What should createCitationMarker do if it discovers that - * uniqueLetters provided are not sufficient for unique presentation? + * What should createCitationMarker do if it discovers that uniqueLetters provided are not + * sufficient for unique presentation? */ public enum NonUniqueCitationMarker { /** Give an insufficient representation anyway. */ FORGIVEN, - /** Throw a RuntimeException */ + /** Throw an exception */ THROWS } diff --git a/src/main/java/org/jabref/model/openoffice/style/OODataModel.java b/src/main/java/org/jabref/model/openoffice/style/OODataModel.java index 50c3a9e4842..20b2365ebf2 100644 --- a/src/main/java/org/jabref/model/openoffice/style/OODataModel.java +++ b/src/main/java/org/jabref/model/openoffice/style/OODataModel.java @@ -9,19 +9,15 @@ /** What is the data stored? */ public enum OODataModel { - /** - * JabRef52: pageInfo belongs to CitationGroup, not Citation. - */ + /** JabRef52: pageInfo belongs to CitationGroup, not Citation. */ JabRef52, - /** - * JabRef53: pageInfo belongs to Citation. - */ - JabRef53; + /** JabRef60: pageInfo belongs to Citation. */ + JabRef60; /** * @param pageInfo Nullable. - * @return JabRef53 style pageInfo list with pageInfo in the last slot. + * @return JabRef60 style pageInfo list with pageInfo in the last slot. */ public static List> fakePageInfos(String pageInfo, int nCitations) { List> pageInfos = new ArrayList<>(nCitations); diff --git a/src/main/java/org/jabref/model/openoffice/style/PageInfo.java b/src/main/java/org/jabref/model/openoffice/style/PageInfo.java index 6807ecf0753..ace7eedae02 100644 --- a/src/main/java/org/jabref/model/openoffice/style/PageInfo.java +++ b/src/main/java/org/jabref/model/openoffice/style/PageInfo.java @@ -42,6 +42,6 @@ public static int comparePageInfo(Optional a, Optional b) { if (bb.isEmpty()) { return +1; } - return aa.get().asString().compareTo(bb.get().asString()); + return aa.get().toString().compareTo(bb.get().toString()); } } 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 b97618a3231..fdbbb0dd1c6 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoBookmark.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoBookmark.java @@ -6,7 +6,6 @@ import com.sun.star.container.XNameAccess; import com.sun.star.container.XNamed; import com.sun.star.lang.DisposedException; -import com.sun.star.lang.IllegalArgumentException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XBookmarksSupplier; import com.sun.star.text.XTextContent; @@ -24,7 +23,7 @@ public static XNameAccess getNameAccess(XTextDocument doc) throws NoDocumentException { - XBookmarksSupplier supplier = UnoCast.unoQI(XBookmarksSupplier.class, doc); + XBookmarksSupplier supplier = UnoCast.cast(XBookmarksSupplier.class, doc).get(); try { return supplier.getBookmarks(); } catch (DisposedException ex) { @@ -44,45 +43,36 @@ public static Optional getAnchor(XTextDocument doc, String name) NoDocumentException { XNameAccess nameAccess = getNameAccess(doc); - return (UnoNameAccess.getTextContentByName(nameAccess, name) - .map(e -> e.getAnchor())); + return (UnoNameAccess.getTextContentByName(nameAccess, name).map(XTextContent::getAnchor)); } /** - * Insert a bookmark with the given name at the cursor provided, - * or with another name if the one we asked for is already in use. + * Insert a bookmark with the given name at the cursor provided, or with another name if the one + * we asked for is already in use. * * 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 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. + * 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) throws - IllegalArgumentException, CreationException { - return UnoNamed.insertNamedTextContent(doc, - "com.sun.star.text.Bookmark", - name, - range, - absorb); + return UnoNamed.insertNamedTextContent(doc, "com.sun.star.text.Bookmark", name, range, absorb); } /** * Remove the named bookmark if it exists. */ - public static void remove(XTextDocument doc, String name) + public static void removeIfExists(XTextDocument doc, String name) throws NoDocumentException, - NoSuchElementException, WrappedTargetException { XNameAccess marks = UnoBookmark.getNameAccess(doc); @@ -92,7 +82,11 @@ public static void remove(XTextDocument doc, String name) if (mark.isEmpty()) { return; } - doc.getText().removeTextContent(mark.get()); + try { + doc.getText().removeTextContent(mark.get()); + } catch (NoSuchElementException ex) { + // The caller gets what it expects. + } } } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoCast.java b/src/main/java/org/jabref/model/openoffice/uno/UnoCast.java index df5be51db36..fcc1bcc3e12 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoCast.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoCast.java @@ -9,16 +9,11 @@ public class UnoCast { private UnoCast() { } /** - * unoQI : short for UnoRuntime.queryInterface + * cast : short for Optional.ofNullable(UnoRuntime.queryInterface(...)) * - * @return A reference to the requested UNO interface type if available, - * otherwise null + * @return A reference to the requested UNO interface type if available, otherwise Optional.empty() */ - public static T unoQI(Class zInterface, Object object) { - return UnoRuntime.queryInterface(zInterface, object); - } - - public static Optional optUnoQI(Class zInterface, Object object) { + public static Optional cast(Class zInterface, Object object) { return Optional.ofNullable(UnoRuntime.queryInterface(zInterface, object)); } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoCrossRef.java b/src/main/java/org/jabref/model/openoffice/uno/UnoCrossRef.java index 0e8b84e8d22..37dc580a1fb 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoCrossRef.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoCrossRef.java @@ -21,53 +21,67 @@ private UnoCrossRef() { } */ public static void refresh(XTextDocument doc) { // Refresh the document - XRefreshable xRefresh = UnoCast.unoQI(XRefreshable.class, doc); + XRefreshable xRefresh = UnoCast.cast(XRefreshable.class, doc).get(); xRefresh.refresh(); } /** - * Insert a clickable cross-reference to a reference mark, - * with a label containing the target's page number. + * Insert a clickable cross-reference to a reference mark, with a label containing the target's + * page number. * - * May need a documentConnection.refresh() after, to update - * the text shown. + * May need a documentConnection.refresh() after, to update the text shown. */ public static void insertReferenceToPageNumberOfReferenceMark(XTextDocument doc, String referenceMarkName, XTextRange cursor) throws CreationException, - UnknownPropertyException, - PropertyVetoException, WrappedTargetException { // based on: https://wiki.openoffice.org/wiki/Documentation/DevGuide/Text/Reference_Marks - XMultiServiceFactory msf = UnoCast.unoQI(XMultiServiceFactory.class, doc); + XMultiServiceFactory msf = UnoCast.cast(XMultiServiceFactory.class, doc).get(); // Create a 'GetReference' text field to refer to the reference mark we just inserted, // and get it's XPropertySet interface XPropertySet xFieldProps; try { String name = "com.sun.star.text.textfield.GetReference"; - xFieldProps = (XPropertySet) UnoCast.unoQI(XPropertySet.class, - msf.createInstance(name)); - } catch (Exception e) { + xFieldProps = UnoCast.cast(XPropertySet.class, msf.createInstance(name)).get(); + } catch (com.sun.star.uno.Exception e) { throw new CreationException(e.getMessage()); } - // Set the SourceName of the GetReference text field to the referenceMarkName - xFieldProps.setPropertyValue("SourceName", referenceMarkName); + try { + // Set the SourceName of the GetReference text field to the referenceMarkName + xFieldProps.setPropertyValue("SourceName", referenceMarkName); + } catch (UnknownPropertyException ex) { + throw new java.lang.IllegalStateException("The created GetReference does not have property 'SourceName'"); + } catch (PropertyVetoException ex) { + throw new java.lang.IllegalStateException("Caught PropertyVetoException on 'SourceName'"); + } - // specify that the source is a reference mark (could also be a footnote, - // bookmark or sequence field) - xFieldProps.setPropertyValue("ReferenceFieldSource", - new Short(ReferenceFieldSource.REFERENCE_MARK)); + try { + // specify that the source is a reference mark (could also be a footnote, + // bookmark or sequence field) + xFieldProps.setPropertyValue("ReferenceFieldSource", Short.valueOf​(ReferenceFieldSource.REFERENCE_MARK)); + } catch (UnknownPropertyException ex) { + throw new java.lang.IllegalStateException("The created GetReference does not have property" + + " 'ReferenceFieldSource'"); + } catch (PropertyVetoException ex) { + throw new java.lang.IllegalStateException("Caught PropertyVetoException on 'ReferenceFieldSource'"); + } - // We want the reference displayed as page number - xFieldProps.setPropertyValue("ReferenceFieldPart", - new Short(ReferenceFieldPart.PAGE)); + try { + // We want the reference displayed as page number + xFieldProps.setPropertyValue("ReferenceFieldPart", Short.valueOf​(ReferenceFieldPart.PAGE)); + } catch (UnknownPropertyException ex) { + throw new java.lang.IllegalStateException("The created GetReference does not have property" + + " 'ReferenceFieldPart'"); + } catch (PropertyVetoException ex) { + throw new java.lang.IllegalStateException("Caught PropertyVetoException on 'ReferenceFieldPart'"); + } // Get the XTextContent interface of the GetReference text field - XTextContent xRefContent = (XTextContent) UnoCast.unoQI(XTextContent.class, xFieldProps); + XTextContent xRefContent = UnoCast.cast(XTextContent.class, xFieldProps).get(); // Insert the text field cursor.getText().insertTextContent(cursor.getEnd(), xRefContent, false); diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java b/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java index b7115feb8e1..1770b6957c5 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java @@ -18,8 +18,8 @@ private UnoCursor() { } */ public static Optional getViewCursor(XTextDocument doc) { return (UnoTextDocument.getCurrentController(doc) - .flatMap(e -> UnoCast.optUnoQI(XTextViewCursorSupplier.class, e)) - .map(e -> e.getViewCursor())); + .flatMap(e -> UnoCast.cast(XTextViewCursorSupplier.class, e)) + .map(XTextViewCursorSupplier::getViewCursor)); } /** diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoNameAccess.java b/src/main/java/org/jabref/model/openoffice/uno/UnoNameAccess.java index 3d172d11f14..243c136f382 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoNameAccess.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoNameAccess.java @@ -12,14 +12,13 @@ public class UnoNameAccess { private UnoNameAccess() { } /** - * @return null if name not found, or if the result does not - * support the XTextContent interface. + * @return null if name not found, or if the result does not support the XTextContent interface. */ public static Optional getTextContentByName(XNameAccess nameAccess, String name) throws WrappedTargetException { try { - return UnoCast.optUnoQI(XTextContent.class, nameAccess.getByName(name)); + return UnoCast.cast(XTextContent.class, nameAccess.getByName(name)); } catch (NoSuchElementException ex) { return Optional.empty(); } 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 d99b6702153..5f1f50c873d 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoNamed.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoNamed.java @@ -11,30 +11,24 @@ public class UnoNamed { private UnoNamed() { } /** - * Insert a new instance of a service at the provided cursor - * position. + * Insert a new instance of a service at the provided cursor position. * * @param service For example - * "com.sun.star.text.ReferenceMark", - * "com.sun.star.text.Bookmark" or - * "com.sun.star.text.TextSection". + * "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. + * 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 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 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. + * @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. * @@ -47,20 +41,22 @@ static XNamed insertNamedTextContent(XTextDocument doc, throws CreationException { - XMultiServiceFactory msf = UnoCast.unoQI(XMultiServiceFactory.class, doc); + XMultiServiceFactory msf = UnoCast.cast(XMultiServiceFactory.class, doc).get(); Object xObject; try { xObject = msf.createInstance(service); - } catch (Exception e) { + } catch (com.sun.star.uno.Exception e) { throw new CreationException(e.getMessage()); } - XNamed xNamed = UnoCast.unoQI(XNamed.class, xObject); + XNamed xNamed = (UnoCast.cast(XNamed.class, xObject) + .orElseThrow(() -> new IllegalArgumentException("Service is not an XNamed"))); xNamed.setName(name); // get XTextContent interface - XTextContent xTextContent = UnoCast.unoQI(XTextContent.class, xObject); + XTextContent xTextContent = (UnoCast.cast(XTextContent.class, xObject) + .orElseThrow(() -> new IllegalArgumentException("Service is not an XTextContent"))); range.getText().insertTextContent(range, xTextContent, absorb); return xNamed; } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java b/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java index 07a6de1374d..3a47818cf8b 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java @@ -26,7 +26,7 @@ private UnoProperties() { } */ public static Optional asPropertySet(XPropertyContainer propertyContainer) { - return UnoCast.optUnoQI(XPropertySet.class, propertyContainer); + return UnoCast.cast(XPropertySet.class, propertyContainer); } /* diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoRedlines.java b/src/main/java/org/jabref/model/openoffice/uno/UnoRedlines.java index a5f5ce7c6d1..2c408648d6f 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoRedlines.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoRedlines.java @@ -1,5 +1,7 @@ package org.jabref.model.openoffice.uno; +import java.util.Optional; + import com.sun.star.beans.UnknownPropertyException; import com.sun.star.beans.XPropertySet; import com.sun.star.container.NoSuchElementException; @@ -16,25 +18,30 @@ public class UnoRedlines { public static boolean getRecordChanges(XTextDocument doc) throws - UnknownPropertyException, WrappedTargetException { // https://wiki.openoffice.org/wiki/Documentation/DevGuide/Text/Settings // "Properties of com.sun.star.text.TextDocument" - XPropertySet propertySet = (UnoCast.optUnoQI(XPropertySet.class, doc) - .orElseThrow(RuntimeException::new)); + XPropertySet propertySet = UnoCast.cast(XPropertySet.class, doc).get(); - return (boolean) propertySet.getPropertyValue("RecordChanges"); + try { + return (boolean) propertySet.getPropertyValue("RecordChanges"); + } catch (UnknownPropertyException ex) { + throw new java.lang.IllegalStateException("Caught UnknownPropertyException on 'RecordChanges'"); + } } - private static XRedlinesSupplier getRedlinesSupplier(XTextDocument doc) { - return UnoCast.unoQI(XRedlinesSupplier.class, doc); + private static Optional getRedlinesSupplier(XTextDocument doc) { + return UnoCast.cast(XRedlinesSupplier.class, doc); } public static int countRedlines(XTextDocument doc) { - XRedlinesSupplier supplier = getRedlinesSupplier(doc); - XEnumerationAccess enumerationAccess = supplier.getRedlines(); + Optional supplier = getRedlinesSupplier(doc); + if (supplier.isEmpty()) { + return 0; + } + XEnumerationAccess enumerationAccess = supplier.get().getRedlines(); XEnumeration enumeration = enumerationAccess.createEnumeration(); if (enumeration == null) { return 0; 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 8185c1ffbe3..7a719042d79 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoReferenceMark.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoReferenceMark.java @@ -22,15 +22,14 @@ private UnoReferenceMark() { } /** * @throws NoDocumentException If cannot get reference marks * - * Note: also used by `isDocumentConnectionMissing` to test if - * we have a working connection. + * Note: also used by `isDocumentConnectionMissing` to test if we have a working connection. * */ public static XNameAccess getNameAccess(XTextDocument doc) throws NoDocumentException { - XReferenceMarksSupplier supplier = UnoCast.unoQI(XReferenceMarksSupplier.class, doc); + XReferenceMarksSupplier supplier = UnoCast.cast(XReferenceMarksSupplier.class, doc).get(); try { return supplier.getReferenceMarks(); @@ -60,11 +59,10 @@ public static List getListOfNames(XTextDocument doc) * * Removes both the text and the mark itself. */ - public static void remove(XTextDocument doc, String name) + public static void removeIfExists(XTextDocument doc, String name) throws WrappedTargetException, - NoDocumentException, - NoSuchElementException { + NoDocumentException { XNameAccess xReferenceMarks = UnoReferenceMark.getNameAccess(doc); @@ -73,7 +71,11 @@ public static void remove(XTextDocument doc, String name) if (mark.isEmpty()) { return; } - doc.getText().removeTextContent(mark.get()); + try { + doc.getText().removeTextContent(mark.get()); + } catch (NoSuchElementException ex) { + // The caller gets what it expects. + } } } @@ -97,37 +99,27 @@ public static Optional getAnchor(XTextDocument doc, String name) NoDocumentException, WrappedTargetException { return (UnoReferenceMark.getAsTextContent(doc, name) - .map(e -> e.getAnchor())); + .map(XTextContent::getAnchor)); } /** - * Insert a new reference mark at the provided cursor - * position. + * 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 absorb} 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. + * 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. + * @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(XTextDocument doc, String name, XTextRange range, boolean absorb) throws CreationException { - return UnoNamed.insertNamedTextContent(doc, - "com.sun.star.text.ReferenceMark", - name, - range, - absorb); + return UnoNamed.insertNamedTextContent(doc, "com.sun.star.text.ReferenceMark", name, range, absorb); } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoSelection.java b/src/main/java/org/jabref/model/openoffice/uno/UnoSelection.java index 0ef750b9983..43d89ed157b 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoSelection.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoSelection.java @@ -29,12 +29,12 @@ private static Optional getSelectionSupplier(XTextDocument d LOGGER.warn("UnoSelection.getSelectionSupplier: getCurrentController(doc) returned empty"); return Optional.empty(); } - XSelectionSupplier supplier = UnoCast.unoQI(XSelectionSupplier.class, controller.get()); - if (supplier == null) { - LOGGER.warn("UnoSelection.getSelectionSupplier: unoQI(XSelectionSupplier) returned null"); + Optional supplier = UnoCast.cast(XSelectionSupplier.class, controller.get()); + if (supplier.isEmpty()) { + LOGGER.warn("UnoSelection.getSelectionSupplier: cast to XSelectionSupplier returned empty"); return Optional.empty(); } - return Optional.of(supplier); + return supplier; } /** @@ -91,12 +91,12 @@ public static Optional getSelectionAsXServiceInfo(XTextDocument do if (selection == null) { return Optional.empty(); } - XServiceInfo result = UnoCast.unoQI(XServiceInfo.class, selection); - if (result == null) { - LOGGER.warn("unoQI(XServiceInfo) returned null"); + Optional result = UnoCast.cast(XServiceInfo.class, selection); + if (result.isEmpty()) { + LOGGER.warn("cast to XServiceInfo returned empty"); return Optional.empty(); } - return Optional.of(result); + return result; } /** diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java b/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java index 86222872597..dece8978713 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java @@ -20,26 +20,23 @@ public class UnoStyle { private UnoStyle() { } - private static Optional getStyleFromFamily(XTextDocument doc, - String familyName, - String styleName) + private static Optional getStyleFromFamily(XTextDocument doc, String familyName, String styleName) throws WrappedTargetException { - XStyleFamiliesSupplier fss = UnoCast.unoQI(XStyleFamiliesSupplier.class, doc); - XNameAccess fs = UnoCast.unoQI(XNameAccess.class, fss.getStyleFamilies()); + XStyleFamiliesSupplier fss = UnoCast.cast(XStyleFamiliesSupplier.class, doc).get(); + XNameAccess fs = UnoCast.cast(XNameAccess.class, fss.getStyleFamilies()).get(); XNameContainer xFamily; try { - xFamily = UnoCast.unoQI(XNameContainer.class, fs.getByName(familyName)); + xFamily = UnoCast.cast(XNameContainer.class, fs.getByName(familyName)).get(); } catch (NoSuchElementException ex) { String msg = String.format("Style family name '%s' is not recognized", familyName); - throw new RuntimeException(msg, ex); + throw new java.lang.IllegalArgumentException(msg, ex); } try { - Object s = xFamily.getByName(styleName); - XStyle xs = (XStyle) UnoCast.unoQI(XStyle.class, s); - return Optional.ofNullable(xs); + Object style = xFamily.getByName(styleName); + return UnoCast.cast(XStyle.class, style); } catch (NoSuchElementException ex) { return Optional.empty(); } @@ -62,7 +59,7 @@ public static Optional getInternalNameOfStyle(XTextDocument doc, String throws WrappedTargetException { return (getStyleFromFamily(doc, familyName, name) - .map(e -> e.getName())); + .map(XStyle::getName)); } public static Optional getInternalNameOfParagraphStyle(XTextDocument doc, String name) diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoTextDocument.java b/src/main/java/org/jabref/model/openoffice/uno/UnoTextDocument.java index 188a092465a..c7e94e6bb4c 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoTextDocument.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoTextDocument.java @@ -59,19 +59,18 @@ public static Optional getCurrentController(XTextDocument doc) { */ public static Optional getFrameTitle(XTextDocument doc) { - Optional frame = getCurrentController(doc).map(e -> e.getFrame()); + Optional frame = getCurrentController(doc).map(XController::getFrame); if (frame.isEmpty()) { return Optional.empty(); } - Optional propertySet = UnoCast.optUnoQI(XPropertySet.class, frame.get()); + Optional propertySet = UnoCast.cast(XPropertySet.class, frame.get()); if (propertySet.isEmpty()) { return Optional.empty(); } try { - Optional frameTitleObj = - UnoProperties.getValueAsObject(propertySet.get(), "Title"); + Optional frameTitleObj = UnoProperties.getValueAsObject(propertySet.get(), "Title"); if (frameTitleObj.isEmpty()) { return Optional.empty(); } @@ -85,8 +84,8 @@ public static Optional getFrameTitle(XTextDocument doc) { static Optional getDocumentProperties(XTextDocument doc) { return (Optional.ofNullable(doc) - .map(e -> UnoCast.unoQI(XDocumentPropertiesSupplier.class, e)) - .map(e -> e.getDocumentProperties())); + .flatMap(e -> UnoCast.cast(XDocumentPropertiesSupplier.class, e)) + .map(XDocumentPropertiesSupplier::getDocumentProperties)); } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java b/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java index b44ed6ce38b..56cb1498e2a 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java @@ -17,12 +17,12 @@ private UnoTextRange() { } * Returns Optional.empty if not in a footnote. */ public static Optional getFootnoteMarkRange(XTextRange original) { - XFootnote footer = UnoCast.unoQI(XFootnote.class, original.getText()); - if (footer != null) { + Optional footer = UnoCast.cast(XFootnote.class, original.getText()); + if (footer.isPresent()) { // If we are inside a footnote, // find the linking footnote marker: // The footnote's anchor gives the correct position in the text: - return Optional.ofNullable(footer.getAnchor()); + return Optional.ofNullable(footer.get().getAnchor()); } return Optional.empty(); } @@ -46,9 +46,9 @@ public static int compareStartsUnsafe(XTextRangeCompare compare, XTextRange a, X public static int compareStarts(XTextRange a, XTextRange b) { if (!comparables(a, b)) { - throw new RuntimeException("compareStarts: got incomparable regions"); + throw new java.lang.IllegalArgumentException("compareStarts: got incomparable regions"); } - final XTextRangeCompare compare = UnoCast.unoQI(XTextRangeCompare.class, a.getText()); + final XTextRangeCompare compare = UnoCast.cast(XTextRangeCompare.class, a.getText()).get(); return compareStartsUnsafe(compare, a, b); } @@ -59,9 +59,9 @@ public static int compareStarts(XTextRange a, XTextRange b) { */ public static int compareEnds(XTextRange a, XTextRange b) { if (!comparables(a, b)) { - throw new RuntimeException("compareEnds: got incomparable regions"); + throw new java.lang.IllegalArgumentException("compareEnds: got incomparable regions"); } - final XTextRangeCompare compare = UnoCast.unoQI(XTextRangeCompare.class, a.getText()); + final XTextRangeCompare compare = UnoCast.cast(XTextRangeCompare.class, a.getText()).get(); return (-1) * compare.compareRegionEnds(a, b); } @@ -78,9 +78,9 @@ public static int compareStartsThenEndsUnsafe(XTextRangeCompare compare, XTextRa public static int compareStartsThenEnds(XTextRange a, XTextRange b) { if (!comparables(a, b)) { - throw new RuntimeException("compareStartsThenEnds: got incomparable regions"); + throw new java.lang.IllegalArgumentException("compareStartsThenEnds: got incomparable regions"); } - final XTextRangeCompare compare = UnoCast.unoQI(XTextRangeCompare.class, a.getText()); + final XTextRangeCompare compare = UnoCast.cast(XTextRangeCompare.class, a.getText()).get(); return compareStartsThenEndsUnsafe(compare, a, b); } } 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 107e7a0e018..3b9797f553e 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoTextSection.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoTextSection.java @@ -6,8 +6,8 @@ import com.sun.star.container.XNameAccess; import com.sun.star.container.XNamed; import com.sun.star.lang.DisposedException; -import com.sun.star.lang.IllegalArgumentException; import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextContent; import com.sun.star.text.XTextDocument; import com.sun.star.text.XTextRange; import com.sun.star.text.XTextSection; @@ -23,7 +23,7 @@ public static XNameAccess getNameAccess(XTextDocument doc) throws NoDocumentException { - XTextSectionsSupplier supplier = UnoCast.unoQI(XTextSectionsSupplier.class, doc); + XTextSectionsSupplier supplier = UnoCast.cast(XTextSectionsSupplier.class, doc).get(); try { return supplier.getTextSections(); } catch (DisposedException ex) { @@ -40,9 +40,7 @@ public static Optional getByName(XTextDocument doc, String name) NoDocumentException { XNameAccess nameAccess = getNameAccess(doc); try { - return Optional.ofNullable((XTextSection) - ((Any) nameAccess.getByName(name)) - .getObject()); + return Optional.ofNullable((XTextSection) ((Any) nameAccess.getByName(name)).getObject()); } catch (NoSuchElementException ex) { return Optional.empty(); } @@ -60,31 +58,23 @@ public static Optional getAnchor(XTextDocument doc, String name) NoDocumentException { XNameAccess nameAccess = getNameAccess(doc); - return (UnoNameAccess.getTextContentByName(nameAccess, name) - .map(e -> e.getAnchor())); + return (UnoNameAccess.getTextContentByName(nameAccess, name).map(XTextContent::getAnchor)); } /** - * Create a text section with the provided name and insert it at - * the provided cursor. + * 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) throws - IllegalArgumentException, CreationException { - return UnoNamed.insertNamedTextContent(doc, - "com.sun.star.text.TextSection", - name, - range, - absorb); + return UnoNamed.insertNamedTextContent(doc, "com.sun.star.text.TextSection", name, range, absorb); } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java b/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java index 7f41515dd1c..b75bee17f3e 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java @@ -16,14 +16,13 @@ private UnoUndo() { } public static Optional getXUndoManager(XTextDocument doc) { // https://www.openoffice.org/api/docs/common/ref/com/sun/star/document/XUndoManager.html - return (UnoCast.optUnoQI(XUndoManagerSupplier.class, doc) - .map(e -> e.getUndoManager())); + return (UnoCast.cast(XUndoManagerSupplier.class, doc) + .map(XUndoManagerSupplier::getUndoManager)); } /** - * Each call to enterUndoContext must be paired by a call to - * leaveUndoContext, otherwise, the document's undo stack is - * left in an inconsistent state. + * Each call to enterUndoContext must be paired by a call to leaveUndoContext, otherwise, the + * document's undo stack is left in an inconsistent state. */ public static void enterUndoContext(XTextDocument doc, String title) { Optional um = getXUndoManager(doc); @@ -38,7 +37,7 @@ public static void leaveUndoContext(XTextDocument doc) { try { um.get().leaveUndoContext(); } catch (InvalidStateException ex) { - throw new RuntimeException("leaveUndoContext reported InvalidStateException"); + throw new IllegalStateException("leaveUndoContext reported InvalidStateException"); } } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java b/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java index dd09ae4745a..634edb0c57b 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java @@ -7,13 +7,14 @@ import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyAttribute; import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; import com.sun.star.beans.UnknownPropertyException; import com.sun.star.beans.XPropertyContainer; import com.sun.star.beans.XPropertySet; import com.sun.star.beans.XPropertySetInfo; -import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.document.XDocumentProperties; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextDocument; import com.sun.star.uno.Any; @@ -33,7 +34,7 @@ public class UnoUserDefinedProperty { private UnoUserDefinedProperty() { } public static Optional getPropertyContainer(XTextDocument doc) { - return UnoTextDocument.getDocumentProperties(doc).map(e -> e.getUserDefinedProperties()); + return UnoTextDocument.getDocumentProperties(doc).map(XDocumentProperties::getUserDefinedProperties); } public static List getListOfNames(XTextDocument doc) { @@ -43,13 +44,12 @@ public static List getListOfNames(XTextDocument doc) { } /** - * @param property Name of a custom document property in the - * current document. + * @param property Name of a custom document property in the current document. * * @return The value of the property or Optional.empty() * - * These properties are used to store extra data about - * individual citation. In particular, the `pageInfo` part. + * These properties are used to store extra data about individual citation. + * In particular, the `pageInfo` part. * */ public static Optional getStringValue(XTextDocument doc, String property) @@ -58,7 +58,7 @@ public static Optional getStringValue(XTextDocument doc, String property Optional propertySet = (UnoUserDefinedProperty.getPropertyContainer(doc) .flatMap(UnoProperties::asPropertySet)); if (propertySet.isEmpty()) { - throw new RuntimeException("getting UserDefinedProperties as XPropertySet failed"); + throw new java.lang.IllegalArgumentException("getting UserDefinedProperties as XPropertySet failed"); } try { String v = propertySet.get().getPropertyValue(property).toString(); @@ -69,17 +69,14 @@ public static Optional getStringValue(XTextDocument doc, String property } /** - * @param property Name of a custom document property in the - * current document. Created if does not exist yet. + * @param property Name of a custom document property in the current document. + * Created if does not exist yet. * * @param value The value to be stored. */ - public static void createStringProperty(XTextDocument doc, String property, String value) + public static void setStringProperty(XTextDocument doc, String property, String value) throws - NotRemoveableException, - PropertyExistException, IllegalTypeException, - IllegalArgumentException, PropertyVetoException, WrappedTargetException { @@ -89,12 +86,12 @@ public static void createStringProperty(XTextDocument doc, String property, Stri Optional container = UnoUserDefinedProperty.getPropertyContainer(doc); if (container.isEmpty()) { - throw new RuntimeException("UnoUserDefinedProperty.getPropertyContainer failed"); + throw new java.lang.IllegalArgumentException("UnoUserDefinedProperty.getPropertyContainer failed"); } Optional propertySet = container.flatMap(UnoProperties::asPropertySet); if (propertySet.isEmpty()) { - throw new RuntimeException("asPropertySet failed"); + throw new java.lang.IllegalArgumentException("asPropertySet failed"); } XPropertySetInfo propertySetInfo = propertySet.get().getPropertySetInfo(); @@ -108,60 +105,53 @@ public static void createStringProperty(XTextDocument doc, String property, Stri } } - container.get().addProperty(property, - com.sun.star.beans.PropertyAttribute.REMOVEABLE, - new Any(Type.STRING, value)); + try { + container.get().addProperty(property, PropertyAttribute.REMOVEABLE, new Any(Type.STRING, value)); + } catch (PropertyExistException ex) { + throw new java.lang.IllegalStateException("Caught PropertyExistException for property assumed not to exist"); + } } /** - * @param property Name of a custom document property in the - * current document. + * @param property Name of a custom document property in the current document. * * Logs warning if does not exist. */ public static void remove(XTextDocument doc, String property) throws - NotRemoveableException, - PropertyExistException, - IllegalTypeException, - IllegalArgumentException { + NotRemoveableException { Objects.requireNonNull(property); Optional container = UnoUserDefinedProperty.getPropertyContainer(doc); if (container.isEmpty()) { - throw new RuntimeException("getUserDefinedPropertiesAsXPropertyContainer failed"); + throw new java.lang.IllegalArgumentException("getUserDefinedPropertiesAsXPropertyContainer failed"); } try { container.get().removeProperty(property); } catch (UnknownPropertyException ex) { - LOGGER.warn(String.format("UnoUserDefinedProperty.remove(%s)" - + " This property was not there to remove", + LOGGER.warn(String.format("UnoUserDefinedProperty.remove(%s) This property was not there to remove", property)); } } /** - * @param property Name of a custom document property in the - * current document. + * @param property Name of a custom document property in the current document. * * Keep silent if property did not exist. */ public static void removeIfExists(XTextDocument doc, String property) throws - NotRemoveableException, - PropertyExistException, - IllegalTypeException, - IllegalArgumentException { + NotRemoveableException { Objects.requireNonNull(property); Optional container = UnoUserDefinedProperty.getPropertyContainer(doc); if (container.isEmpty()) { - throw new RuntimeException("getUserDefinedPropertiesAsXPropertyContainer failed"); + throw new java.lang.IllegalArgumentException("getUserDefinedPropertiesAsXPropertyContainer failed"); } try { diff --git a/src/main/java/org/jabref/model/openoffice/util/OOResult.java b/src/main/java/org/jabref/model/openoffice/util/OOResult.java index 2be478f6d8a..c90bc68ad13 100644 --- a/src/main/java/org/jabref/model/openoffice/util/OOResult.java +++ b/src/main/java/org/jabref/model/openoffice/util/OOResult.java @@ -1,50 +1,39 @@ package org.jabref.model.openoffice.util; +import java.util.NoSuchElementException; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; /* - * error cannot be null - * result cannot be null + * An instance of this class represents either the result of a computation, or an error + * value. Neither of these is allowed to be null. * * Void is not allowed for R, use OOVoidResult instead. * * Out of `isPresent()` and `isError()` exactly one is true. */ public class OOResult { + private final Optional result; private final Optional error; /** * Exactly one of the arguments should be Optional.empty() - * - * @param result - * @param error */ private OOResult(Optional result, Optional error) { this.result = result; this.error = error; } - /** - * @param result Null is not allowed. - */ public static OOResult ok(R result) { return new OOResult<>(Optional.of(result), Optional.empty()); } - /** - * @param error Null is not allowed. - */ public static OOResult error(E error) { return new OOResult<>(Optional.empty(), Optional.of(error)); } - /* - * Test state - */ - public boolean isPresent() { return result.isPresent(); } @@ -61,13 +50,9 @@ public boolean isOK() { return !isError(); } - /* - * getters - */ - public R get() { if (isError()) { - throw new RuntimeException("Cannot get from error"); + throw new NoSuchElementException("Cannot get from error"); } return result.get(); } @@ -76,10 +61,6 @@ public E getError() { return error.get(); } - /* - * Conditionals - */ - public OOResult ifPresent(Consumer fun) { if (isPresent()) { fun.accept(get()); diff --git a/src/main/java/org/jabref/model/openoffice/util/OOTuple3.java b/src/main/java/org/jabref/model/openoffice/util/OOTuple3.java index ca324ebc4ad..8742e06764f 100644 --- a/src/main/java/org/jabref/model/openoffice/util/OOTuple3.java +++ b/src/main/java/org/jabref/model/openoffice/util/OOTuple3.java @@ -1,9 +1,20 @@ package org.jabref.model.openoffice.util; +/** + * This class allows three objects to be packed together, and later accessed as fields `a`, `b` and + * `c`. + * + * Can be used to avoid creating a new class for just this purpose. + * + * Can be useful if you do not have `Trifunction` at hand but need to pass three objects at a time. + * + */ public class OOTuple3 { + public final A a; public final B b; public final C c; + public OOTuple3(A a, B b, C c) { this.a = a; this.b = b; diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java index 03a0b535e34..82d7888afd8 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java @@ -109,7 +109,7 @@ static String runGetNumCitationMarker2b(OOBibStyle style, CitationMarkerNumericEntry... s) { List input = Stream.of(s).collect(Collectors.toList()); OOText res = style.getNumCitationMarker2(input, minGroupingCount); - return res.asString(); + return res.toString(); } static CitationMarkerEntry makeCitationMarkerEntry(BibEntry entry, @@ -178,7 +178,7 @@ void testGetNumCitationMarker() throws IOException { CitationMarkerNumericEntry e2 = numEntry("key", 1, "pp. 55-56"); assertEquals(true, e2.getPageInfo().isPresent()); - assertEquals("pp. 55-56", e2.getPageInfo().get().asString()); + assertEquals("pp. 55-56", e2.getPageInfo().get().toString()); citation = runGetNumCitationMarker2b(style, -1, e2); assertEquals("[1; pp. 55-56]", citation); @@ -250,7 +250,7 @@ void testGetNumCitationMarkerUndefined() throws IOException { */ CitationMarkerNumericBibEntry x = numBibEntry("key", Optional.empty()); assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "] ", - style.getNumCitationMarkerForBibliography(x).asString()); + style.getNumCitationMarkerForBibliography(x).toString()); } @Test @@ -761,13 +761,13 @@ void testGetCitationMarkerJoinFirst() throws IOException { + "; Boström, Wäyrynen, Bodén, Beznosov & NotKruchten, 2006c]", style.createCitationMarker(citationMarkerEntries, true, - NonUniqueCitationMarker.THROWS).asString()); + NonUniqueCitationMarker.THROWS).toString()); assertEquals("Boström, Wäyrynen, Bodén, Beznosov & Kruchten [2006a,b]" + "; Boström, Wäyrynen, Bodén, Beznosov & NotKruchten [2006c]", style.createCitationMarker(citationMarkerEntries, false, - NonUniqueCitationMarker.THROWS).asString()); + NonUniqueCitationMarker.THROWS).toString()); } // Without pageInfo, only the first is isFirstAppearanceOfSource. @@ -789,7 +789,7 @@ void testGetCitationMarkerJoinFirst() throws IOException { + "; Boström et al., 2006c]", style.createCitationMarker(citationMarkerEntries, true, - NonUniqueCitationMarker.THROWS).asString()); + NonUniqueCitationMarker.THROWS).toString()); } // Without pageInfo, only the second is isFirstAppearanceOfSource. @@ -813,7 +813,7 @@ void testGetCitationMarkerJoinFirst() throws IOException { + "; Boström et al., 2006c]", style.createCitationMarker(citationMarkerEntries, true, - NonUniqueCitationMarker.THROWS).asString()); + NonUniqueCitationMarker.THROWS).toString()); } // Without pageInfo, neither is isFirstAppearanceOfSource. @@ -835,7 +835,7 @@ void testGetCitationMarkerJoinFirst() throws IOException { assertEquals("[Boström et al., 2006a,b,c]", style.createCitationMarker(citationMarkerEntries, true, - NonUniqueCitationMarker.THROWS).asString()); + NonUniqueCitationMarker.THROWS).toString()); } // With pageInfo: different entries with identical non-null pageInfo: not joined. @@ -857,7 +857,7 @@ void testGetCitationMarkerJoinFirst() throws IOException { + "; Boström et al., 2006c; p1]", style.createCitationMarker(citationMarkerEntries, true, - NonUniqueCitationMarker.THROWS).asString()); + NonUniqueCitationMarker.THROWS).toString()); } // With pageInfo: same entries with identical non-null pageInfo: collapsed. @@ -878,7 +878,7 @@ void testGetCitationMarkerJoinFirst() throws IOException { assertEquals("[Boström et al., 2006a; p1]", style.createCitationMarker(citationMarkerEntries, true, - NonUniqueCitationMarker.THROWS).asString()); + NonUniqueCitationMarker.THROWS).toString()); } // With pageInfo: same entries with different pageInfo: kept separate. // Empty ("") and missing pageInfos considered equal, thus collapsed. @@ -902,7 +902,7 @@ void testGetCitationMarkerJoinFirst() throws IOException { + "; Boström et al., 2006a]", style.createCitationMarker(citationMarkerEntries, true, - NonUniqueCitationMarker.THROWS).asString()); + NonUniqueCitationMarker.THROWS).toString()); } } } diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java index 9fbe9579ccb..ae5e83abd2f 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java @@ -98,14 +98,14 @@ static String runGetNumCitationMarker2a(OOBibStyle style, List num, int minGroupingCount, boolean inList) { if (inList) { if (num.size() != 1) { - throw new RuntimeException("Numeric label for the bibliography with " - + String.valueOf(num.size()) + " numbers?"); + throw new IllegalArgumentException("Numeric label for the bibliography with " + + String.valueOf(num.size()) + " numbers?"); } int n = num.get(0); CitationMarkerNumericBibEntryImpl x = new CitationMarkerNumericBibEntryImpl("key", (n == 0) ? Optional.empty() : Optional.of(n)); - return style.getNumCitationMarkerForBibliography(x).asString(); + return style.getNumCitationMarkerForBibliography(x).toString(); } else { List input = num.stream() @@ -114,7 +114,7 @@ static String runGetNumCitationMarker2a(OOBibStyle style, n, Optional.empty())) .collect(Collectors.toList()); - return style.getNumCitationMarker2(input, minGroupingCount).asString(); + return style.getNumCitationMarker2(input, minGroupingCount).toString(); } } @@ -131,7 +131,7 @@ static String runGetNumCitationMarker2b(OOBibStyle style, CitationMarkerNumericEntry... s) { List input = Stream.of(s).collect(Collectors.toList()); OOText res = style.getNumCitationMarker2(input, minGroupingCount); - return res.asString(); + return res.toString(); } /* @@ -146,8 +146,8 @@ static CitationMarkerEntry makeCitationMarkerEntry(BibEntry entry, String uniqueLetterQ, String pageInfoQ, boolean isFirstAppearanceOfSource) { - if (!entry.getCitationKey().isPresent()) { - throw new RuntimeException("!entry.getCitationKey().isPresent()"); + if (entry.getCitationKey().isEmpty()) { + throw new IllegalArgumentException("entry.getCitationKey() is empty"); } String citationKey = entry.getCitationKey().get(); Citation result = new Citation(citationKey); @@ -194,7 +194,7 @@ static String getCitationMarker2(OOBibStyle style, } return style.createCitationMarker(citationMarkerEntries, inParenthesis, - NonUniqueCitationMarker.THROWS).asString(); + NonUniqueCitationMarker.THROWS).toString(); } /* From 61fa941236ae85469127150e5e80dc6b68fe5cd3 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sat, 19 Jun 2021 13:58:19 +0200 Subject: [PATCH 032/103] apply oobranch-[DEFGH]-update.patch --- .../org/jabref/gui/openoffice/OOBibBase2.java | 24 +- .../gui/openoffice/OOBibBaseConnect.java | 12 +- .../logic/openoffice/action/EditInsert.java | 17 +- .../logic/openoffice/action/EditMerge.java | 64 ++--- .../logic/openoffice/action/EditSeparate.java | 21 +- .../logic/openoffice/action/ExportCited.java | 2 +- .../logic/openoffice/action/Update.java | 6 +- .../logic/openoffice/backend/Backend52.java | 65 +++-- .../logic/openoffice/backend/Codec52.java | 32 +-- .../logic/openoffice/backend/GetContext.java | 8 +- .../NamedRangeManagerReferenceMark.java | 6 +- .../backend/NamedRangeReferenceMark.java | 164 ++++------- .../logic/openoffice/frontend/OOFrontend.java | 254 +++++++++--------- .../frontend/UpdateBibliography.java | 11 +- .../frontend/UpdateCitationMarkers.java | 4 +- .../logic/openoffice/style/OOBibStyle.java | 16 +- .../style/OOBibStyleGetCitationMarker.java | 12 +- .../style/OOBibStyleGetNumCitationMarker.java | 15 +- .../style/OOFormatBibliography.java | 25 +- .../logic/openoffice/style/OOProcess.java | 6 +- .../model/openoffice/backend/NamedRange.java | 8 +- .../model/openoffice/ootext/OOFormat.java | 59 ++-- .../model/openoffice/ootext/OOText.java | 28 +- .../model/openoffice/ootext/OOTextIntoOO.java | 120 ++++----- .../rangesort/FunctionalTextViewCursor.java | 52 ++-- .../rangesort/RangeOverlapBetween.java | 42 +-- .../rangesort/RangeOverlapWithin.java | 27 +- .../model/openoffice/rangesort/RangeSet.java | 7 +- .../model/openoffice/rangesort/RangeSort.java | 19 +- .../openoffice/rangesort/RangeSortVisual.java | 52 ++-- .../openoffice/rangesort/RangeSortable.java | 6 +- .../model/openoffice/style/Citation.java | 2 +- .../model/openoffice/style/CitationGroup.java | 9 +- .../openoffice/style/CitationGroupId.java | 3 +- .../openoffice/style/CitationGroups.java | 59 ++-- .../style/CitationLookupResult.java | 3 +- .../openoffice/style/CitationMarkerEntry.java | 10 +- .../style/CitationMarkerNormEntry.java | 7 +- .../model/openoffice/style/CitationPath.java | 4 +- .../model/openoffice/style/CitedKey.java | 11 +- .../openoffice/style/CompareCitation.java | 4 +- .../openoffice/style/CompareCitedKey.java | 4 +- .../style/NonUniqueCitationMarker.java | 6 +- .../model/openoffice/style/OODataModel.java | 12 +- .../model/openoffice/style/PageInfo.java | 2 +- .../model/openoffice/uno/UnoBookmark.java | 34 +-- .../jabref/model/openoffice/uno/UnoCast.java | 11 +- .../model/openoffice/uno/UnoCrossRef.java | 56 ++-- .../model/openoffice/uno/UnoCursor.java | 4 +- .../model/openoffice/uno/UnoNameAccess.java | 5 +- .../jabref/model/openoffice/uno/UnoNamed.java | 40 ++- .../model/openoffice/uno/UnoProperties.java | 2 +- .../model/openoffice/uno/UnoRedlines.java | 23 +- .../openoffice/uno/UnoReferenceMark.java | 50 ++-- .../model/openoffice/uno/UnoSelection.java | 16 +- .../jabref/model/openoffice/uno/UnoStyle.java | 19 +- .../model/openoffice/uno/UnoTextDocument.java | 11 +- .../model/openoffice/uno/UnoTextRange.java | 18 +- .../model/openoffice/uno/UnoTextSection.java | 26 +- .../jabref/model/openoffice/uno/UnoUndo.java | 11 +- .../uno/UnoUserDefinedProperty.java | 58 ++-- .../model/openoffice/util/OOResult.java | 29 +- .../model/openoffice/util/OOTuple3.java | 11 + .../openoffice/style/OOBibStyleTest.java | 22 +- .../style/OOBibStyleTestHelper.java | 16 +- 65 files changed, 805 insertions(+), 977 deletions(-) diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java index ca8324cda2a..f196bae6bc4 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java @@ -164,7 +164,7 @@ void showDialog(String title, OOError ex) { OOVoidResult collectResults(String title, List> results) { String msg = (results.stream() - .filter(e -> e.isError()) + .filter(OOVoidResult::isError) .map(e -> e.getError().getLocalizedMessage()) .collect(Collectors.joining("\n\n"))); if (msg.isEmpty()) { @@ -322,7 +322,7 @@ private static OOVoidResult checkIfOpenOfficeIsRecordingChanges(XTextDo } return OOVoidResult.error(new OOError(title, msg)); } - } catch (UnknownPropertyException | WrappedTargetException ex) { + } catch (WrappedTargetException ex) { String msg = Localization.lang("Error while checking if Writer" + " is recording changes or has recorded changes."); return OOVoidResult.error(new OOError(title, msg, ex)); @@ -372,10 +372,10 @@ OOVoidResult selectedBibEntryIsRequired(List entries, * Checks existence and also checks if it is not an internal name. */ private OOVoidResult checkStyleExistsInTheDocument(String familyName, - String styleName, - XTextDocument doc, - String labelInJstyleFile, - String pathToStyleFile) + String styleName, + XTextDocument doc, + String labelInJstyleFile, + String pathToStyleFile) throws NoSuchElementException, WrappedTargetException { @@ -394,9 +394,9 @@ private OOVoidResult checkStyleExistsInTheDocument(String familyName, labelInJstyleFile, styleName); default -> - throw new RuntimeException("Expected " + UnoStyle.CHARACTER_STYLES - + " or " + UnoStyle.PARAGRAPH_STYLES - + " for familyName"); + throw new IllegalArgumentException("Expected " + UnoStyle.CHARACTER_STYLES + + " or " + UnoStyle.PARAGRAPH_STYLES + + " for familyName"); } + "\n" + Localization.lang("Please create it in the document or change in the file:") @@ -419,9 +419,9 @@ private OOVoidResult checkStyleExistsInTheDocument(String familyName, styleName, internalName.get()); default -> - throw new RuntimeException("Expected " + UnoStyle.CHARACTER_STYLES - + " or " + UnoStyle.PARAGRAPH_STYLES - + " for familyName"); + throw new IllegalArgumentException("Expected " + UnoStyle.CHARACTER_STYLES + + " or " + UnoStyle.PARAGRAPH_STYLES + + " for familyName"); } + "\n" + Localization.lang("Please use the latter in the style file below" diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java b/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java index 03765f8ffd8..c9f6246062b 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java @@ -72,10 +72,10 @@ private XDesktop simpleBootstrap(Path loPath) Object desktop; try { desktop = sem.createInstanceWithContext("com.sun.star.frame.Desktop", context); - } catch (Exception e) { + } catch (com.sun.star.uno.Exception e) { throw new CreationException(e.getMessage()); } - return UnoCast.unoQI(XDesktop.class, desktop); + return UnoCast.cast(XDesktop.class, desktop).get(); } private static List getTextDocuments(XDesktop desktop) @@ -90,10 +90,10 @@ private static List getTextDocuments(XDesktop desktop) while (compEnum.hasMoreElements()) { Object next = compEnum.nextElement(); - XComponent comp = UnoCast.unoQI(XComponent.class, next); - XTextDocument doc = UnoCast.unoQI(XTextDocument.class, comp); - if (doc != null) { - result.add(doc); + XComponent comp = UnoCast.cast(XComponent.class, next).get(); + Optional doc = UnoCast.cast(XTextDocument.class, comp); + if (doc.isPresent()) { + result.add(doc.get()); } } return result; diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java index 277b92bec76..1345f1f2a99 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java @@ -43,28 +43,21 @@ public class EditInsert { * * In the document we store citations by their citation key. * - * If the citation key is missing, the best we can do is to notify - * the user. Or the programmer, that we cannot accept such input. + * If the citation key is missing, the best we can do is to notify the user. Or the programmer, + * that we cannot accept such input. * */ private static String insertEntryGetCitationKey(BibEntry entry) { Optional key = entry.getCitationKey(); if (key.isEmpty()) { - throw new RuntimeException("insertEntryGetCitationKey:" - + " cannot cite entries without citation key"); + throw new IllegalArgumentException("insertEntryGetCitationKey: cannot cite entries without citation key"); } return key.get(); } - /* + /** * @param cursor Where to insert. - * - * @param sync If not empty, update citation markers and, - * depending on the embedded options, the - * bibliography. - * - * @param fcursor If sync.isPresent(), it must provide a - * FunctionalTextViewCursor. Otherwise not used. + * @param pageInfo A single pageInfo for a list of entries. This is what we get from the GUI. */ public static void insertCitationGroup(XTextDocument doc, OOFrontend fr, diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java index 823610c51cf..4cd225eb1a8 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java @@ -107,14 +107,10 @@ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend fr, OOBi } private static class JoinableGroupData { - /* - * A list of consecutive citation groups only separated by spaces. - */ + /** A list of consecutive citation groups only separated by spaces. */ List group; - /* - * A cursor covering the XTextRange of each entry in group - * (and the spaces between them) - */ + + /** A cursor covering the XTextRange of each entry in group (and the spaces between them) */ XTextCursor groupCursor; JoinableGroupData(List group, XTextCursor groupCursor) { @@ -128,21 +124,21 @@ private static class ScanState { // Citation groups in the current group List currentGroup; - // A cursor that covers the Citation groups in currentGroup, - // including the space between them. - // Null if currentGroup.isEmpty() + // A cursor that covers the Citation groups in currentGroup, including the space between + // them. + // null if currentGroup.isEmpty() XTextCursor currentGroupCursor; // A cursor starting at the end of the last CitationGroup in - // currentGroup. Null if currentGroup.isEmpty() + // currentGroup. null if currentGroup.isEmpty() XTextCursor cursorBetween; // The last element of currentGroup. - // Null if currentGroup.isEmpty() + // null if currentGroup.isEmpty() CitationGroup prev; // The XTextRange for prev. - // Null if currentGroup.isEmpty() + // null if currentGroup.isEmpty() XTextRange prevRange; ScanState() { @@ -164,9 +160,8 @@ void reset() { * @param cg The CitationGroup to test * @param currentRange The XTextRange corresponding to cg. * - * @return false if cannot add, true if can. If returned true, - * then state.cursorBetween and state.currentGroupCursor are - * expanded to end at the start of currentRange. + * @return false if cannot add, true if can. If returned true, then state.cursorBetween and + * state.currentGroupCursor are expanded to end at the start of currentRange. */ private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextRange currentRange) { @@ -186,8 +181,7 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextR if (state.prev != null) { - // Even if we combine AUTHORYEAR_INTEXT citations, we - // would not mix them with AUTHORYEAR_PAR + // Even if we combine AUTHORYEAR_INTEXT citations, we would not mix them with AUTHORYEAR_PAR if (cg.citationType != state.prev.citationType) { return false; } @@ -196,8 +190,7 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextR return false; } - // Sanity check: the current range should start later than - // the previous. + // Sanity check: the current range should start later than the previous. int textOrder = UnoTextRange.compareStarts(state.prevRange, currentRange); if (textOrder != (-1)) { String msg = @@ -208,8 +201,7 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextR currentRange.getString(), ((textOrder == 0) ? "they start at the same position" - : ("the start of the latter precedes" - + " the start of the first"))); + : "the start of the latter precedes the start of the first")); LOGGER.warn(msg); return false; } @@ -224,14 +216,13 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextR // assume: currentGroupCursor.getEnd() == cursorBetween.getEnd() if (UnoTextRange.compareEnds(state.cursorBetween, state.currentGroupCursor) != 0) { - String msg = ("MergeCitationGroups:" - + " cursorBetween.end != currentGroupCursor.end"); - throw new RuntimeException(msg); + String msg = ("MergeCitationGroups: cursorBetween.end != currentGroupCursor.end"); + throw new IllegalStateException(msg); } /* - * Try to expand state.currentGroupCursor and state.cursorBetween by going right - * to reach rangeStart. + * Try to expand state.currentGroupCursor and state.cursorBetween by going right to reach + * rangeStart. */ XTextRange rangeStart = currentRange.getStart(); boolean couldExpand = true; @@ -257,12 +248,10 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextR // These two should move in sync: if (UnoTextRange.compareEnds(state.cursorBetween, state.currentGroupCursor) != 0) { - String msg = ("MergeCitationGroups:" - + " cursorBetween.end != currentGroupCursor.end" - + " (during expand)"); - throw new RuntimeException(msg); + String msg = ("MergeCitationGroups: cursorBetween.end != currentGroupCursor.end (during expand)"); + throw new IllegalStateException(msg); } - } // while + } if (!couldExpand) { return false; @@ -304,7 +293,7 @@ private static void addToCurrentGroup(ScanState state, CitationGroup cg, XTextRa if (UnoTextRange.compareEnds(state.cursorBetween, state.currentGroupCursor) != 0) { String msg = ("MergeCitationGroups: cursorBetween.end != currentGroupCursor.end"); - throw new RuntimeException(msg); + throw new IllegalStateException(msg); } /* Store data about last entry in currentGroup */ @@ -321,9 +310,7 @@ private static List scan(XTextDocument doc, OOFrontend fr) WrappedTargetException { List result = new ArrayList<>(); - List cgs = - fr.getCitationGroupsSortedWithinPartitions(doc, - false /* mapFootnotesToFootnoteMarks */); + List cgs = fr.getCitationGroupsSortedWithinPartitions(doc, false /* mapFootnotesToFootnoteMarks */); if (cgs.isEmpty()) { return result; } @@ -333,7 +320,7 @@ private static List scan(XTextDocument doc, OOFrontend fr) for (CitationGroup cg : cgs) { XTextRange currentRange = (fr.getMarkRange(doc, cg) - .orElseThrow(RuntimeException::new)); + .orElseThrow(IllegalStateException::new)); /* * Decide if we add cg to the group. False when the group is empty. @@ -341,8 +328,7 @@ private static List scan(XTextDocument doc, OOFrontend fr) boolean addToGroup = checkAddToGroup(state, cg, currentRange); /* - * Even if we do not add it to an existing group, - * we might use it to start a new group. + * Even if we do not add it to an existing group, we might use it to start a new group. * * Can it start a new group? */ diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java index 31c23ed52d0..0293159d34f 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java @@ -65,7 +65,7 @@ public static boolean separateCitations(XTextDocument doc, XTextRange range1 = (fr .getMarkRange(doc, cg) - .orElseThrow(RuntimeException::new)); + .orElseThrow(IllegalStateException::new)); XTextCursor textCursor = range1.getText().createTextCursorByRange(range1); List cits = cg.citationsInStorageOrder; @@ -82,16 +82,15 @@ public static boolean separateCitations(XTextDocument doc, boolean insertSpaceAfter = (i != last); Citation cit = cits.get(i); - UpdateCitationMarkers.createAndFillCitationGroup( - fr, - doc, - List.of(cit.citationKey), - List.of(cit.getPageInfo()), - cg.citationType, - OOText.fromString(cit.citationKey), - textCursor, - style, - insertSpaceAfter); + UpdateCitationMarkers.createAndFillCitationGroup(fr, + doc, + List.of(cit.citationKey), + List.of(cit.getPageInfo()), + cg.citationType, + OOText.fromString(cit.citationKey), + textCursor, + style, + insertSpaceAfter); textCursor.collapseToEnd(); } diff --git a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java index 8d344688c68..ef7985d666a 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java +++ b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java @@ -41,7 +41,7 @@ public static class GenerateDatabaseResult { * If a key is not found, it is added to result.unresolvedKeys * * Cross references (in StandardField.CROSSREF) are followed (not recursively): - * if the referenced entry is found, it is included in the result. + * If the referenced entry is found, it is included in the result. * If it is not found, it is silently ignored. */ public static GenerateDatabaseResult generateDatabase(XTextDocument doc, List databases) diff --git a/src/main/java/org/jabref/logic/openoffice/action/Update.java b/src/main/java/org/jabref/logic/openoffice/action/Update.java index 151e4b6575b..675afb2a79f 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/Update.java +++ b/src/main/java/org/jabref/logic/openoffice/action/Update.java @@ -20,13 +20,13 @@ import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextDocument; -/* +/** * Update document: citation marks and bibliography */ public class Update { - /* - * @return unresolvedKeys + /** + * @return the list of unresolved citation keys */ private static List updateDocument(XTextDocument doc, OOFrontend fr, diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java index d7c1b62086a..cf91ad1043e 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java @@ -67,8 +67,8 @@ public List getJabRefReferenceMarkNames(XTextDocument doc) } /** - * Names of custom properties belonging to us, but without a - * corresponding reference mark. These can be deleted. + * Names of custom properties belonging to us, but without a corresponding reference mark. + * These can be deleted. * * @param citationGroupNames These are the names that are used. * @@ -178,16 +178,14 @@ public CitationGroup readCitationGroupFromDocumentOrThrow(XTextDocument doc, Str } /** - * Create a reference mark with the given name, at the - * end of position. + * Create a reference mark with the given name, at the end of position. * - * On return {@code position} is collapsed, and is after the - * inserted space, or at the end of the reference mark. + * On return {@code position} is collapsed, and is after the inserted space, or at the end of + * the reference mark. * * @param position Collapsed to its end. - * @param insertSpaceAfter We insert a space after the mark, that - * carries on format of characters from - * the original position. + * @param insertSpaceAfter We insert a space after the mark, that carries on format of + * characters from the original position. */ public CitationGroup createCitationGroup(XTextDocument doc, List citationKeys, @@ -206,7 +204,7 @@ public CitationGroup createCitationGroup(XTextDocument doc, Objects.requireNonNull(pageInfos); if (pageInfos.size() != citationKeys.size()) { - throw new RuntimeException("pageInfos.size != citationKeys.size"); + throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); } // Get a new refMarkName @@ -237,7 +235,7 @@ public CitationGroup createCitationGroup(XTextDocument doc, } } break; - case JabRef53: + case JabRef60: cit.setPageInfo(pageInfo); break; } @@ -257,7 +255,7 @@ public CitationGroup createCitationGroup(XTextDocument doc, if (pageInfo.isPresent()) { String pageInfoString = OOText.toString(pageInfo.get()); - UnoUserDefinedProperty.createStringProperty(doc, refMarkName, pageInfoString); + UnoUserDefinedProperty.setStringProperty(doc, refMarkName, pageInfoString); } else { // do not inherit from trash UnoUserDefinedProperty.removeIfExists(doc, refMarkName); @@ -269,16 +267,15 @@ public CitationGroup createCitationGroup(XTextDocument doc, this.cgidToNamedRange.put(cgid, namedRange); return cg; default: - throw new RuntimeException("Backend52 requires JabRef52 dataModel"); + throw new IllegalStateException("Backend52 requires JabRef52 dataModel"); } } /** - * @return A list with a nullable pageInfo entry for each citation in - * joinableGroups. + * @return A list with a nullable pageInfo entry for each citation in joinableGroups. * - * TODO: JabRef52 combinePageInfos is not reversible. Should warn - * user to check the result. Or ask what to do. + * TODO: JabRef52 combinePageInfos is not reversible. Should warn user to check the result. Or + * ask what to do. */ public static List> combinePageInfosCommon(OODataModel dataModel, List joinableGroup) { @@ -296,20 +293,20 @@ public CitationGroup createCitationGroup(XTextDocument doc, .collect(Collectors.joining("; "))); int nCitations = (joinableGroup.stream() - .map(cg -> cg.numberOfCitations()) + .map(CitationGroup::numberOfCitations) .mapToInt(Integer::intValue).sum()); if ("".equals(cgPageInfo)) { cgPageInfo = null; } return OODataModel.fakePageInfos(cgPageInfo, nCitations); - case JabRef53: + case JabRef60: return (joinableGroup.stream() .flatMap(cg -> (cg.citationsInStorageOrder.stream() .map(Citation::getPageInfo))) .collect(Collectors.toList())); default: - throw new RuntimeException("unhandled dataModel here"); + throw new IllegalArgumentException("unhandled dataModel here"); } } @@ -323,8 +320,8 @@ public List> combinePageInfos(List joinableGroup private NamedRange getNamedRangeOrThrow(CitationGroup cg) { NamedRange namedRange = this.cgidToNamedRange.get(cg.cgid); if (namedRange == null) { - LOGGER.warn("getNamedRange: could not lookup namedRange"); - throw new RuntimeException("getNamedRange: could not lookup namedRange"); + String msg = "getNamedRange: could not lookup namedRange"; + throw new IllegalStateException("getNamedRange: could not lookup namedRange"); } return namedRange; } @@ -346,9 +343,7 @@ public void removeCitationGroup(CitationGroup cg, XTextDocument doc) } /** - * * @return Optional.empty if the reference mark is missing. - * */ public Optional getMarkRange(CitationGroup cg, XTextDocument doc) throws @@ -360,8 +355,8 @@ public Optional getMarkRange(CitationGroup cg, XTextDocument doc) } /** - * Cursor for the reference marks as is, not prepared for filling, - * but does not need cleanFillCursorForCitationGroup either. + * Cursor for the reference marks as is: not prepared for filling, but does not need + * cleanFillCursorForCitationGroup either. */ public Optional getRawCursorForCitationGroup(CitationGroup cg, XTextDocument doc) throws @@ -403,14 +398,14 @@ public List getCitationEntries(XTextDocument doc, CitationGroups switch (dataModel) { case JabRef52: // One context per CitationGroup: Backend52 (DataModel.JabRef52) - // For DataModel.JabRef53 (Backend53) we need one context per Citation + // For DataModel.JabRef60 (Backend60) we need one context per Citation int n = cgs.numberOfCitationGroups(); List citations = new ArrayList<>(n); for (CitationGroup cg : cgs.getCitationGroupsUnordered()) { String name = cg.cgid.citationGroupIdAsString(); XTextCursor cursor = (this .getRawCursorForCitationGroup(cg, doc) - .orElseThrow(RuntimeException::new)); + .orElseThrow(IllegalStateException::new)); String context = GetContext.getCursorStringWithContext(cursor, 30, 30, true); Optional pageInfo = (cg.numberOfCitations() > 0 ? (getPageInfoFromData(cg) @@ -420,11 +415,11 @@ public List getCitationEntries(XTextDocument doc, CitationGroups citations.add(entry); } return citations; - case JabRef53: + case JabRef60: // xx - throw new RuntimeException("getCitationEntries for JabRef53 is not implemented yet"); + throw new IllegalStateException("getCitationEntries for JabRef60 is not implemented yet"); default: - throw new RuntimeException("getCitationEntries: unhandled dataModel "); + throw new IllegalStateException("getCitationEntries: unhandled dataModel "); } } @@ -449,15 +444,15 @@ public void applyCitationEntries(XTextDocument doc, List citation pageInfo = PageInfo.normalizePageInfo(pageInfo); if (pageInfo.isPresent()) { String name = entry.getRefMarkName(); - UnoUserDefinedProperty.createStringProperty(doc, name, pageInfo.get().asString()); + UnoUserDefinedProperty.setStringProperty(doc, name, pageInfo.get().toString()); } } break; - case JabRef53: + case JabRef60: // xx - throw new RuntimeException("applyCitationEntries for JabRef53 is not implemented yet"); + throw new IllegalStateException("applyCitationEntries for JabRef60 is not implemented yet"); default: - throw new RuntimeException("applyCitationEntries: unhandled dataModel "); + throw new IllegalStateException("applyCitationEntries: unhandled dataModel "); } } diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java index 352df27cdeb..e4405dc6115 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java @@ -16,7 +16,6 @@ * How and what is encoded in a mark names. * * - pageInfo does not appear here. It is not encoded in the mark name. - * - Does not depend on the type of marks (reference mark of bookmark) used. */ class Codec52 { private static final String BIB_CITATION = "JR_cite"; @@ -27,7 +26,6 @@ class Codec52 { /** * This is what we get back from parsing a refMarkName. - * */ public static class ParsedMarkName { /** "", "0", "1" ... */ @@ -46,9 +44,8 @@ public static class ParsedMarkName { } } - /* - * Integer representation was written into the document in - * JabRef52, keep it for compatibility. + /** + * Integer representation was written into the document in JabRef52, keep it for compatibility. */ public static CitationType CitationTypeFromInt(int i) { switch (i) { @@ -59,7 +56,7 @@ public static CitationType CitationTypeFromInt(int i) { case 3: return CitationType.INVISIBLE_CIT; default: - throw new RuntimeException("Invalid CitationType code"); + throw new IllegalArgumentException("Invalid CitationType code"); } } @@ -72,21 +69,18 @@ public static int CitationTypeToInt(CitationType i) { case INVISIBLE_CIT: return 3; default: - throw new RuntimeException("Invalid CitationType"); + throw new IllegalArgumentException("Invalid CitationType"); } } /** - * Produce a reference mark name for JabRef for the given citation - * key and citationType that does not yet appear among the reference - * marks of the document. + * Produce a reference mark name for JabRef for the given citation key and citationType that + * does not yet appear among the reference marks of the document. * * @param bibtexKey The citation key. - * @param citationType Encodes the effect of withText and - * inParenthesis options. + * @param citationType Encodes the effect of withText and inParenthesis options. * - * The first occurrence of bibtexKey gets no serial number, the - * second gets 0, the third 1 ... + * The first occurrence of bibtexKey gets no serial number, the second gets 0, the third 1 ... * * Or the first unused in this series, after removals. */ @@ -97,10 +91,10 @@ public static String getUniqueMarkName(Set usedNames, NoDocumentException { int i = 0; - int j = CitationTypeToInt(citationType); - String name = BIB_CITATION + '_' + j + '_' + bibtexKey; + int citTypeCode = CitationTypeToInt(citationType); + String name = BIB_CITATION + '_' + citTypeCode + '_' + bibtexKey; while (usedNames.contains(name)) { - name = BIB_CITATION + i + '_' + j + '_' + bibtexKey; + name = BIB_CITATION + i + '_' + citTypeCode + '_' + bibtexKey; i++; } return name; @@ -121,8 +115,8 @@ public static Optional parseMarkName(String refMarkName) { List keys = Arrays.asList(citeMatcher.group(3).split(",")); String i = citeMatcher.group(1); - int j = Integer.parseInt(citeMatcher.group(2)); - CitationType citationType = CitationTypeFromInt(j); + int citTypeCode = Integer.parseInt(citeMatcher.group(2)); + CitationType citationType = CitationTypeFromInt(citTypeCode); return (Optional.of(new Codec52.ParsedMarkName(i, citationType, keys))); } diff --git a/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java b/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java index 468d630e756..4cde12ad236 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java @@ -27,8 +27,8 @@ private GetContext() { * @param cursor * @param charBefore Number of characters requested. * @param charAfter Number of characters requested. - * @param htmlMarkup If true, the text belonging to the - * reference mark is surrounded by bold html tag. + * @param htmlMarkup If true, the text belonging to the reference mark is surrounded by bold + * html tag. * */ public static String getCursorStringWithContext(XTextCursor cursor, @@ -46,8 +46,8 @@ public static String getCursorStringWithContext(XTextCursor cursor, for (int i = 0; i < charBefore; i++) { try { cursor.goLeft((short) 1, true); - // If we are close to charBefore and see a space, - // then cut here. Might avoid cutting a word in half. + // If we are close to charBefore and see a space, then cut here. Might avoid cutting + // a word in half. if ((i >= (charBefore - flex)) && Character.isWhitespace(cursor.getString().charAt(0))) { break; diff --git a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java index 157dd87cf0c..d82ad08378e 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java @@ -23,11 +23,7 @@ public NamedRange nrmCreate(XTextDocument doc, boolean withoutBrackets) throws CreationException { - return NamedRangeReferenceMark.create(doc, - refMarkName, - position, - insertSpaceAfter, - withoutBrackets); + return NamedRangeReferenceMark.create(doc, refMarkName, position, insertSpaceAfter, withoutBrackets); } @Override 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 38ac716d9ac..63d5f917fc5 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java @@ -47,11 +47,11 @@ String getId() { } /** - * Insert {@code n} spaces in a way that reference - * marks just before or just after the cursor are not affected. + * Insert {@code n} spaces in a way that reference marks just before or just after the cursor + * are not affected. * - * This is based on the observation, that starting two - * new paragraphs separates us from a reference mark on either side. + * This is based on the observation, that starting two new paragraphs separates us from + * reference marks on either side. * * The pattern used is: * {@code safeInsertSpaces(n): para, para, left, space(n), right-delete, left(n), left-delete} @@ -61,8 +61,6 @@ String getId() { * * @return a new cursor, covering the just-inserted spaces. * - * This could be generalized to insert arbitrary text safely - * between two reference marks. But we do not need that now. */ private static XTextCursor safeInsertSpacesBetweenReferenceMarks(XTextRange position, int n) { // Start with an empty cursor at position.getStart(); @@ -129,19 +127,14 @@ static NamedRangeReferenceMark create(XTextDocument doc, throws CreationException { - createReprInDocument(doc, - refMarkName, - position, - insertSpaceAfter, - withoutBrackets); + createReprInDocument(doc, refMarkName, position, insertSpaceAfter, withoutBrackets); return new NamedRangeReferenceMark(refMarkName); } /** * @return Optional.empty if there is no corresponding range. */ - static Optional getFromDocument(XTextDocument doc, - String refMarkName) + static Optional getFromDocument(XTextDocument doc, String refMarkName) throws NoDocumentException, WrappedTargetException { @@ -160,7 +153,7 @@ public void nrRemoveFromDocument(XTextDocument doc) WrappedTargetException, NoDocumentException, NoSuchElementException { - UnoReferenceMark.remove(doc, this.nrGetRangeName()); + UnoReferenceMark.removeIfExists(doc, this.nrGetRangeName()); } @Override @@ -185,11 +178,11 @@ public Optional nrGetMarkRange(XTextDocument doc) } /** - * Cursor for the reference marks as is, not prepared for filling, - * but does not need nrCleanFillCursor either. + * Cursor for the reference marks as is, not prepared for filling, but does not need + * nrCleanFillCursor either. * * @return Optional.empty() if reference mark is missing from the document, - * otherwise an XTextCursor for getMarkRange + * otherwise an XTextCursor for getMarkRange * * See: getRawCursorForCitationGroup */ @@ -230,11 +223,11 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) String name = this.nrGetRangeName(); - final boolean debugThisFun = false; final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; final short leftLength = (short) left.length(); final short rightLength = (short) right.length(); + final boolean debugThisFun = false; XTextCursor full = null; String fullText = null; @@ -242,86 +235,62 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) Optional markAsTextContent = UnoReferenceMark.getAsTextContent(doc, name); if (markAsTextContent.isEmpty()) { - String msg = String.format("nrGetFillCursor:" - + " markAsTextContent(%s).isEmpty (attempt %d)", - name, - i); - throw new RuntimeException(msg); + String msg = String.format("nrGetFillCursor: markAsTextContent(%s).isEmpty (attempt %d)", name, i); + throw new IllegalStateException(msg); } full = UnoCursor.getTextCursorOfTextContentAnchor(markAsTextContent.get()).orElse(null); if (full == null) { String msg = String.format("nrGetFillCursor: full == null (attempt %d)", i); - throw new RuntimeException(msg); + throw new IllegalStateException(msg); } fullText = full.getString(); - if (debugThisFun) { - System.out.printf("nrGetFillCursor: fulltext = '%s'%n", fullText); - } + LOGGER.debug("nrGetFillCursor: fulltext = '{}'", fullText); if (fullText.length() >= 2) { - if (debugThisFun) { - System.out.printf("nrGetFillCursor: (attempt: %d) fulltext.length() >= 2," - + " break loop%n", i); - } + LOGGER.debug("nrGetFillCursor: (attempt: {}) fulltext.length() >= 2, break loop%n", i); break; } else { // (fullText.length() < 2) if (i == 2) { - String msg = String.format("nrGetFillCursor:" - + " (fullText.length() < 2) (attempt %d)", - i); - throw new RuntimeException(msg); + String msg = String.format("nrGetFillCursor: (fullText.length() < 2) (attempt %d)", i); + throw new IllegalStateException(msg); } // too short, recreate - if (true || debugThisFun) { - System.out.println("nrGetFillCursor: too short, recreate"); - } + LOGGER.warn("nrGetFillCursor: too short, recreate"); + full.setString(""); - try { - UnoReferenceMark.remove(doc, name); - } catch (NoSuchElementException ex) { - String msg = String.format("nrGetFillCursor got NoSuchElementException" - + " for '%s'", - name); - LOGGER.warn(msg); - } - createReprInDocument(doc, - name, - full, - false, /* insertSpaceAfter */ - false /* withoutBrackets */); + UnoReferenceMark.removeIfExists(doc, name); + + final boolean insertSpaceAfter = false; + final boolean withoutBrackets = false; + createReprInDocument(doc, name, full, insertSpaceAfter, withoutBrackets); } } if (full == null) { - throw new RuntimeException("nrGetFillCursorFor: full == null (after loop)"); + throw new IllegalStateException("nrGetFillCursorFor: full == null (after loop)"); } if (fullText == null) { - throw new RuntimeException("nrGetFillCursor: fullText == null (after loop)"); + throw new IllegalStateException("nrGetFillCursor: fullText == null (after loop)"); } fullText = full.getString(); if (fullText.length() < 2) { - throw new RuntimeException("nrGetFillCursor: fullText.length() < 2 (after loop)'%n"); + throw new IllegalStateException("nrGetFillCursor: fullText.length() < 2 (after loop)'%n"); } XTextCursor beta = full.getText().createTextCursorByRange(full); beta.collapseToStart(); beta.goRight((short) 1, false); beta.goRight((short) (fullText.length() - 2), true); - if (debugThisFun) { - System.out.printf("nrGetFillCursor: beta(1) covers '%s'%n", beta.getString()); - } + LOGGER.debug("nrGetFillCursor: beta(1) covers '{}'", beta.getString()); + if (fullText.startsWith(left) && fullText.endsWith(right)) { beta.setString(""); } else { - if (debugThisFun) { - String msg = String.format("nrGetFillCursor: recreating brackets for '%s'", fullText); - // LOGGER.warn(msg); - System.out.println(msg); - } + LOGGER.debug("nrGetFillCursor: recreating brackets for '{}'", fullText); // we have at least two characters inside XTextCursor alpha = full.getText().createTextCursorByRange(full); @@ -336,47 +305,40 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) String paddingy = "y"; String paddingz = "z"; beta.setString(paddingx + left + paddingy + right + paddingz); - if (debugThisFun) { - System.out.printf("nrGetFillCursor: beta(2) covers '%s'%n", beta.getString()); - } + LOGGER.debug("nrGetFillCursor: beta(2) covers '{}'", beta.getString()); + // move beta to before the right bracket beta.collapseToEnd(); beta.goLeft((short) (rightLength + 1), false); // remove middle padding beta.goLeft((short) 1, true); - if (debugThisFun) { - System.out.printf("nrGetFillCursor: beta(3) covers '%s'%n", beta.getString()); - } + LOGGER.debug("nrGetFillCursor: beta(3) covers '{}'", beta.getString()); + // only drop paddingy later: beta.setString(""); // drop the initial character and paddingx alpha.collapseToStart(); alpha.goRight((short) (1 + 1), true); - if (debugThisFun) { - System.out.printf("nrGetFillCursor: alpha(4) covers '%s'%n", alpha.getString()); - } + LOGGER.debug("nrGetFillCursor: alpha(4) covers '{}'", alpha.getString()); + alpha.setString(""); // drop the last character and paddingz omega.collapseToEnd(); omega.goLeft((short) (1 + 1), true); - if (debugThisFun) { - System.out.printf("nrGetFillCursor: omega(5) covers '%s'%n", omega.getString()); - } + LOGGER.debug("nrGetFillCursor: omega(5) covers '{}'", omega.getString()); + omega.setString(""); // drop paddingy now - if (debugThisFun) { - System.out.printf("nrGetFillCursor: beta(6) covers '%s'%n", beta.getString()); - } + LOGGER.debug("nrGetFillCursor: beta(6) covers '{}'", beta.getString()); + beta.setString(""); // should be OK now. if (debugThisFun) { alpha.goRight(leftLength, true); - System.out.printf("nrGetFillCursor: alpha(7) covers '%s', should be '%s'%n", - alpha.getString(), left); + LOGGER.debug("nrGetFillCursor: alpha(7) covers '{}', should be '{}'", alpha.getString(), left); omega.goLeft(rightLength, true); - System.out.printf("nrGetFillCursor: omega(8) covers '%s', should be '%s'%n", - omega.getString(), right); + LOGGER.debug("nrGetFillCursor: omega(8) covers '%s', should be '%s'%n", omega.getString(), right); } } @@ -385,7 +347,7 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) } /* - * Throw RuntimeException if the brackets are not there. + * Throw IllegalStateException if the brackets are not there. */ public static void checkFillCursor(XTextCursor cursor) { final String left = REFERENCE_MARK_LEFT_BRACKET; @@ -403,10 +365,9 @@ public static void checkFillCursor(XTextCursor cursor) { alpha.goLeft(leftLength, true); if (!left.equals(alpha.getString())) { String msg = String.format("checkFillCursor:" - + " ('%s') is not prefixed with" - + " REFERENCE_MARK_LEFT_BRACKET, has '%s'", + + " ('%s') is not prefixed with REFERENCE_MARK_LEFT_BRACKET, has '%s'", cursor.getString(), alpha.getString()); - throw new RuntimeException(msg); + throw new IllegalStateException(msg); } } @@ -414,17 +375,16 @@ public static void checkFillCursor(XTextCursor cursor) { omega.goRight(rightLength, true); if (!right.equals(omega.getString())) { String msg = String.format("checkFillCursor:" - + " ('%s') is not followed by" - + " REFERENCE_MARK_RIGHT_BRACKET, has '%s'", + + " ('%s') is not followed by REFERENCE_MARK_RIGHT_BRACKET, has '%s'", cursor.getString(), omega.getString()); - throw new RuntimeException(msg); + throw new IllegalStateException(msg); } } } /** - * Remove brackets, but if the result would become empty, leave - * them; if the result would be a single characer, leave the left bracket. + * Remove brackets, but if the result would become empty, leave them; if the result would be a + * single characer, leave the left bracket. * * See: cleanFillCursorForCitationGroup */ @@ -435,13 +395,11 @@ public void nrCleanFillCursor(XTextDocument doc) WrappedTargetException, CreationException { - // alwaysRemoveBrackets : full compatibility with JabRef 5.2: - // brackets are temporary, only exist between nrGetFillCursor - // and nrCleanFillCursor. + // alwaysRemoveBrackets : full compatibility with JabRef 5.2: brackets are temporary, only + // exist between nrGetFillCursor and nrCleanFillCursor. final boolean alwaysRemoveBrackets = false; - // removeBracketsFromEmpty is intended to force removal if we - // are working on an "Empty citation" (INVISIBLE_CIT). + // removeBracketsFromEmpty is intended to force removal if we are working on an "Empty citation" (INVISIBLE_CIT). final boolean removeBracketsFromEmpty = false; final String left = REFERENCE_MARK_LEFT_BRACKET; @@ -451,28 +409,24 @@ public void nrCleanFillCursor(XTextDocument doc) String name = this.nrGetRangeName(); - XTextCursor full = this.nrGetRawCursor(doc).orElseThrow(RuntimeException::new); + XTextCursor full = this.nrGetRawCursor(doc).orElseThrow(IllegalStateException::new); final String fullText = full.getString(); final int fullTextLength = fullText.length(); if (!fullText.startsWith(left)) { - String msg = String.format("nrCleanFillCursor:" - + " (%s) does not start with REFERENCE_MARK_LEFT_BRACKET", - name); - throw new RuntimeException(msg); + String msg = String.format("nrCleanFillCursor: (%s) does not start with REFERENCE_MARK_LEFT_BRACKET", name); + throw new IllegalStateException(msg); } if (!fullText.endsWith(right)) { - String msg = String.format("nrCleanFillCursor:" - + " (%s) does not end with REFERENCE_MARK_RIGHT_BRACKET", - name); - throw new RuntimeException(msg); + String msg = String.format("nrCleanFillCursor: (%s) does not end with REFERENCE_MARK_RIGHT_BRACKET", name); + throw new IllegalStateException(msg); } final int contentLength = (fullTextLength - (leftLength + rightLength)); if (contentLength < 0) { String msg = String.format("nrCleanFillCursor: length(%s) < 0", name); - throw new RuntimeException(msg); + throw new IllegalStateException(msg); } boolean removeRight = ((contentLength >= 1) diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java index fd0523a4bf8..6a4f741b793 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java @@ -57,9 +57,7 @@ public OOFrontend(XTextDocument doc) NoDocumentException, WrappedTargetException { - // TODO: dataModel should come from looking at the - // document and preferences. - // + // TODO: dataModel should come from looking at the document and preferences. this.backend = new Backend52(); // Get the citationGroupNames @@ -98,24 +96,19 @@ public Optional healthReport(XTextDocument doc) } /** - * Creates a list of {@code RangeSortable} values for - * our {@code CitationGroup} values. Originally designed to be - * passed to {@code visualSort}. + * Creates a list of {@code RangeSortable} values for our {@code CitationGroup} + * values. Originally designed to be passed to {@code visualSort}. * - * The elements of the returned list are actually of type - * {@code RangeSortEntry}. + * The elements of the returned list are actually of type {@code RangeSortEntry}. * - * The result is sorted within {@code XTextRange.getText()} - * partitions of the citation groups according to their {@code XTextRange} - * (before mapping to footnote marks). + * The result is sorted within {@code XTextRange.getText()} partitions of the citation groups + * according to their {@code XTextRange} (before mapping to footnote marks). * - * In the result, RangeSortable.getIndexInPosition() contains - * unique indexes within the original partition (not after - * mapFootnotesToFootnoteMarks). + * In the result, RangeSortable.getIndexInPosition() contains unique indexes within the original + * partition (not after mapFootnotesToFootnoteMarks). * - * @param mapFootnotesToFootnoteMarks If true, replace ranges in - * footnotes with the range of the corresponding footnote - * mark. This is used for numbering the citations. + * @param mapFootnotesToFootnoteMarks If true, replace ranges in footnotes with the range of the + * corresponding footnote mark. This is used for numbering the citations. * */ private List> @@ -128,27 +121,24 @@ public Optional healthReport(XTextDocument doc) for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { XTextRange range = (this .getMarkRange(doc, cg) - .orElseThrow(RuntimeException::new)); + .orElseThrow(IllegalStateException::new)); sortables.add(new RangeSortEntry<>(range, 0, cg)); } /* * At this point we are almost ready to return sortables. * - * But we may want to number citations in a footnote - * as if it appeared where the footnote mark is. + * But we may want to number citations in a footnote as if it appeared where the footnote + * mark is. * - * The following code replaces ranges within footnotes with - * the range for the corresponding footnote mark. + * The following code replaces ranges within footnotes with the range for the corresponding + * footnote mark. * - * This brings further ambiguity if we have multiple - * citation groups within the same footnote: for the comparison - * they become indistinguishable. Numbering between them is - * not controlled. Also combineCiteMarkers will see them in - * the wrong order (if we use this comparison), and will not - * be able to merge. To avoid these, we sort textually within - * each .getText() partition and add indexInPosition - * accordingly. + * This brings further ambiguity if we have multiple citation groups within the same + * footnote: for the comparison they become indistinguishable. Numbering between them is + * not controlled. Also combineCiteMarkers will see them in the wrong order (if we use this + * comparison), and will not be able to merge. To avoid these, we sort textually within + * each .getText() partition and add indexInPosition accordingly. * */ @@ -174,53 +164,45 @@ public Optional healthReport(XTextDocument doc) } } result.add(sortable); - } + } } return result.stream().map(e -> e).collect(Collectors.toList()); } /** - * @param mapFootnotesToFootnoteMarks If true, sort reference - * marks in footnotes as if they appeared at the - * corresponding footnote mark. + * @param mapFootnotesToFootnoteMarks If true, sort reference marks in footnotes as if they + * appeared at the corresponding footnote mark. * * @return citation groups sorted by their visual positions. * - * Limitation: for two column layout visual (top-down, - * left-right) order does not match the expected (textual) - * order. + * Limitation: for two column layout visual (top-down, left-right) order does not match the + * expected (textual) order. * */ - private List - getVisuallySortedCitationGroups(XTextDocument doc, - boolean mapFootnotesToFootnoteMarks, - FunctionalTextViewCursor fcursor) + private List getVisuallySortedCitationGroups(XTextDocument doc, + boolean mapFootnotesToFootnoteMarks, + FunctionalTextViewCursor fcursor) throws WrappedTargetException, NoDocumentException, JabRefException { - List> sortables = - createVisualSortInput(doc, mapFootnotesToFootnoteMarks); + List> sortables = createVisualSortInput(doc, mapFootnotesToFootnoteMarks); - List> sorted = - RangeSortVisual.visualSort(sortables, - doc, - fcursor); + List> sorted = RangeSortVisual.visualSort(sortables, doc, fcursor); - List result = - (sorted.stream().map(e -> e.getContent()).collect(Collectors.toList())); + List result = (sorted.stream() + .map(RangeSortable::getContent) + .collect(Collectors.toList())); return result; } /** - * Return citation groups in visual order within (but not across) - * XText partitions. + * Return citation groups in visual order within (but not across) XText partitions. * - * This is (1) sufficient for combineCiteMarkers which looks for - * consecutive XTextRanges within each XText, (2) not confused by - * multicolumn layout or multipage display. + * This is (1) sufficient for combineCiteMarkers which looks for consecutive XTextRanges within + * each XText, (2) not confused by multicolumn layout or multipage display. */ public List getCitationGroupsSortedWithinPartitions(XTextDocument doc, boolean mapFootnotesToFootnoteMarks) @@ -236,19 +218,17 @@ public Optional healthReport(XTextDocument doc) } /** - * Create a citation group for the given citation keys, at the - * end of position. + * Create a citation group for the given citation keys, at the end of position. * - * On return {@code position} is collapsed, and is after the - * inserted space, or at the end of the reference mark. + * On return {@code position} is collapsed, and is after the inserted space, or at the end of + * the reference mark. * * @param citationKeys In storage order * @param pageInfos In storage order * @param citationType * @param position Collapsed to its end. - * @param insertSpaceAfter If true, we insert a space after the mark, that - * carries on format of characters from - * the original position. + * @param insertSpaceAfter If true, we insert a space after the mark, that carries on format of + * characters from the original position. */ public CitationGroup createCitationGroup(XTextDocument doc, List citationKeys, @@ -267,7 +247,7 @@ public CitationGroup createCitationGroup(XTextDocument doc, Objects.requireNonNull(pageInfos); if (pageInfos.size() != citationKeys.size()) { - throw new RuntimeException("pageInfos.size != citationKeys.size"); + throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); } CitationGroup cg = backend.createCitationGroup(doc, citationKeys, @@ -357,8 +337,8 @@ public List> citationRanges(XTextDocument new ArrayList<>(citationGroups.numberOfCitationGroups()); for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { - XTextRange range = this.getMarkRange(doc, cg).orElseThrow(RuntimeException::new); - String description = cg.cgid.citationGroupIdAsString(); // cg.cgRangeStorage.nrGetRangeName(); + XTextRange range = this.getMarkRange(doc, cg).orElseThrow(IllegalStateException::new); + String description = cg.cgid.citationGroupIdAsString(); result.add(new RangeForOverlapCheck<>(range, cg.cgid, RangeForOverlapCheck.REFERENCE_MARK_KIND, @@ -404,56 +384,88 @@ public List> viewCursorRanges(XTextDocumen } /** - * @return A range for each footnote mark where the footnote - * contains at least one citation group. + * @return A range for each footnote mark where the footnote contains at least one citation group. * - * Purpose: We do not want markers of footnotes containing - * reference marks to overlap with reference - * marks. Overwriting these footnote marks might kill our - * reference marks in the footnote. + * Purpose: We do not want markers of footnotes containing reference marks to overlap with + * reference marks. Overwriting these footnote marks might kill our reference marks in the + * footnote. * - * Note: Here we directly communicate to the document, not - * through the backend. This is because mapping ranges to - * footnote marks does not depend on how do we mark or - * structure those ranges. + * Note: Here we directly communicate to the document, not through the backend. This is because + * mapping ranges to footnote marks does not depend on how do we mark or structure those + * ranges. */ public List> - footnoteMarkRanges(XTextDocument doc, - List> citationRanges) + footnoteMarkRanges(XTextDocument doc, List> citationRanges) throws NoDocumentException, WrappedTargetException { - // Avoid inserting the same mark twice. - // Could use RangeSet if we had that. - RangeSet seen = new RangeSet(); + if (false) { + // Avoid inserting the same mark twice. + RangeSet seen = new RangeSet(); - List> result = new ArrayList<>(); + List> result = new ArrayList<>(); + + for (RangeForOverlapCheck citationRange : citationRanges) { - for (RangeForOverlapCheck citationRange : citationRanges) { + Optional footnoteMarkRange = UnoTextRange.getFootnoteMarkRange(citationRange.range); - Optional footnoteMarkRange = - UnoTextRange.getFootnoteMarkRange(citationRange.range); + if (footnoteMarkRange.isEmpty()) { + // not in footnote + continue; + } - if (footnoteMarkRange.isEmpty()) { - // not in footnote - continue; + boolean seenContains = seen.contains(footnoteMarkRange.get()); + if (!seenContains) { + seen.add(footnoteMarkRange.get()); + result.add(new RangeForOverlapCheck<>(footnoteMarkRange.get(), + citationRange.idWithinKind, + RangeForOverlapCheck.FOOTNOTE_MARK_KIND, + "FootnoteMark for " + citationRange.format())); + } } + return result; + } else { + + // RangeSet.add involves a few comparisons anf getText, which is probably costly. + // + // (On the other hand we only insert ranges of footnotes, which probably limits the sizes + // of its partitions) + // + // We can avoid using RangeSet by partitioning only and using a single range from + // each partition to get at the corresponding footnotemark range. + + List> result = new ArrayList<>(); + RangeSort.RangePartitions> partitions = + RangeSort.partitionRanges(citationRanges); + + // Now it is sufficient to check a single entry from each partition. + // Each partition corresponds to an XText, and each footnote has a single XText. + // (This latter ignores the possibility of XTextContents inserted into footnotes.) + // Also: different footnotes cannot share a footnotemark range, we are not creating duplicates. + for (List> partition : partitions.getPartitions()) { + if (partition.isEmpty()) { + continue; + } + RangeForOverlapCheck citationRange = partition.get(0); + + Optional footnoteMarkRange = UnoTextRange.getFootnoteMarkRange(citationRange.range); + + if (footnoteMarkRange.isEmpty()) { + // not in footnote + continue; + } - boolean seenContains = seen.contains(footnoteMarkRange.get()); - if (!seenContains) { - seen.add(footnoteMarkRange.get()); result.add(new RangeForOverlapCheck<>(footnoteMarkRange.get(), citationRange.idWithinKind, RangeForOverlapCheck.FOOTNOTE_MARK_KIND, "FootnoteMark for " + citationRange.format())); } + return result; } - return result; } - static String - rangeOverlapsToMessage(List>> overlaps) { + static String rangeOverlapsToMessage(List>> overlaps) { if (overlaps.size() == 0) { return "(*no overlaps*)"; @@ -481,6 +493,7 @@ public List> viewCursorRanges(XTextDocumen * Check for any overlap between userRanges and protected ranges. * * Assume userRanges is small (usually 1 elements for checking the cursor) + * * Returns on first problem found. */ public OOVoidResult @@ -500,11 +513,10 @@ public List> viewCursorRanges(XTextDocumen ranges.addAll(footnoteMarkRanges(doc, citationRanges)); List>> overlaps = - RangeOverlapBetween.findFirst( - doc, - userRanges, - ranges, - requireSeparation); + RangeOverlapBetween.findFirst(doc, + userRanges, + ranges, + requireSeparation); if (overlaps.size() == 0) { return OOVoidResult.ok(); @@ -518,11 +530,10 @@ public List> viewCursorRanges(XTextDocumen * @param reportAtMost Limit number of overlaps reported (0 for no limit) * */ - public OOVoidResult - checkRangeOverlaps(XTextDocument doc, - List> userRanges, - boolean requireSeparation, - int reportAtMost) + public OOVoidResult checkRangeOverlaps(XTextDocument doc, + List> userRanges, + boolean requireSeparation, + int reportAtMost) throws NoDocumentException, WrappedTargetException { @@ -550,33 +561,29 @@ public List> viewCursorRanges(XTextDocumen * * Called from: ManageCitationsDialogViewModel constructor. * - * @return A list with entries corresponding to citations in the - * text, in arbitrary order (same order as from - * getJabRefReferenceMarkNames). + * @return A list with entries corresponding to citations in the text, in arbitrary order (same + * order as from getJabRefReferenceMarkNames). * - * Note: visual or alphabetic order could be more - * manageable for the user. We could provide these - * here, but switching between them needs change on - * GUI (adding a toggle or selector). + * Note: visual or alphabetic order could be more manageable for the user. We + * could provide these here, but switching between them needs change on GUI + * (adding a toggle or selector). * - * Note: CitationEntry implements Comparable, where - * compareTo() and equals() are based on refMarkName. - * The order used in the "Manage citations" dialog + * Note: CitationEntry implements Comparable, where compareTo() and equals() are + * based on refMarkName. The order used in the "Manage citations" dialog * does not seem to use that. * - * The 1st is labeled "Citation" (show citation in bold, - * and some context around it). + * The 1st is labeled "Citation" (show citation in bold, and some context + * around it). * - * The columns can be sorted by clicking on the column title. - * For the "Citation" column, the sorting is based on the content, - * (the context before the citation), not on the citation itself. + * The columns can be sorted by clicking on the column title. For the + * "Citation" column, the sorting is based on the content, (the context + * before the citation), not on the citation itself. * - * In the "Extra information ..." column some visual indication - * of the editable part could be helpful. + * In the "Extra information ..." column some visual indication of the + * editable part could be helpful. * - * Wish: selecting an entry (or a button in the line) in - * the GUI could move the cursor in the document to - * the entry. + * Wish: selecting an entry (or a button in the line) in the GUI could move the cursor + * in the document to the entry. */ public List getCitationEntries(XTextDocument doc) throws @@ -608,8 +615,7 @@ public void imposeGlobalOrder(XTextDocument doc, FunctionalTextViewCursor fcurso boolean mapFootnotesToFootnoteMarks = true; List sortedCitationGroups = getVisuallySortedCitationGroups(doc, mapFootnotesToFootnoteMarks, fcursor); - List sortedCitationGroupIds = - OOListUtil.map(sortedCitationGroups, cg -> cg.cgid); + List sortedCitationGroupIds = OOListUtil.map(sortedCitationGroups, cg -> cg.cgid); citationGroups.setGlobalOrder(sortedCitationGroupIds); } } 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 ef1a4c42dc5..2d0de320ca6 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java @@ -47,7 +47,6 @@ public static void rebuildBibTextSection(XTextDocument doc, throws NoSuchElementException, WrappedTargetException, - IllegalArgumentException, CreationException, PropertyVetoException, UnknownPropertyException, @@ -69,8 +68,7 @@ public static void rebuildBibTextSection(XTextDocument doc, */ private static void createBibTextSection2(XTextDocument doc) throws - CreationException, - IllegalArgumentException { + CreationException { // Always creating at the end of the document. // Alternatively, we could receive a cursor. @@ -89,7 +87,6 @@ private static void createBibTextSection2(XTextDocument doc) private static void clearBibTextSectionContent2(XTextDocument doc) throws CreationException, - IllegalArgumentException, NoDocumentException, WrappedTargetException { @@ -124,7 +121,7 @@ private static void populateBibTextSection(XTextDocument doc, UnknownPropertyException, WrappedTargetException { - XTextRange sectionRange = getBibliographyRange(doc).orElseThrow(RuntimeException::new); + XTextRange sectionRange = getBibliographyRange(doc).orElseThrow(IllegalStateException::new); XTextCursor cursor = doc.getText().createTextCursorByRange(sectionRange); @@ -138,13 +135,13 @@ private static void populateBibTextSection(XTextDocument doc, cursor.collapseToEnd(); // remove the inital empty paragraph from the section. - sectionRange = getBibliographyRange(doc).orElseThrow(RuntimeException::new); + sectionRange = getBibliographyRange(doc).orElseThrow(IllegalStateException::new); XTextCursor initialParagraph = doc.getText().createTextCursorByRange(sectionRange); initialParagraph.collapseToStart(); initialParagraph.goRight((short) 1, true); initialParagraph.setString(""); - UnoBookmark.remove(doc, BIB_SECTION_END_NAME); + UnoBookmark.removeIfExists(doc, BIB_SECTION_END_NAME); UnoBookmark.create(doc, BIB_SECTION_END_NAME, cursor, true); cursor.collapseToEnd(); diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java index 7d864ab1063..b3f90d380a7 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java @@ -102,7 +102,7 @@ public static void fillCitationMarkInCursor(XTextDocument doc, OOText citationText2 = style.decorateCitationMarker(citationText); // inject a ZERO_WIDTH_SPACE to hold the initial character format final String ZERO_WIDTH_SPACE = "\u200b"; - citationText2 = OOText.fromString(ZERO_WIDTH_SPACE + citationText2.asString()); + citationText2 = OOText.fromString(ZERO_WIDTH_SPACE + citationText2.toString()); OOTextIntoOO.write(doc, cursor, citationText2); } else { cursor.setString(""); @@ -150,7 +150,7 @@ public static void createAndFillCitationGroup(OOFrontend fr, Objects.requireNonNull(pageInfos); if (pageInfos.size() != citationKeys.size()) { - throw new RuntimeException("pageInfos.size != citationKeys.size"); + throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); } CitationGroup cg = fr.createCitationGroup(doc, citationKeys, diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index 113cef246e2..feccb727f53 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -517,20 +517,6 @@ public String getNumCitationMarker(List number, int minGroupingCount, b /* end_old */ /* begin_old */ - /** - * Format the marker for the in-text citation according to this BIB style. Uniquefier letters are added as - * provided by the uniquefiers argument. If successive entries within the citation are uniquefied from each other, - * this method will perform a grouping of these entries. - * - * @param entries The list of JabRef BibEntry providing the data. - * @param database A map of BibEntry-BibDatabase pairs. - * @param inParenthesis Signals whether a parenthesized citation or an in-text citation is wanted. - * @param uniquefiers Strings to add behind the year for each entry in case it's needed to separate similar - * entries. - * @param unlimAuthors Boolean for each entry. If true, we should not use "et al" formatting regardless - * of the number of authors. Can be null to indicate that no entries should have unlimited names. - * @return The formatted citation. - */ public String getCitationMarker(List entries, Map database, boolean inParenthesis, String[] uniquefiers, int[] unlimAuthors) { // Look for groups of uniquefied entries that should be combined in the output. @@ -1115,7 +1101,7 @@ public OOText getNumCitationMarkerForBibliography(CitationMarkerNumericBibEntry // not null, check size if (pageInfos.size() != nCitations) { - throw new RuntimeException("normalizePageInfos: pageInfos.size() != nCitations"); + throw new IllegalArgumentException("normalizePageInfos: pageInfos.size() != nCitations"); } // not null, normalize elementwise 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 ee2bba27e7e..e501cd4aaaf 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java @@ -65,10 +65,10 @@ private static String markupAuthorName(OOBibStyle style, String name) { * to mark their omission. * Set to -1 to write out all authors. * - * maxAuthors=0 is pointless, now throws RuntimeException + * maxAuthors=0 is pointless, now throws IllegalArgumentException * (Earlier it behaved as maxAuthors=1) * - * maxAuthors less than -1 : throw RuntimeException + * maxAuthors less than -1 : throw IllegalArgumentException * * @param andString For "A, B[ and ]C" * @@ -129,10 +129,10 @@ private static String formatAuthorList(OOBibStyle style, // To reduce ambiguity, throw on unexpected values of maxAuthors if (maxAuthors == 0 && nAuthors != 0) { - throw new RuntimeException("maxAuthors = 0 in formatAuthorList"); + throw new IllegalArgumentException("maxAuthors = 0 in formatAuthorList"); } if (maxAuthors < -1) { - throw new RuntimeException("maxAuthors < -1 in formatAuthorList"); + throw new IllegalArgumentException("maxAuthors < -1 in formatAuthorList"); } // emitAllAuthors == false means use "et al." @@ -724,8 +724,8 @@ static OOText getNormalizedCitationMarker(OOBibStyle style, if (uniqueLetterDoesNotMakeUnique && nonUniqueCitationMarkerHandling.equals(NonUniqueCitationMarker.THROWS)) { - throw new RuntimeException("different citation keys," - + " but same normalizedMarker and uniqueLetter"); + throw new IllegalArgumentException("different citation keys," + + " but same normalizedMarker and uniqueLetter"); } final boolean pageInfoInhibitsJoin = (bothPageInfosAreEmpty diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java index 376c4478421..8d8422fbc51 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java @@ -91,7 +91,7 @@ private static void emitBlock(List block, final int blockSize = block.size(); if (blockSize == 0) { - throw new RuntimeException("The block is empty"); + throw new IllegalArgumentException("The block is empty"); } if (blockSize == 1) { @@ -117,17 +117,16 @@ private static void emitBlock(List block, */ if (block.stream().anyMatch(x -> x.getPageInfo().isPresent())) { - throw new RuntimeException("Found pageInfo in a block with more than one elements"); + throw new IllegalArgumentException("Found pageInfo in a block with more than one elements"); } if (block.stream().anyMatch(x -> x.getNumber().isEmpty())) { - throw new RuntimeException("Found unresolved entry" - + " in a block with more than one elements"); + throw new IllegalArgumentException("Found unresolved entry in a block with more than one elements"); } for (int j = 1; j < blockSize; j++) { if ((block.get(j).getNumber().get() - block.get(j - 1).getNumber().get()) != 1) { - throw new RuntimeException("Numbers are not consecutive"); + throw new IllegalArgumentException("Numbers are not consecutive"); } } @@ -139,7 +138,7 @@ private static void emitBlock(List block, int first = block.get(0).getNumber().get(); int last = block.get(blockSize - 1).getNumber().get(); if (last != (first + blockSize - 1)) { - throw new RuntimeException("blockSize and length of num range differ"); + throw new IllegalArgumentException("blockSize and length of num range differ"); } // Emit: "first-last" @@ -221,7 +220,7 @@ public static OOText getNumCitationMarker2(OOBibStyle style, final CitationMarkerNumericEntry current = sorted.get(i); if (current.getNumber().isPresent() && current.getNumber().get() < 0) { - throw new RuntimeException("getNumCitationMarker2: found negative value"); + throw new IllegalArgumentException("getNumCitationMarker2: found negative number"); } if (currentBlock.size() == 0) { @@ -259,7 +258,7 @@ public static OOText getNumCitationMarker2(OOBibStyle style, } if (nextBlock.size() != 0) { - throw new RuntimeException("impossible: (nextBlock.size() != 0) after loop"); + throw new IllegalStateException("impossible: (nextBlock.size() != 0) after loop"); } if (currentBlock.size() > 0) { diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java b/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java index c9ae527dcec..6c22c8abb09 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java @@ -36,7 +36,7 @@ public static OOText formatBibliography(CitationGroups cgs, OOText title = style.getFormattedBibliographyTitle(); OOText body = formatBibliographyBody(cgs, bibliography, style, alwaysAddCitedOnPages); - return OOText.fromString(title.asString() + body.asString()); + return OOText.fromString(title.toString() + body.toString()); } /** @@ -51,7 +51,7 @@ public static OOText formatBibliographyBody(CitationGroups cgs, for (CitedKey ck : bibliography.values()) { OOText entryText = formatBibliographyEntry(cgs, ck, style, alwaysAddCitedOnPages); - stringBuilder.append(entryText.asString()); + stringBuilder.append(entryText.toString()); } return OOText.fromString(stringBuilder.toString()); @@ -68,18 +68,18 @@ public static OOText formatBibliographyEntry(CitationGroups cgs, // insert marker "[1]" if (style.isNumberEntries()) { - sb.append(style.getNumCitationMarkerForBibliography(ck).asString()); + sb.append(style.getNumCitationMarkerForBibliography(ck).toString()); } else { // !style.isNumberEntries() : emit no prefix // Note: We might want [citationKey] prefix for style.isCitationKeyCiteMarkers(); } // Add entry body - sb.append(formatBibliographyEntryBody(ck, style).asString()); + sb.append(formatBibliographyEntryBody(ck, style).toString()); // Add "Cited on pages" if (ck.getLookupResult().isEmpty() || alwaysAddCitedOnPages) { - sb.append(formatCitedOnPages(cgs, ck).asString()); + sb.append(formatCitedOnPages(cgs, ck).toString()); } // Add paragraph @@ -169,14 +169,17 @@ private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey ck) { List citationGroups = new ArrayList<>(); for (CitationPath p : ck.getCitationPaths()) { CitationGroupId cgid = p.group; - CitationGroup cg = cgs.getCitationGroupOrThrow(cgid); - citationGroups.add(cg); + Optional cg = cgs.getCitationGroup(cgid); + if (cg.isEmpty()) { + throw new IllegalStateException(); + } + citationGroups.add(cg.get()); } // sort the citationGroups according to their indexInGlobalOrder citationGroups.sort((a, b) -> { - Integer aa = a.getIndexInGlobalOrder().orElseThrow(RuntimeException::new); - Integer bb = b.getIndexInGlobalOrder().orElseThrow(RuntimeException::new); + Integer aa = a.getIndexInGlobalOrder().orElseThrow(IllegalStateException::new); + Integer bb = b.getIndexInGlobalOrder().orElseThrow(IllegalStateException::new); return (aa.compareTo(bb)); }); @@ -185,9 +188,9 @@ private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey ck) { if (i > 0) { sb.append(", "); } - String markName = cg.getReferenceMarkNameForLinking().orElseThrow(RuntimeException::new); + String markName = cg.getReferenceMarkNameForLinking().orElseThrow(IllegalStateException::new); OOText xref = OOFormat.formatReferenceToPageNumberOfReferenceMark(markName); - sb.append(xref.asString()); + sb.append(xref.toString()); i++; } sb.append(suffix); diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java index 6f7709aac10..05475fcdfac 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java @@ -66,12 +66,10 @@ public static Comparator comparatorForMulticite(OOBibStyle style) { * Fill cgs.bibliography and cgs.citationGroupsUnordered//CitationMarker * according to style. */ - public static void produceCitationMarkers(CitationGroups cgs, - List databases, - OOBibStyle style) { + public static void produceCitationMarkers(CitationGroups cgs, List databases, OOBibStyle style) { if (!cgs.hasGlobalOrder()) { - throw new RuntimeException("produceCitationMarkers: globalOrder is misssing in cgs"); + throw new IllegalStateException("produceCitationMarkers: globalOrder is misssing in cgs"); } cgs.lookupCitations(databases); diff --git a/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java index e5c54773b07..d8e1832b6ef 100644 --- a/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java +++ b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java @@ -24,8 +24,8 @@ public Optional nrGetMarkRange(XTextDocument doc) WrappedTargetException; /** - * Cursor for the reference marks as is, not prepared for filling, - * but does not need nrCleanFillCursor either. + * Cursor for the reference marks as is, not prepared for filling, but does not need + * nrCleanFillCursor either. */ public Optional nrGetRawCursor(XTextDocument doc) throws @@ -44,8 +44,8 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) CreationException; /** - * Remove brackets, but if the result would become empty, leave - * them; if the result would be a single characer, leave the left bracket. + * Remove brackets, but if the result would become empty, leave them; if the result would be a + * single characer, leave the left bracket. * */ public void nrCleanFillCursor(XTextDocument doc) diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java index 472ca519161..be5ee399e55 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java @@ -1,9 +1,16 @@ package org.jabref.model.openoffice.ootext; +/** + * Helper functions to produce some of the markup as understood by OOTextIntoOO.write + * + * These do not cover all tags, only those needed to embed markup + * from Layout and citation marker formatters into citation markers and + * bibliography. + */ public class OOFormat { /** - * Mark {@code s} as using a character locale known to OO. + * Mark {@code ootext} as using a character locale known to OO. * * @param locale language[-country[-territory]] * @@ -11,63 +18,61 @@ public class OOFormat { * * The country part is optional. * - * The territory part is not only optional, the allowed "codes are - * vendor and browser-specific", so probably best to avoid them if possible. + * The territory part is not only optional, the allowed "codes are vendor and browser-specific", + * so probably best to avoid them if possible. * */ - public static OOText setLocale(OOText s, String locale) { - return OOText.fromString(String.format("", locale) + s.asString() + ""); + public static OOText setLocale(OOText ootext, String locale) { + return OOText.fromString(String.format("", locale) + ootext.toString() + ""); } /** - * Mark {@code s} as using the character locale "zxx", which means - * "no language", "no linguistic content". + * Mark {@code ootext} as using the character locale "zxx", which means "no language", "no + * linguistic content". * * Used around citation marks, probably to turn off spellchecking. * */ - public static OOText setLocaleNone(OOText s) { - return OOFormat.setLocale(s, "zxx"); + public static OOText setLocaleNone(OOText ootext) { + return OOFormat.setLocale(ootext, "zxx"); } /** - * Mark {@code s} using a character style {@code charStyle} + * Mark {@code ootext} using a character style {@code charStyle} * - * @param charStyle Name of a character style known to OO. May be - * empty for "Standard", which in turn means do not override any properties. + * @param charStyle Name of a character style known to OO. May be empty for "Standard", which in + * turn means do not override any properties. * */ - public static OOText setCharStyle(OOText s, String charStyle) { + public static OOText setCharStyle(OOText ootext, String charStyle) { return OOText.fromString(String.format("", charStyle) - + s.asString() - + ""); + + ootext.toString() + + ""); } /** - * Mark {@code s} as part of a paragraph with style {@code paraStyle} + * Mark {@code ootext} as part of a paragraph with style {@code paraStyle} */ - public static OOText paragraph(OOText s, String paraStyle) { + public static OOText paragraph(OOText ootext, String paraStyle) { if (paraStyle == null || "".equals(paraStyle)) { - return paragraph(s); + return paragraph(ootext); } String startTag = String.format("

", paraStyle); - return OOText.fromString(startTag + s.asString() + "

"); + return OOText.fromString(startTag + ootext.toString() + "

"); } /** - * Mark {@code s} as part of a paragraph. + * Mark {@code ootext} as part of a paragraph. */ - public static OOText paragraph(OOText s) { - return OOText.fromString("

" + s.asString() + "

"); + public static OOText paragraph(OOText ootext) { + return OOText.fromString("

" + ootext.toString() + "

"); } /** - * Format an OO cross-reference showing the target's page number - * as label to a reference mark. + * Format an OO cross-reference showing the target's page number as label to a reference mark. */ public static OOText formatReferenceToPageNumberOfReferenceMark(String referencMarkName) { - String s = String.format("", - referencMarkName); - return OOText.fromString(s); + String string = String.format("", referencMarkName); + return OOText.fromString(string); } } diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOText.java b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java index a568a7c6e8a..ad0b9fb448d 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOText.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java @@ -5,9 +5,8 @@ /** * Text with HTML-like markup as understood by OOTextIntoOO.write * - * Some of the tags can be added using OOFormat methods. Others come - * from the layout engine, either by interpreting LaTeX markup or from - * settings in the jstyle file. + * Some of the tags can be added using OOFormat methods. Others come from the layout engine, either + * by interpreting LaTeX markup or from settings in the jstyle file. */ public class OOText { @@ -19,38 +18,39 @@ private OOText(String data) { } /* null input is passed through */ - public static OOText fromString(String s) { - if (s == null) { + public static OOText fromString(String string) { + if (string == null) { return null; } - return new OOText(s); + return new OOText(string); } /* null input is passed through */ - public static String toString(OOText s) { - if (s == null) { + public static String toString(OOText ootext) { + if (ootext == null) { return null; } - return s.data; + return ootext.data; } - public String asString() { + @Override + public String toString() { return data; } /* Object.equals */ @Override - public boolean equals(Object o) { + public boolean equals(Object object) { - if (o == this) { + if (object == this) { return true; } - if (!(o instanceof OOText)) { + if (!(object instanceof OOText)) { return false; } - OOText c = (OOText) o; + OOText c = (OOText) object; return data.equals(c.data); } diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java index 298329f3a43..0758d515446 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java @@ -32,7 +32,6 @@ import com.sun.star.beans.XPropertySet; import com.sun.star.beans.XPropertySetInfo; import com.sun.star.beans.XPropertyState; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.Locale; import com.sun.star.lang.WrappedTargetException; import com.sun.star.style.CaseMap; @@ -45,8 +44,7 @@ import org.slf4j.LoggerFactory; /** - * Interpret OOText into an OpenOffice or LibreOffice writer - * document. + * Interpret OOText into an OpenOffice or LibreOffice writer document. */ @AllowedToUseAwt("Requires AWT for changing document properties") public class OOTextIntoOO { @@ -148,24 +146,17 @@ private OOTextIntoOO() { */ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) throws - UnknownPropertyException, PropertyVetoException, WrappedTargetException, - IllegalArgumentException, - NoSuchElementException, CreationException { - final boolean debugThisFun = false; - Objects.requireNonNull(doc); Objects.requireNonNull(ootext); Objects.requireNonNull(position); String lText = OOText.toString(ootext); - if (debugThisFun) { - System.out.println(lText); - } + LOGGER.debug(lText); XText text = position.getText(); XTextCursor cursor = text.createTextCursorByRange(position); @@ -242,15 +233,11 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) //

if (value != null && !value.equals("")) { if (setParagraphStyle(cursor, value)) { - if (debugThisFun) { - // Presumably tested already: - LOGGER.warn(String.format("oo:ParaStyleName=\"%s\" failed", value)); - } + // Presumably tested already: + LOGGER.debug(String.format("oo:ParaStyleName=\"%s\" failed", value)); } } else { - if (debugThisFun) { - LOGGER.warn(String.format("oo:ParaStyleName inherited")); - } + LOGGER.debug(String.format("oo:ParaStyleName inherited")); } break; default: @@ -359,10 +346,10 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) */ public static void removeDirectFormatting(XTextCursor cursor) { - XMultiPropertyStates mpss = UnoCast.unoQI(XMultiPropertyStates.class, cursor); + XMultiPropertyStates mpss = UnoCast.cast(XMultiPropertyStates.class, cursor).get(); - XPropertySet propertySet = UnoCast.unoQI(XPropertySet.class, cursor); - XPropertyState xPropertyState = UnoCast.unoQI(XPropertyState.class, cursor); + XPropertySet propertySet = UnoCast.cast(XPropertySet.class, cursor).get(); + XPropertyState xPropertyState = UnoCast.cast(XPropertyState.class, cursor).get(); try { // Special handling @@ -370,7 +357,6 @@ public static void removeDirectFormatting(XTextCursor cursor) { xPropertyState.setPropertyToDefault("CharCaseMap"); } catch (UnknownPropertyException | PropertyVetoException | - IllegalArgumentException | WrappedTargetException ex) { LOGGER.warn("exception caught", ex); } @@ -378,8 +364,8 @@ public static void removeDirectFormatting(XTextCursor cursor) { mpss.setAllPropertiesToDefault(); /* - * Now that we have called setAllPropertiesToDefault, check which properties - * are not set to default and try to correct what we can and seem necessary. + * Now that we have called setAllPropertiesToDefault, check which properties are not set to + * default and try to correct what we can and seem necessary. * * Note: tested with LibreOffice : 6.4.6.2 */ @@ -396,7 +382,7 @@ public static void removeDirectFormatting(XTextCursor cursor) { "ParaStyleName"); // query again, just in case it matters - propertySet = UnoCast.unoQI(XPropertySet.class, cursor); + propertySet = UnoCast.cast(XPropertySet.class, cursor).get(); XPropertySetInfo propertySetInfo = propertySet.getPropertySetInfo(); // check the result @@ -409,7 +395,7 @@ public static void removeDirectFormatting(XTextCursor cursor) { continue; } } catch (UnknownPropertyException ex) { - throw new RuntimeException("Unexpected UnknownPropertyException"); + throw new java.lang.IllegalStateException("Unexpected UnknownPropertyException"); } if (knownToFail.contains(p.Name)) { continue; @@ -421,8 +407,8 @@ public static void removeDirectFormatting(XTextCursor cursor) { static class MyPropertyStack { /* - * We only try to control these. Should include all character - * properties we set, and maybe their interdependencies. + * We only try to control these. Should include all character properties we set, and maybe + * their interdependencies. * * For a list of properties see: * https://www.openoffice.org/api/docs/common/ref/com/sun/star/style/CharacterProperties.html @@ -479,17 +465,15 @@ static class MyPropertyStack { final String[] goodNames; /** - * Maintain a stack of layers, each containing a description - * of the desired state of properties. Each description is an - * ArrayList of property values, Optional.empty() encoding - * "not directly set". + * Maintain a stack of layers, each containing a description of the desired state of + * properties. Each description is an ArrayList of property values, Optional.empty() + * encoding "not directly set". */ final Stack>> layers; - MyPropertyStack(XTextCursor cursor) - throws UnknownPropertyException { + MyPropertyStack(XTextCursor cursor) { - XPropertySet propertySet = UnoCast.unoQI(XPropertySet.class, cursor); + XPropertySet propertySet = UnoCast.cast(XPropertySet.class, cursor).get(); XPropertySetInfo propertySetInfo = propertySet.getPropertySetInfo(); /* @@ -515,8 +499,7 @@ static class MyPropertyStack { goodNames[ entry.getValue() ] = entry.getKey(); } - // XMultiPropertySet.setPropertyValues() - // requires alphabetically sorted property names. + // XMultiPropertySet.setPropertyValues() requires alphabetically sorted property names. // We adjust here: Arrays.sort(goodNames); for (int i = 0; i < goodSize; i++) { @@ -524,12 +507,17 @@ static class MyPropertyStack { } /* - * Get the initial state of the properties and add add the first layer. + * Get the initial state of the properties and add the first layer. */ - XMultiPropertyStates mpss = UnoCast.unoQI(XMultiPropertyStates.class, cursor); - PropertyState[] propertyStates = mpss.getPropertyStates(goodNames); + XMultiPropertyStates mpss = UnoCast.cast(XMultiPropertyStates.class, cursor).get(); + PropertyState[] propertyStates = null; + try { + propertyStates = mpss.getPropertyStates(goodNames); + } catch (UnknownPropertyException ex) { + throw new java.lang.IllegalStateException("Caught unexpected UnknownPropertyException"); + } - XMultiPropertySet mps = UnoCast.unoQI(XMultiPropertySet.class, cursor); + XMultiPropertySet mps = UnoCast.cast(XMultiPropertySet.class, cursor).get(); Object[] initialValues = mps.getPropertyValues(goodNames); ArrayList> initialValuesOpt = new ArrayList<>(goodSize); @@ -547,9 +535,8 @@ static class MyPropertyStack { } /** - * Given a list of property name, property value pairs, - * construct and push a new layer describing the intended - * state after these have been applied. + * Given a list of property name, property value pairs, construct and push a new layer + * describing the intended state after these have been applied. * * Opening tags usually call this. */ @@ -582,11 +569,12 @@ void popLayer() { /** * Apply the current desired formatting state to a cursor. + * * The idea is to minimize the number of calls to OpenOffice. */ void apply(XTextCursor cursor) { - XMultiPropertySet mps = UnoCast.unoQI(XMultiPropertySet.class, cursor); - XMultiPropertyStates mpss = UnoCast.unoQI(XMultiPropertyStates.class, cursor); + XMultiPropertySet mps = UnoCast.cast(XMultiPropertySet.class, cursor).get(); + XMultiPropertyStates mpss = UnoCast.cast(XMultiPropertyStates.class, cursor).get(); ArrayList> topLayer = layers.peek(); try { // select values to be set @@ -608,11 +596,9 @@ void apply(XTextCursor cursor) { mpss.setPropertiesToDefault(delNamesArray); mps.setPropertyValues(namesArray, values.toArray()); } catch (UnknownPropertyException ex) { - LOGGER.warn("UnknownPropertyException in MyPropertyStack.apply"); + LOGGER.warn("UnknownPropertyException in MyPropertyStack.apply", ex); } catch (PropertyVetoException ex) { LOGGER.warn("PropertyVetoException in MyPropertyStack.apply"); - } catch (IllegalArgumentException ex) { - LOGGER.warn("IllegalArgumentException in MyPropertyStack.apply"); } catch (WrappedTargetException ex) { LOGGER.warn("WrappedTargetException in MyPropertyStack.apply"); } @@ -648,18 +634,18 @@ private static List> parseAttributes(String s) { } /* - * We rely on property values being either DIRECT_VALUE or - * DEFAULT_VALUE (not AMBIGUOUS_VALUE). If the cursor covers a homogeneous region, - * or is collapsed, then this is true. + * We rely on property values being either DIRECT_VALUE or DEFAULT_VALUE (not + * AMBIGUOUS_VALUE). If the cursor covers a homogeneous region, or is collapsed, then this is + * true. */ private static boolean isPropertyDefault(XTextCursor cursor, String propertyName) throws UnknownPropertyException { - XPropertyState xPropertyState = UnoCast.unoQI(XPropertyState.class, cursor); + XPropertyState xPropertyState = UnoCast.cast(XPropertyState.class, cursor).get(); PropertyState state = xPropertyState.getPropertyState(propertyName); if (state == PropertyState.AMBIGUOUS_VALUE) { - throw new RuntimeException("PropertyState.AMBIGUOUS_VALUE" - + " (expected properties for a homogeneous cursor)"); + throw new java.lang.IllegalArgumentException("PropertyState.AMBIGUOUS_VALUE" + + " (expected properties for a homogeneous cursor)"); } return state == PropertyState.DEFAULT_VALUE; } @@ -723,7 +709,7 @@ private static List> setCharLocale(Locale value) { */ private static List> setCharLocale(String value) { if (value == null || "".equals(value)) { - throw new RuntimeException("setCharLocale \"\" or null"); + throw new java.lang.IllegalArgumentException("setCharLocale \"\" or null"); } String[] parts = value.split("-"); String language = (parts.length > 0) ? parts[0] : ""; @@ -735,8 +721,8 @@ private static List> setCharLocale(String value) { /* * SuperScript and SubScript. * - * @param relative If true, calculate the new values relative to - * the current values. This allows subscript-in-superscript. + * @param relative If true, calculate the new values relative to the current values. This allows + * subscript-in-superscript. */ private static List> setCharEscapement(Optional value, Optional height, @@ -796,22 +782,28 @@ public static boolean setParagraphStyle(XTextCursor cursor, String paragraphStyl final boolean FAIL = true; final boolean PASS = false; - XParagraphCursor paragraphCursor = UnoCast.unoQI(XParagraphCursor.class, cursor); - XPropertySet propertySet = UnoCast.unoQI(XPropertySet.class, paragraphCursor); + XParagraphCursor paragraphCursor = UnoCast.cast(XParagraphCursor.class, cursor).get(); + XPropertySet propertySet = UnoCast.cast(XPropertySet.class, paragraphCursor).get(); try { propertySet.setPropertyValue(PARA_STYLE_NAME, paragraphStyle); return PASS; } catch (UnknownPropertyException | PropertyVetoException - | IllegalArgumentException + | com.sun.star.lang.IllegalArgumentException | WrappedTargetException ex) { return FAIL; } } - private static void insertParagraphBreak(XText text, XTextCursor cursor) - throws IllegalArgumentException { - text.insertControlCharacter(cursor, ControlCharacter.PARAGRAPH_BREAK, true); + private static void insertParagraphBreak(XText text, XTextCursor cursor) { + try { + text.insertControlCharacter(cursor, ControlCharacter.PARAGRAPH_BREAK, true); + } catch (com.sun.star.lang.IllegalArgumentException ex) { + // Assuming it means wrong code for ControlCharacter. + // https://api.libreoffice.org/docs/idl/ref/ does not tell. + // If my assumption is correct, we never get here. + throw new java.lang.IllegalArgumentException("Caught unexpected com.sun.star.lang.IllegalArgumentException", ex); + } } } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java b/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java index 3f780274b0f..e08a7f4a2ad 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java @@ -13,23 +13,21 @@ import com.sun.star.text.XTextViewCursor; /* - * A problem with XTextViewCursor: if it is not in text, then we get a - * crippled version that does not support viewCursor.getStart() or - * viewCursor.gotoRange(range,false), and will throw an exception - * instead. + * A problem with XTextViewCursor: if it is not in text, then we get a crippled version that does + * not support viewCursor.getStart() or viewCursor.gotoRange(range,false), and will throw an + * exception instead. * - * Here we manipulate the cursor via XSelectionSupplier.getSelection and - * XSelectionSupplier.select to move it to the text. + * Here we manipulate the cursor via XSelectionSupplier.getSelection and XSelectionSupplier.select + * to move it to the text. * * Seems to work when the user selected a frame or image. * In these cases restoring the selection works, too. * - * When the cursor is in a comment (referred to as "annotation" in OO - * API) then initialSelection is null, and select() fails to - * get a functional viewCursor. + * When the cursor is in a comment (referred to as "annotation" in OO API) then initialSelection is + * null, and select() fails to get a functional viewCursor. * - * If FunctionalTextViewCursor.get() reports error, we have to ask the - * user to move the cursor into the text part of the document. + * If FunctionalTextViewCursor.get() reports error, we have to ask the user to move the cursor into + * the text part of the document. * * Usage: * @@ -45,19 +43,13 @@ */ public class FunctionalTextViewCursor { - /* - * The initial position of the cursor or null. - */ + /* The initial position of the cursor or null. */ private XTextRange initialPosition; - /* - * The initial selection in the document or null. - */ + /* The initial selection in the document or null. */ private XServiceInfo initialSelection; - /* - * The view cursor, potentially moved from its original location. - */ + /* The view cursor, potentially moved from its original location. */ private XTextViewCursor viewCursor; private FunctionalTextViewCursor(XTextRange initialPosition, @@ -71,12 +63,10 @@ private FunctionalTextViewCursor(XTextRange initialPosition, /* * Get a functional XTextViewCursor or an error message. * - * The cursor position may differ from the location - * provided by the user. + * The cursor position may differ from the location provided by the user. * - * On failure the constructor restores the selection. On success, - * the caller may want to call instance.restore() after finished - * using the cursor. + * On failure the constructor restores the selection. On success, the caller may want to call + * instance.restore() after finished using the cursor. */ public static OOResult get(XTextDocument doc) { @@ -89,9 +79,7 @@ public static OOResult get(XTextDocument doc) try { initialPosition = UnoCursor.createTextCursorByRange(viewCursor); viewCursor.getStart(); - return OOResult.ok(new FunctionalTextViewCursor(initialPosition, - initialSelection, - viewCursor)); + return OOResult.ok(new FunctionalTextViewCursor(initialPosition, initialSelection, viewCursor)); } catch (com.sun.star.uno.RuntimeException ex) { // bad cursor viewCursor = null; @@ -100,8 +88,7 @@ public static OOResult get(XTextDocument doc) } if (initialSelection == null) { - String errorMessage = ("Selection is not available:" - + " cannot provide a functional view cursor"); + String errorMessage = ("Selection is not available: cannot provide a functional view cursor"); return OOResult.error(errorMessage); } else if (!Arrays.stream(initialSelection.getSupportedServiceNames()) .anyMatch("com.sun.star.text.TextRanges"::equals)) { @@ -149,10 +136,7 @@ private static void restore(XTextDocument doc, } } - /* - * Restore initial state of viewCursor (possibly by restoring - * selection) if possible. - */ + /* Restore initial state of viewCursor (possibly by restoring selection) if possible. */ public void restore(XTextDocument doc) { FunctionalTextViewCursor.restore(doc, initialPosition, initialSelection); } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java index 35d2d006fab..9a3ef1c9968 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java @@ -19,7 +19,8 @@ private RangeOverlapBetween() { } /** * Check for any overlap between two sets of XTextRange values. * - * Assume fewHolders is small (usually 1 elements for checking the cursor) + * Assume fewHolders is small (usually a single element, for checking the cursor) + * * Returns on first problem found. */ public static @@ -34,16 +35,22 @@ List> findFirst(XTextDocument doc, return result; } - List> fewTuples = - new ArrayList<>(fewHolders.size()); - - for (V aHolder : fewHolders) { - XText aText = aHolder.getRange().getText(); - fewTuples.add(new OOTuple3<>(aText, - UnoCast.unoQI(XTextRangeCompare.class, aText), - aHolder)); + /* + * Cache all we need to know about fewHolders. We are trying to minimize the number of calls + * to LO. + */ + List> fewTuples = new ArrayList<>(fewHolders.size()); + + for (V aHolder : fewHolders) { + XText aText = aHolder.getRange().getText(); + fewTuples.add(new OOTuple3<>(aText, + UnoCast.cast(XTextRangeCompare.class, aText).get(), + aHolder)); } + /* + * We only go through manyHolders once: fewTuples is in the inner loop. + */ for (V bHolder : manyHolders) { XTextRange bRange = bHolder.getRange(); XText bText = bRange.getText(); @@ -58,25 +65,24 @@ List> findFirst(XTextDocument doc, if (aText != bText) { continue; } - int abEndToStart = -1 * cmp.compareRegionStarts(aRange.getEnd(), bRangeStart); + int abEndToStart = UnoTextRange.compareStartsUnsafe(cmp, aRange.getEnd(), bRangeStart); if (abEndToStart < 0 || (!includeTouching && (abEndToStart == 0))) { continue; } - int baEndToStart = -1 * cmp.compareRegionStarts(bRangeEnd, aRange.getStart()); + int baEndToStart = UnoTextRange.compareStartsUnsafe(cmp, bRangeEnd, aRange.getStart()); if (baEndToStart < 0 || (!includeTouching && (baEndToStart == 0))) { continue; } - boolean equal = UnoTextRange.compareStartsThenEnds(aRange, bRange) == 0; + boolean equal = UnoTextRange.compareStartsThenEndsUnsafe(cmp, aRange, bRange) == 0; boolean touching = (abEndToStart == 0 || baEndToStart == 0); - // In case of two equal collapsed ranges there is an - // ambiguity : TOUCH or EQUAL_RANGE ? + // In case of two equal collapsed ranges there is an ambiguity : TOUCH or EQUAL_RANGE ? + // // We return EQUAL_RANGE - RangeOverlapKind kind = - (equal ? RangeOverlapKind.EQUAL_RANGE - : (touching ? RangeOverlapKind.TOUCH - : RangeOverlapKind.OVERLAP)); + RangeOverlapKind kind = (equal ? RangeOverlapKind.EQUAL_RANGE + : (touching ? RangeOverlapKind.TOUCH + : RangeOverlapKind.OVERLAP)); List valuesForOverlappingRanges = new ArrayList<>(); valuesForOverlappingRanges.add(aHolder); diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java index 62ee6d82ca0..e4df2d8278c 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java @@ -15,17 +15,21 @@ public class RangeOverlapWithin { private RangeOverlapWithin() { } /** - * Report identical, overlapping or touching ranges between - * elements of rangeHolders. + * Report identical, overlapping or touching ranges between elements of rangeHolders. * - * For overlapping and touching, only report consecutive ranges - * and only with a single sample of otherwise identical ranges. + * For overlapping and touching, only report consecutive ranges and only with a single sample of + * otherwise identical ranges. + * + * @param rangeHolders represent the ranges to be checked. + * + * Note: for each rangeHolder, rangeHolder.getRange() is called multiple times. + * To avoid repeated work, they should keep a copy of the range instead of + * getting it each time from the document. * * @param reportAtMost Limit the number of records returned to atMost. * Zero {@code reportAtMost} means no limit. * - * @param includeTouching Should the result contain ranges - * sharing only a boundary? + * @param includeTouching Should the result contain ranges sharing only a boundary? */ public static List> findOverlappingRanges(XTextDocument doc, @@ -43,14 +47,13 @@ List> findOverlappingRanges(XTextDocument doc, /** * Report identical, overlapping or touching ranges. * - * For overlapping and touching, only report consecutive ranges - * and only with a single sample of otherwise identical ranges. + * For overlapping and touching, only report consecutive ranges and only with a single sample of + * otherwise identical ranges. * * @param atMost Limit the number of records returned to atMost. * Zero {@code atMost} means no limit. * - * @param includeTouching Should the result contain ranges - * sharing only a boundary? + * @param includeTouching Should the result contain ranges sharing only a boundary? */ public static List> findOverlappingRanges(RangeSort.RangePartitions input, @@ -64,8 +67,8 @@ List> findOverlappingRanges(RangeSort.RangePartitions input, if (partition.size() == 0) { continue; } - XTextRangeCompare cmp = UnoCast.unoQI(XTextRangeCompare.class, - partition.get(0).getRange().getText()); + XTextRangeCompare cmp = UnoCast.cast(XTextRangeCompare.class, + partition.get(0).getRange().getText()).get(); for (int i = 0; i < (partition.size() - 1); i++) { V aHolder = partition.get(i); diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java index f7fbe37ba25..e389c902b90 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java @@ -29,7 +29,12 @@ public boolean contains(XTextRange range) { return partitions.get(partitionKey).contains(range); } - /* return false if already contained */ + /* + * return false if already contained + * + * Beware: using UnoTextRange::compareStartsThenEnds as comparator involves range.getText() + * twice on each comparison. This makes it costly to use this class. + */ public boolean add(XTextRange range) { TreeSet partition = partitions.get(range.getText()); if (partition == null) { diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java index 2f5daa0e1aa..1b4fc327598 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java @@ -23,7 +23,7 @@ public static class HolderComparatorWithinPartition implements Comparator - void sortWithinPartition(List rangeHolders) { + /* + * Sort a list of RangeHolder values known to share the same getText(). + * + * Note: RangeHolder.getRange() is called many times. + */ + public static void sortWithinPartition(List rangeHolders) { if (rangeHolders.isEmpty()) { return; } @@ -70,8 +74,7 @@ public List> getPartitions() { } } - public static - RangePartitions partitionRanges(List holders) { + public static RangePartitions partitionRanges(List holders) { RangePartitions result = new RangePartitions<>(); for (V holder : holders) { result.add(holder); @@ -79,8 +82,10 @@ RangePartitions partitionRanges(List holders) { return result; } - public static - RangePartitions partitionAndSortRanges(List holders) { + /* + * Note: RangeHolder.getRange() is called many times. + */ + public static RangePartitions partitionAndSortRanges(List holders) { RangePartitions result = partitionRanges(holders); for (List partition : result.getPartitions()) { sortWithinPartition(partition); diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java index 2131c3cecb9..969f9fed44e 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java @@ -21,11 +21,10 @@ * * Requires functional XTextViewCursor. * - * Problem: for multicolumn layout and when viewing pages side-by-side - * in LO, the (top-down,left-to-right) order interpreted - * as-on-the-screen: an XTextRange at the top of the second - * column or second page is sorted before one at the bottom - * of the first column of the first page. + * Problem: for multicolumn layout and when viewing pages side-by-side in LO, the + * (top-down,left-to-right) order interpreted as-on-the-screen: an XTextRange at the top of + * the second column or second page is sorted before an XTextRange at the bottom of the + * first column of the first page. */ public class RangeSortVisual { @@ -36,8 +35,7 @@ public class RangeSortVisual { * * Requires a functional {@code XTextViewCursor}. * - * @return The input, sorted by the elements XTextRange and - * getIndexInPosition. + * @return The input, sorted by the elements XTextRange and getIndexInPosition. */ public static List> visualSort(List> inputs, XTextDocument doc, @@ -49,12 +47,9 @@ public static List> visualSort(List> input final int inputSize = inputs.size(); if (UnoScreenRefresh.hasControllersLocked(doc)) { - LOGGER.warn("visualSort:" - + " with ControllersLocked, viewCursor.gotoRange" - + " is probably useless"); - throw new RuntimeException("visualSort:" - + " with ControllersLocked, viewCursor.gotoRange" - + " is probably useless"); + final String msg = "visualSort: with ControllersLocked, viewCursor.gotoRange is probably useless"; + LOGGER.warn(msg); + throw new IllegalStateException(msg); } XTextViewCursor viewCursor = fcursor.getViewCursor(); @@ -62,13 +57,12 @@ public static List> visualSort(List> input // find coordinates List positions = new ArrayList<>(inputSize); for (RangeSortable v : inputs) { - positions.add(findPositionOfTextRange(v.getRange(), - viewCursor)); + positions.add(findPositionOfTextRange(v.getRange(), viewCursor)); } fcursor.restore(doc); if (positions.size() != inputSize) { - throw new RuntimeException("visualSort: positions.size() != inputSize"); + throw new IllegalStateException("visualSort: positions.size() != inputSize"); } // order by position @@ -82,7 +76,7 @@ public static List> visualSort(List> input Collections.sort(set); if (set.size() != inputSize) { - throw new RuntimeException("visualSort: set.size() != inputSize"); + throw new IllegalStateException("visualSort: set.size() != inputSize"); } // collect ordered result @@ -92,26 +86,24 @@ public static List> visualSort(List> input } if (result.size() != inputSize) { - throw new RuntimeException("visualSort: result.size() != inputSize"); + throw new IllegalStateException("visualSort: result.size() != inputSize"); } return result; } /** - * Given a location, return its position: coordinates relative to - * the top left position of the first page of the document. + * Given a location, return its position: coordinates relative to the top left position of the + * first page of the document. * - * Note: for text layouts with two or more columns, this gives the - * wrong order: top-down/left-to-right does not match - * reading order. + * Note: for text layouts with two or more columns, this gives the wrong order: + * top-down/left-to-right does not match reading order. * - * Note: The "relative to the top left position of the first page" - * is meant "as it appears on the screen". + * Note: The "relative to the top left position of the first page" is meant "as it appears on + * the screen". * - * In particular: when viewing pages side-by-side, the top - * half of the right page is higher than the lower half of - * the left page. Again, top-down/left-to-right does not + * In particular: when viewing pages side-by-side, the top half of the right page is + * higher than the lower half of the left page. Again, top-down/left-to-right does not * match reading order. * * @param range Location. @@ -126,8 +118,8 @@ private static Point findPositionOfTextRange(XTextRange range, XTextViewCursor c /** * A reference mark name paired with its visual position. * - * Comparison is based on (Y,X,indexInPosition): vertical compared - * first, horizontal second, indexInPosition third. + * Comparison is based on (Y,X,indexInPosition): vertical compared first, horizontal second, + * indexInPosition third. * * Used for sorting reference marks by their visual positions. */ diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java index 66e17a5b35b..c3eab225889 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java @@ -9,14 +9,12 @@ public interface RangeSortable extends RangeHolder { /** The XTextRange * - * For citation marks in footnotes this may be the range of the - * footnote mark. + * For citation marks in footnotes this may be the range of the footnote mark. */ public XTextRange getRange(); /** - * For citation marks in footnotes this may provide order within - * the footnote. + * For citation marks in footnotes this may provide order within the footnote. */ public int getIndexInPosition(); diff --git a/src/main/java/org/jabref/model/openoffice/style/Citation.java b/src/main/java/org/jabref/model/openoffice/style/Citation.java index f0b732a9240..3f949237e07 100644 --- a/src/main/java/org/jabref/model/openoffice/style/Citation.java +++ b/src/main/java/org/jabref/model/openoffice/style/Citation.java @@ -112,7 +112,7 @@ public void setUniqueLetter(Optional uniqueLetter) { public void setPageInfo(Optional v) { Optional vv = PageInfo.normalizePageInfo(v); if (!vv.equals(v)) { - throw new RuntimeException("setPageInfo argument is not normalized"); + throw new IllegalArgumentException("setPageInfo argument is not normalized"); } this.pageInfo = vv; } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java index 075c55cc2ef..2986a6f4501 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java @@ -36,15 +36,14 @@ public class CitationGroup { * A name of a reference mark to link to by formatCitedOnPages. * May be initially empty, if backend does not use reference marks. * - * produceCitationMarkers might want fill it to support - * cross-references to citation groups from the bibliography. + * produceCitationMarkers might want fill it to support cross-references to citation groups from + * the bibliography. */ private Optional referenceMarkNameForLinking; /* - * Indices into citations: citations[localOrder[i]] provides ith - * citation according to the currently imposed local order for - * presentation. + * Indices into citations: citations[localOrder[i]] provides ith citation according to the + * currently imposed local order for presentation. * * Initialized to (0..(nCitations-1)) in the constructor. */ diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java index bac1e3c1387..6ba6b760cb6 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java @@ -10,8 +10,7 @@ public CitationGroupId(String id) { } /** - * CitationEntry needs some string identifying the group - * that it can pass back later. + * CitationEntry needs some string identifying the group that it can pass back later. */ public String citationGroupIdAsString() { return id; diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java index f68aa4f115c..bd0cca64e13 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java @@ -20,8 +20,7 @@ /** * CitationGroups : the set of citation groups in the document. * - * This is the main input (as well as output) for creating citation - * markers and bibliography. + * This is the main input (as well as output) for creating citation markers and bibliography. * */ public class CitationGroups { @@ -56,8 +55,7 @@ public int numberOfCitationGroups() { } /** - * For each citation in {@code where} - * call {@code fun.accept(new Pair(citation, value));} + * For each citation in {@code where} call {@code fun.accept(new Pair(citation, value));} */ public void distributeToCitations(List where, Consumer> fun, @@ -84,21 +82,19 @@ public void lookupCitations(List databases) { if (true) { // collect-lookup-distribute // - // CitationDatabaseLookupResult for the same citation key - // is the same object. Until we insert a new citation from the GUI. + // CitationDatabaseLookupResult for the same citation key is the same object. Until we + // insert a new citation from the GUI. CitedKeys cks = getCitedKeysUnordered(); cks.lookupInDatabases(databases); cks.distributeLookupResults(this); } else { // lookup each citation directly // - // CitationDatabaseLookupResult for the same citation key - // may be a different object: CitedKey.addPath has to use equals, - // so CitationDatabaseLookupResult has to override Object.equals, - // which depends on BibEntry.equals and BibDatabase.equals - // doing the right thing. Seems to work. But what we gained - // from avoiding collect-and-distribute may be lost in more - // complicated consistency checking in addPath. + // CitationDatabaseLookupResult for the same citation key may be a different object: + // CitedKey.addPath has to use equals, so CitationDatabaseLookupResult has to override + // Object.equals, which depends on BibEntry.equals and BibDatabase.equals doing the + // right thing. Seems to work. But what we gained from avoiding collect-and-distribute + // may be lost in more complicated consistency checking in addPath. // for (CitationGroup cg : getCitationGroupsUnordered()) { for (Citation cit : cg.citationsInStorageOrder) { @@ -117,22 +113,21 @@ public List getCitationGroupsUnordered() { */ public List getCitationGroupsInGlobalOrder() { if (globalOrder.isEmpty()) { - throw new RuntimeException("getCitationGroupsInGlobalOrder: not ordered yet"); + throw new IllegalStateException("getCitationGroupsInGlobalOrder: not ordered yet"); } return OOListUtil.map(globalOrder.get(), cgid -> citationGroupsUnordered.get(cgid)); } /** - * Impose an order of citation groups by providing the order - * of their citation group idendifiers. + * Impose an order of citation groups by providing the order of their citation group + * idendifiers. * * Also set indexInGlobalOrder for each citation group. */ public void setGlobalOrder(List globalOrder) { Objects.requireNonNull(globalOrder); if (globalOrder.size() != numberOfCitationGroups()) { - throw new RuntimeException("setGlobalOrder:" - + " globalOrder.size() != numberOfCitationGroups()"); + throw new IllegalStateException("setGlobalOrder: globalOrder.size() != numberOfCitationGroups()"); } this.globalOrder = Optional.of(globalOrder); @@ -158,8 +153,8 @@ public void imposeLocalOrder(Comparator entryComparator) { } /** - * Collect citations into a list of cited sources using neither - * CitationGroup.globalOrder or Citation.localOrder + * Collect citations into a list of cited sources using neither CitationGroup.globalOrder or + * Citation.localOrder */ public CitedKeys getCitedKeysUnordered() { LinkedHashMap res = new LinkedHashMap<>(); @@ -185,7 +180,7 @@ public CitedKeys getCitedKeysUnordered() { public CitedKeys getCitedKeysSortedInOrderOfAppearance() { LinkedHashMap res = new LinkedHashMap<>(); if (!hasGlobalOrder()) { - throw new RuntimeException("getSortedCitedKeys: no globalOrder"); + throw new IllegalStateException("getSortedCitedKeys: no globalOrder"); } for (CitationGroup cg : getCitationGroupsInGlobalOrder()) { for (int i : cg.getLocalOrder()) { @@ -224,8 +219,8 @@ public List getUnresolvedKeys() { public void createNumberedBibliographySortedInOrderOfAppearance() { if (!bibliography.isEmpty()) { - throw new RuntimeException("createNumberedBibliographySortedInOrderOfAppearance:" - + " already have a bibliography"); + throw new IllegalStateException("createNumberedBibliographySortedInOrderOfAppearance:" + + " already have a bibliography"); } CitedKeys citedKeys = getCitedKeysSortedInOrderOfAppearance(); citedKeys.numberCitedKeysInCurrentOrder(); @@ -238,8 +233,7 @@ public void createNumberedBibliographySortedInOrderOfAppearance() { */ public void createPlainBibliographySortedByComparator(Comparator entryComparator) { if (!bibliography.isEmpty()) { - throw new RuntimeException("createPlainBibliographySortedByComparator:" - + " already have a bibliography"); + throw new IllegalStateException("createPlainBibliographySortedByComparator: already have a bibliography"); } CitedKeys citedKeys = getCitedKeysUnordered(); citedKeys.sortByComparator(entryComparator); @@ -251,8 +245,7 @@ public void createPlainBibliographySortedByComparator(Comparator entry */ public void createNumberedBibliographySortedByComparator(Comparator entryComparator) { if (!bibliography.isEmpty()) { - throw new RuntimeException("createNumberedBibliographySortedByComparator:" - + " already have a bibliography"); + throw new IllegalStateException("createNumberedBibliographySortedByComparator: already have a bibliography"); } CitedKeys citedKeys = getCitedKeysUnordered(); citedKeys.sortByComparator(entryComparator); @@ -270,18 +263,6 @@ public Optional getCitationGroup(CitationGroupId cgid) { return Optional.ofNullable(cg); } - /** - * Call this when the citation group is unquestionably there. - */ - public CitationGroup getCitationGroupOrThrow(CitationGroupId cgid) { - CitationGroup cg = citationGroupsUnordered.get(cgid); - if (cg == null) { - throw new RuntimeException("getCitationGroupOrThrow:" - + " the requested CitationGroup is not available"); - } - return cg; - } - /* * @return true if all citation groups have referenceMarkNameForLinking */ diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java b/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java index 866a0de34c3..b17ec100ee2 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java @@ -23,8 +23,7 @@ public CitationLookupResult(BibEntry entry, BibDatabase database) { * Consequently, {@code this.database.equals(that.database)} below * is equivalent to {@code this.database == that.database}. * - * Since within each GUI call we use a fixed list of - * databases, it is OK. + * Since within each GUI call we use a fixed list of databases, it is OK. */ @Override public boolean equals(Object o) { diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationMarkerEntry.java b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerEntry.java index 4ab2c626b68..5fcb9bcc1a8 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationMarkerEntry.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerEntry.java @@ -5,8 +5,7 @@ import org.jabref.model.openoffice.ootext.OOText; /** - * This is what we need for createCitationMarker to produce author-year - * citation markers. + * This is what we need for createCitationMarker to produce author-year citation markers. */ public interface CitationMarkerEntry extends CitationMarkerNormEntry { @@ -17,14 +16,13 @@ public interface CitationMarkerEntry extends CitationMarkerNormEntry { /** * pageInfo for this citation, provided by the user. - * May be empty, for none. + * May be empty, for none. */ Optional getPageInfo(); /** - * @return true if this citation is the first appearance of the - * source cited. Some styles use different limit on the number of - * authors shown in this case. + * @return true if this citation is the first appearance of the source cited. Some styles use + * different limit on the number of authors shown in this case. */ boolean getIsFirstAppearanceOfSource(); } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNormEntry.java b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNormEntry.java index e9df5ec961f..a2581b38b60 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNormEntry.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNormEntry.java @@ -3,16 +3,13 @@ import java.util.Optional; /** - * This is what we need to produce normalized author-year citation - * markers. + * This is what we need to produce normalized author-year citation markers. */ public interface CitationMarkerNormEntry { /** Citation key. This is what we usually get from the document. * - * Used if getBibEntry() and/or getDatabase() returns - * empty, which indicates failure to lookup in the databases. - * + * Used if getLookupResult() returns empty, which indicates failure to lookup in the databases. */ String getCitationKey(); diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationPath.java b/src/main/java/org/jabref/model/openoffice/style/CitationPath.java index 05aeb6547f6..0920ea20feb 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationPath.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationPath.java @@ -1,8 +1,8 @@ package org.jabref.model.openoffice.style; /** - * Identifies a citation with the citation group containing it and - * its storage index within. + * Identifies a citation with the identifier of the citation group containing it and its storage + * index within. */ public class CitationPath { diff --git a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java index 08b2ffb1bb8..f577867c539 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java @@ -11,9 +11,8 @@ /** * Cited keys are collected from the citations in citation groups. * - * They contain backreferences to the corresponding citations in - * {@code where}. This allows the extra information generated using - * CitedKeys to be distributed back to the in-text citations. + * They contain backreferences to the corresponding citations in {@code where}. This allows the + * extra information generated using CitedKeys to be distributed back to the in-text citations. */ public class CitedKey implements ComparableCitedKey, @@ -106,13 +105,13 @@ void addPath(CitationPath p, Citation cit) { // Check consistency if (!cit.getLookupResult().equals(this.db)) { - throw new RuntimeException("CitedKey.addPath: mismatch on cit.db"); + throw new IllegalStateException("CitedKey.addPath: mismatch on cit.db"); } if (!cit.getNumber().equals(this.number)) { - throw new RuntimeException("CitedKey.addPath: mismatch on cit.number"); + throw new IllegalStateException("CitedKey.addPath: mismatch on cit.number"); } if (!cit.getUniqueLetter().equals(this.uniqueLetter)) { - throw new RuntimeException("CitedKey.addPath: mismatch on cit.uniqueLetter"); + throw new IllegalStateException("CitedKey.addPath: mismatch on cit.uniqueLetter"); } } diff --git a/src/main/java/org/jabref/model/openoffice/style/CompareCitation.java b/src/main/java/org/jabref/model/openoffice/style/CompareCitation.java index 916f8ec610c..966715b11a8 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CompareCitation.java +++ b/src/main/java/org/jabref/model/openoffice/style/CompareCitation.java @@ -5,8 +5,8 @@ import org.jabref.model.entry.BibEntry; /* - * Given a Comparator provide a Comparator - * that can handle unresolved citation keys and takes pageInfo into account. + * Given a Comparator provide a Comparator that can handle unresolved + * citation keys and takes pageInfo into account. */ public class CompareCitation implements Comparator { diff --git a/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java b/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java index 439d0556c2d..a5484560316 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java +++ b/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java @@ -6,8 +6,8 @@ import org.jabref.model.entry.BibEntry; /* - * Given a Comparator provide a Comparator - * that also handles unresolved citation keys. + * Given a Comparator provide a Comparator that also handles + * unresolved citation keys. */ public class CompareCitedKey implements Comparator { diff --git a/src/main/java/org/jabref/model/openoffice/style/NonUniqueCitationMarker.java b/src/main/java/org/jabref/model/openoffice/style/NonUniqueCitationMarker.java index e7d988ee216..34300734d2f 100644 --- a/src/main/java/org/jabref/model/openoffice/style/NonUniqueCitationMarker.java +++ b/src/main/java/org/jabref/model/openoffice/style/NonUniqueCitationMarker.java @@ -1,15 +1,15 @@ package org.jabref.model.openoffice.style; /** - * What should createCitationMarker do if it discovers that - * uniqueLetters provided are not sufficient for unique presentation? + * What should createCitationMarker do if it discovers that uniqueLetters provided are not + * sufficient for unique presentation? */ public enum NonUniqueCitationMarker { /** Give an insufficient representation anyway. */ FORGIVEN, - /** Throw a RuntimeException */ + /** Throw an exception */ THROWS } diff --git a/src/main/java/org/jabref/model/openoffice/style/OODataModel.java b/src/main/java/org/jabref/model/openoffice/style/OODataModel.java index 50c3a9e4842..20b2365ebf2 100644 --- a/src/main/java/org/jabref/model/openoffice/style/OODataModel.java +++ b/src/main/java/org/jabref/model/openoffice/style/OODataModel.java @@ -9,19 +9,15 @@ /** What is the data stored? */ public enum OODataModel { - /** - * JabRef52: pageInfo belongs to CitationGroup, not Citation. - */ + /** JabRef52: pageInfo belongs to CitationGroup, not Citation. */ JabRef52, - /** - * JabRef53: pageInfo belongs to Citation. - */ - JabRef53; + /** JabRef60: pageInfo belongs to Citation. */ + JabRef60; /** * @param pageInfo Nullable. - * @return JabRef53 style pageInfo list with pageInfo in the last slot. + * @return JabRef60 style pageInfo list with pageInfo in the last slot. */ public static List> fakePageInfos(String pageInfo, int nCitations) { List> pageInfos = new ArrayList<>(nCitations); diff --git a/src/main/java/org/jabref/model/openoffice/style/PageInfo.java b/src/main/java/org/jabref/model/openoffice/style/PageInfo.java index 6807ecf0753..ace7eedae02 100644 --- a/src/main/java/org/jabref/model/openoffice/style/PageInfo.java +++ b/src/main/java/org/jabref/model/openoffice/style/PageInfo.java @@ -42,6 +42,6 @@ public static int comparePageInfo(Optional a, Optional b) { if (bb.isEmpty()) { return +1; } - return aa.get().asString().compareTo(bb.get().asString()); + return aa.get().toString().compareTo(bb.get().toString()); } } 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 b97618a3231..fdbbb0dd1c6 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoBookmark.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoBookmark.java @@ -6,7 +6,6 @@ import com.sun.star.container.XNameAccess; import com.sun.star.container.XNamed; import com.sun.star.lang.DisposedException; -import com.sun.star.lang.IllegalArgumentException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XBookmarksSupplier; import com.sun.star.text.XTextContent; @@ -24,7 +23,7 @@ public static XNameAccess getNameAccess(XTextDocument doc) throws NoDocumentException { - XBookmarksSupplier supplier = UnoCast.unoQI(XBookmarksSupplier.class, doc); + XBookmarksSupplier supplier = UnoCast.cast(XBookmarksSupplier.class, doc).get(); try { return supplier.getBookmarks(); } catch (DisposedException ex) { @@ -44,45 +43,36 @@ public static Optional getAnchor(XTextDocument doc, String name) NoDocumentException { XNameAccess nameAccess = getNameAccess(doc); - return (UnoNameAccess.getTextContentByName(nameAccess, name) - .map(e -> e.getAnchor())); + return (UnoNameAccess.getTextContentByName(nameAccess, name).map(XTextContent::getAnchor)); } /** - * Insert a bookmark with the given name at the cursor provided, - * or with another name if the one we asked for is already in use. + * Insert a bookmark with the given name at the cursor provided, or with another name if the one + * we asked for is already in use. * * 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 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. + * 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) throws - IllegalArgumentException, CreationException { - return UnoNamed.insertNamedTextContent(doc, - "com.sun.star.text.Bookmark", - name, - range, - absorb); + return UnoNamed.insertNamedTextContent(doc, "com.sun.star.text.Bookmark", name, range, absorb); } /** * Remove the named bookmark if it exists. */ - public static void remove(XTextDocument doc, String name) + public static void removeIfExists(XTextDocument doc, String name) throws NoDocumentException, - NoSuchElementException, WrappedTargetException { XNameAccess marks = UnoBookmark.getNameAccess(doc); @@ -92,7 +82,11 @@ public static void remove(XTextDocument doc, String name) if (mark.isEmpty()) { return; } - doc.getText().removeTextContent(mark.get()); + try { + doc.getText().removeTextContent(mark.get()); + } catch (NoSuchElementException ex) { + // The caller gets what it expects. + } } } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoCast.java b/src/main/java/org/jabref/model/openoffice/uno/UnoCast.java index df5be51db36..fcc1bcc3e12 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoCast.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoCast.java @@ -9,16 +9,11 @@ public class UnoCast { private UnoCast() { } /** - * unoQI : short for UnoRuntime.queryInterface + * cast : short for Optional.ofNullable(UnoRuntime.queryInterface(...)) * - * @return A reference to the requested UNO interface type if available, - * otherwise null + * @return A reference to the requested UNO interface type if available, otherwise Optional.empty() */ - public static T unoQI(Class zInterface, Object object) { - return UnoRuntime.queryInterface(zInterface, object); - } - - public static Optional optUnoQI(Class zInterface, Object object) { + public static Optional cast(Class zInterface, Object object) { return Optional.ofNullable(UnoRuntime.queryInterface(zInterface, object)); } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoCrossRef.java b/src/main/java/org/jabref/model/openoffice/uno/UnoCrossRef.java index 0e8b84e8d22..37dc580a1fb 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoCrossRef.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoCrossRef.java @@ -21,53 +21,67 @@ private UnoCrossRef() { } */ public static void refresh(XTextDocument doc) { // Refresh the document - XRefreshable xRefresh = UnoCast.unoQI(XRefreshable.class, doc); + XRefreshable xRefresh = UnoCast.cast(XRefreshable.class, doc).get(); xRefresh.refresh(); } /** - * Insert a clickable cross-reference to a reference mark, - * with a label containing the target's page number. + * Insert a clickable cross-reference to a reference mark, with a label containing the target's + * page number. * - * May need a documentConnection.refresh() after, to update - * the text shown. + * May need a documentConnection.refresh() after, to update the text shown. */ public static void insertReferenceToPageNumberOfReferenceMark(XTextDocument doc, String referenceMarkName, XTextRange cursor) throws CreationException, - UnknownPropertyException, - PropertyVetoException, WrappedTargetException { // based on: https://wiki.openoffice.org/wiki/Documentation/DevGuide/Text/Reference_Marks - XMultiServiceFactory msf = UnoCast.unoQI(XMultiServiceFactory.class, doc); + XMultiServiceFactory msf = UnoCast.cast(XMultiServiceFactory.class, doc).get(); // Create a 'GetReference' text field to refer to the reference mark we just inserted, // and get it's XPropertySet interface XPropertySet xFieldProps; try { String name = "com.sun.star.text.textfield.GetReference"; - xFieldProps = (XPropertySet) UnoCast.unoQI(XPropertySet.class, - msf.createInstance(name)); - } catch (Exception e) { + xFieldProps = UnoCast.cast(XPropertySet.class, msf.createInstance(name)).get(); + } catch (com.sun.star.uno.Exception e) { throw new CreationException(e.getMessage()); } - // Set the SourceName of the GetReference text field to the referenceMarkName - xFieldProps.setPropertyValue("SourceName", referenceMarkName); + try { + // Set the SourceName of the GetReference text field to the referenceMarkName + xFieldProps.setPropertyValue("SourceName", referenceMarkName); + } catch (UnknownPropertyException ex) { + throw new java.lang.IllegalStateException("The created GetReference does not have property 'SourceName'"); + } catch (PropertyVetoException ex) { + throw new java.lang.IllegalStateException("Caught PropertyVetoException on 'SourceName'"); + } - // specify that the source is a reference mark (could also be a footnote, - // bookmark or sequence field) - xFieldProps.setPropertyValue("ReferenceFieldSource", - new Short(ReferenceFieldSource.REFERENCE_MARK)); + try { + // specify that the source is a reference mark (could also be a footnote, + // bookmark or sequence field) + xFieldProps.setPropertyValue("ReferenceFieldSource", Short.valueOf​(ReferenceFieldSource.REFERENCE_MARK)); + } catch (UnknownPropertyException ex) { + throw new java.lang.IllegalStateException("The created GetReference does not have property" + + " 'ReferenceFieldSource'"); + } catch (PropertyVetoException ex) { + throw new java.lang.IllegalStateException("Caught PropertyVetoException on 'ReferenceFieldSource'"); + } - // We want the reference displayed as page number - xFieldProps.setPropertyValue("ReferenceFieldPart", - new Short(ReferenceFieldPart.PAGE)); + try { + // We want the reference displayed as page number + xFieldProps.setPropertyValue("ReferenceFieldPart", Short.valueOf​(ReferenceFieldPart.PAGE)); + } catch (UnknownPropertyException ex) { + throw new java.lang.IllegalStateException("The created GetReference does not have property" + + " 'ReferenceFieldPart'"); + } catch (PropertyVetoException ex) { + throw new java.lang.IllegalStateException("Caught PropertyVetoException on 'ReferenceFieldPart'"); + } // Get the XTextContent interface of the GetReference text field - XTextContent xRefContent = (XTextContent) UnoCast.unoQI(XTextContent.class, xFieldProps); + XTextContent xRefContent = UnoCast.cast(XTextContent.class, xFieldProps).get(); // Insert the text field cursor.getText().insertTextContent(cursor.getEnd(), xRefContent, false); diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java b/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java index b7115feb8e1..1770b6957c5 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java @@ -18,8 +18,8 @@ private UnoCursor() { } */ public static Optional getViewCursor(XTextDocument doc) { return (UnoTextDocument.getCurrentController(doc) - .flatMap(e -> UnoCast.optUnoQI(XTextViewCursorSupplier.class, e)) - .map(e -> e.getViewCursor())); + .flatMap(e -> UnoCast.cast(XTextViewCursorSupplier.class, e)) + .map(XTextViewCursorSupplier::getViewCursor)); } /** diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoNameAccess.java b/src/main/java/org/jabref/model/openoffice/uno/UnoNameAccess.java index 3d172d11f14..243c136f382 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoNameAccess.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoNameAccess.java @@ -12,14 +12,13 @@ public class UnoNameAccess { private UnoNameAccess() { } /** - * @return null if name not found, or if the result does not - * support the XTextContent interface. + * @return null if name not found, or if the result does not support the XTextContent interface. */ public static Optional getTextContentByName(XNameAccess nameAccess, String name) throws WrappedTargetException { try { - return UnoCast.optUnoQI(XTextContent.class, nameAccess.getByName(name)); + return UnoCast.cast(XTextContent.class, nameAccess.getByName(name)); } catch (NoSuchElementException ex) { return Optional.empty(); } 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 d99b6702153..5f1f50c873d 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoNamed.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoNamed.java @@ -11,30 +11,24 @@ public class UnoNamed { private UnoNamed() { } /** - * Insert a new instance of a service at the provided cursor - * position. + * Insert a new instance of a service at the provided cursor position. * * @param service For example - * "com.sun.star.text.ReferenceMark", - * "com.sun.star.text.Bookmark" or - * "com.sun.star.text.TextSection". + * "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. + * 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 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 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. + * @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. * @@ -47,20 +41,22 @@ static XNamed insertNamedTextContent(XTextDocument doc, throws CreationException { - XMultiServiceFactory msf = UnoCast.unoQI(XMultiServiceFactory.class, doc); + XMultiServiceFactory msf = UnoCast.cast(XMultiServiceFactory.class, doc).get(); Object xObject; try { xObject = msf.createInstance(service); - } catch (Exception e) { + } catch (com.sun.star.uno.Exception e) { throw new CreationException(e.getMessage()); } - XNamed xNamed = UnoCast.unoQI(XNamed.class, xObject); + XNamed xNamed = (UnoCast.cast(XNamed.class, xObject) + .orElseThrow(() -> new IllegalArgumentException("Service is not an XNamed"))); xNamed.setName(name); // get XTextContent interface - XTextContent xTextContent = UnoCast.unoQI(XTextContent.class, xObject); + XTextContent xTextContent = (UnoCast.cast(XTextContent.class, xObject) + .orElseThrow(() -> new IllegalArgumentException("Service is not an XTextContent"))); range.getText().insertTextContent(range, xTextContent, absorb); return xNamed; } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java b/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java index 07a6de1374d..3a47818cf8b 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java @@ -26,7 +26,7 @@ private UnoProperties() { } */ public static Optional asPropertySet(XPropertyContainer propertyContainer) { - return UnoCast.optUnoQI(XPropertySet.class, propertyContainer); + return UnoCast.cast(XPropertySet.class, propertyContainer); } /* diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoRedlines.java b/src/main/java/org/jabref/model/openoffice/uno/UnoRedlines.java index a5f5ce7c6d1..2c408648d6f 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoRedlines.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoRedlines.java @@ -1,5 +1,7 @@ package org.jabref.model.openoffice.uno; +import java.util.Optional; + import com.sun.star.beans.UnknownPropertyException; import com.sun.star.beans.XPropertySet; import com.sun.star.container.NoSuchElementException; @@ -16,25 +18,30 @@ public class UnoRedlines { public static boolean getRecordChanges(XTextDocument doc) throws - UnknownPropertyException, WrappedTargetException { // https://wiki.openoffice.org/wiki/Documentation/DevGuide/Text/Settings // "Properties of com.sun.star.text.TextDocument" - XPropertySet propertySet = (UnoCast.optUnoQI(XPropertySet.class, doc) - .orElseThrow(RuntimeException::new)); + XPropertySet propertySet = UnoCast.cast(XPropertySet.class, doc).get(); - return (boolean) propertySet.getPropertyValue("RecordChanges"); + try { + return (boolean) propertySet.getPropertyValue("RecordChanges"); + } catch (UnknownPropertyException ex) { + throw new java.lang.IllegalStateException("Caught UnknownPropertyException on 'RecordChanges'"); + } } - private static XRedlinesSupplier getRedlinesSupplier(XTextDocument doc) { - return UnoCast.unoQI(XRedlinesSupplier.class, doc); + private static Optional getRedlinesSupplier(XTextDocument doc) { + return UnoCast.cast(XRedlinesSupplier.class, doc); } public static int countRedlines(XTextDocument doc) { - XRedlinesSupplier supplier = getRedlinesSupplier(doc); - XEnumerationAccess enumerationAccess = supplier.getRedlines(); + Optional supplier = getRedlinesSupplier(doc); + if (supplier.isEmpty()) { + return 0; + } + XEnumerationAccess enumerationAccess = supplier.get().getRedlines(); XEnumeration enumeration = enumerationAccess.createEnumeration(); if (enumeration == null) { return 0; 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 8185c1ffbe3..7a719042d79 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoReferenceMark.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoReferenceMark.java @@ -22,15 +22,14 @@ private UnoReferenceMark() { } /** * @throws NoDocumentException If cannot get reference marks * - * Note: also used by `isDocumentConnectionMissing` to test if - * we have a working connection. + * Note: also used by `isDocumentConnectionMissing` to test if we have a working connection. * */ public static XNameAccess getNameAccess(XTextDocument doc) throws NoDocumentException { - XReferenceMarksSupplier supplier = UnoCast.unoQI(XReferenceMarksSupplier.class, doc); + XReferenceMarksSupplier supplier = UnoCast.cast(XReferenceMarksSupplier.class, doc).get(); try { return supplier.getReferenceMarks(); @@ -60,11 +59,10 @@ public static List getListOfNames(XTextDocument doc) * * Removes both the text and the mark itself. */ - public static void remove(XTextDocument doc, String name) + public static void removeIfExists(XTextDocument doc, String name) throws WrappedTargetException, - NoDocumentException, - NoSuchElementException { + NoDocumentException { XNameAccess xReferenceMarks = UnoReferenceMark.getNameAccess(doc); @@ -73,7 +71,11 @@ public static void remove(XTextDocument doc, String name) if (mark.isEmpty()) { return; } - doc.getText().removeTextContent(mark.get()); + try { + doc.getText().removeTextContent(mark.get()); + } catch (NoSuchElementException ex) { + // The caller gets what it expects. + } } } @@ -97,37 +99,27 @@ public static Optional getAnchor(XTextDocument doc, String name) NoDocumentException, WrappedTargetException { return (UnoReferenceMark.getAsTextContent(doc, name) - .map(e -> e.getAnchor())); + .map(XTextContent::getAnchor)); } /** - * Insert a new reference mark at the provided cursor - * position. + * 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 absorb} 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. + * 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. + * @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(XTextDocument doc, String name, XTextRange range, boolean absorb) throws CreationException { - return UnoNamed.insertNamedTextContent(doc, - "com.sun.star.text.ReferenceMark", - name, - range, - absorb); + return UnoNamed.insertNamedTextContent(doc, "com.sun.star.text.ReferenceMark", name, range, absorb); } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoSelection.java b/src/main/java/org/jabref/model/openoffice/uno/UnoSelection.java index 0ef750b9983..43d89ed157b 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoSelection.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoSelection.java @@ -29,12 +29,12 @@ private static Optional getSelectionSupplier(XTextDocument d LOGGER.warn("UnoSelection.getSelectionSupplier: getCurrentController(doc) returned empty"); return Optional.empty(); } - XSelectionSupplier supplier = UnoCast.unoQI(XSelectionSupplier.class, controller.get()); - if (supplier == null) { - LOGGER.warn("UnoSelection.getSelectionSupplier: unoQI(XSelectionSupplier) returned null"); + Optional supplier = UnoCast.cast(XSelectionSupplier.class, controller.get()); + if (supplier.isEmpty()) { + LOGGER.warn("UnoSelection.getSelectionSupplier: cast to XSelectionSupplier returned empty"); return Optional.empty(); } - return Optional.of(supplier); + return supplier; } /** @@ -91,12 +91,12 @@ public static Optional getSelectionAsXServiceInfo(XTextDocument do if (selection == null) { return Optional.empty(); } - XServiceInfo result = UnoCast.unoQI(XServiceInfo.class, selection); - if (result == null) { - LOGGER.warn("unoQI(XServiceInfo) returned null"); + Optional result = UnoCast.cast(XServiceInfo.class, selection); + if (result.isEmpty()) { + LOGGER.warn("cast to XServiceInfo returned empty"); return Optional.empty(); } - return Optional.of(result); + return result; } /** diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java b/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java index 86222872597..dece8978713 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java @@ -20,26 +20,23 @@ public class UnoStyle { private UnoStyle() { } - private static Optional getStyleFromFamily(XTextDocument doc, - String familyName, - String styleName) + private static Optional getStyleFromFamily(XTextDocument doc, String familyName, String styleName) throws WrappedTargetException { - XStyleFamiliesSupplier fss = UnoCast.unoQI(XStyleFamiliesSupplier.class, doc); - XNameAccess fs = UnoCast.unoQI(XNameAccess.class, fss.getStyleFamilies()); + XStyleFamiliesSupplier fss = UnoCast.cast(XStyleFamiliesSupplier.class, doc).get(); + XNameAccess fs = UnoCast.cast(XNameAccess.class, fss.getStyleFamilies()).get(); XNameContainer xFamily; try { - xFamily = UnoCast.unoQI(XNameContainer.class, fs.getByName(familyName)); + xFamily = UnoCast.cast(XNameContainer.class, fs.getByName(familyName)).get(); } catch (NoSuchElementException ex) { String msg = String.format("Style family name '%s' is not recognized", familyName); - throw new RuntimeException(msg, ex); + throw new java.lang.IllegalArgumentException(msg, ex); } try { - Object s = xFamily.getByName(styleName); - XStyle xs = (XStyle) UnoCast.unoQI(XStyle.class, s); - return Optional.ofNullable(xs); + Object style = xFamily.getByName(styleName); + return UnoCast.cast(XStyle.class, style); } catch (NoSuchElementException ex) { return Optional.empty(); } @@ -62,7 +59,7 @@ public static Optional getInternalNameOfStyle(XTextDocument doc, String throws WrappedTargetException { return (getStyleFromFamily(doc, familyName, name) - .map(e -> e.getName())); + .map(XStyle::getName)); } public static Optional getInternalNameOfParagraphStyle(XTextDocument doc, String name) diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoTextDocument.java b/src/main/java/org/jabref/model/openoffice/uno/UnoTextDocument.java index 188a092465a..c7e94e6bb4c 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoTextDocument.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoTextDocument.java @@ -59,19 +59,18 @@ public static Optional getCurrentController(XTextDocument doc) { */ public static Optional getFrameTitle(XTextDocument doc) { - Optional frame = getCurrentController(doc).map(e -> e.getFrame()); + Optional frame = getCurrentController(doc).map(XController::getFrame); if (frame.isEmpty()) { return Optional.empty(); } - Optional propertySet = UnoCast.optUnoQI(XPropertySet.class, frame.get()); + Optional propertySet = UnoCast.cast(XPropertySet.class, frame.get()); if (propertySet.isEmpty()) { return Optional.empty(); } try { - Optional frameTitleObj = - UnoProperties.getValueAsObject(propertySet.get(), "Title"); + Optional frameTitleObj = UnoProperties.getValueAsObject(propertySet.get(), "Title"); if (frameTitleObj.isEmpty()) { return Optional.empty(); } @@ -85,8 +84,8 @@ public static Optional getFrameTitle(XTextDocument doc) { static Optional getDocumentProperties(XTextDocument doc) { return (Optional.ofNullable(doc) - .map(e -> UnoCast.unoQI(XDocumentPropertiesSupplier.class, e)) - .map(e -> e.getDocumentProperties())); + .flatMap(e -> UnoCast.cast(XDocumentPropertiesSupplier.class, e)) + .map(XDocumentPropertiesSupplier::getDocumentProperties)); } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java b/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java index b44ed6ce38b..56cb1498e2a 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java @@ -17,12 +17,12 @@ private UnoTextRange() { } * Returns Optional.empty if not in a footnote. */ public static Optional getFootnoteMarkRange(XTextRange original) { - XFootnote footer = UnoCast.unoQI(XFootnote.class, original.getText()); - if (footer != null) { + Optional footer = UnoCast.cast(XFootnote.class, original.getText()); + if (footer.isPresent()) { // If we are inside a footnote, // find the linking footnote marker: // The footnote's anchor gives the correct position in the text: - return Optional.ofNullable(footer.getAnchor()); + return Optional.ofNullable(footer.get().getAnchor()); } return Optional.empty(); } @@ -46,9 +46,9 @@ public static int compareStartsUnsafe(XTextRangeCompare compare, XTextRange a, X public static int compareStarts(XTextRange a, XTextRange b) { if (!comparables(a, b)) { - throw new RuntimeException("compareStarts: got incomparable regions"); + throw new java.lang.IllegalArgumentException("compareStarts: got incomparable regions"); } - final XTextRangeCompare compare = UnoCast.unoQI(XTextRangeCompare.class, a.getText()); + final XTextRangeCompare compare = UnoCast.cast(XTextRangeCompare.class, a.getText()).get(); return compareStartsUnsafe(compare, a, b); } @@ -59,9 +59,9 @@ public static int compareStarts(XTextRange a, XTextRange b) { */ public static int compareEnds(XTextRange a, XTextRange b) { if (!comparables(a, b)) { - throw new RuntimeException("compareEnds: got incomparable regions"); + throw new java.lang.IllegalArgumentException("compareEnds: got incomparable regions"); } - final XTextRangeCompare compare = UnoCast.unoQI(XTextRangeCompare.class, a.getText()); + final XTextRangeCompare compare = UnoCast.cast(XTextRangeCompare.class, a.getText()).get(); return (-1) * compare.compareRegionEnds(a, b); } @@ -78,9 +78,9 @@ public static int compareStartsThenEndsUnsafe(XTextRangeCompare compare, XTextRa public static int compareStartsThenEnds(XTextRange a, XTextRange b) { if (!comparables(a, b)) { - throw new RuntimeException("compareStartsThenEnds: got incomparable regions"); + throw new java.lang.IllegalArgumentException("compareStartsThenEnds: got incomparable regions"); } - final XTextRangeCompare compare = UnoCast.unoQI(XTextRangeCompare.class, a.getText()); + final XTextRangeCompare compare = UnoCast.cast(XTextRangeCompare.class, a.getText()).get(); return compareStartsThenEndsUnsafe(compare, a, b); } } 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 107e7a0e018..3b9797f553e 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoTextSection.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoTextSection.java @@ -6,8 +6,8 @@ import com.sun.star.container.XNameAccess; import com.sun.star.container.XNamed; import com.sun.star.lang.DisposedException; -import com.sun.star.lang.IllegalArgumentException; import com.sun.star.lang.WrappedTargetException; +import com.sun.star.text.XTextContent; import com.sun.star.text.XTextDocument; import com.sun.star.text.XTextRange; import com.sun.star.text.XTextSection; @@ -23,7 +23,7 @@ public static XNameAccess getNameAccess(XTextDocument doc) throws NoDocumentException { - XTextSectionsSupplier supplier = UnoCast.unoQI(XTextSectionsSupplier.class, doc); + XTextSectionsSupplier supplier = UnoCast.cast(XTextSectionsSupplier.class, doc).get(); try { return supplier.getTextSections(); } catch (DisposedException ex) { @@ -40,9 +40,7 @@ public static Optional getByName(XTextDocument doc, String name) NoDocumentException { XNameAccess nameAccess = getNameAccess(doc); try { - return Optional.ofNullable((XTextSection) - ((Any) nameAccess.getByName(name)) - .getObject()); + return Optional.ofNullable((XTextSection) ((Any) nameAccess.getByName(name)).getObject()); } catch (NoSuchElementException ex) { return Optional.empty(); } @@ -60,31 +58,23 @@ public static Optional getAnchor(XTextDocument doc, String name) NoDocumentException { XNameAccess nameAccess = getNameAccess(doc); - return (UnoNameAccess.getTextContentByName(nameAccess, name) - .map(e -> e.getAnchor())); + return (UnoNameAccess.getTextContentByName(nameAccess, name).map(XTextContent::getAnchor)); } /** - * Create a text section with the provided name and insert it at - * the provided cursor. + * 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) throws - IllegalArgumentException, CreationException { - return UnoNamed.insertNamedTextContent(doc, - "com.sun.star.text.TextSection", - name, - range, - absorb); + return UnoNamed.insertNamedTextContent(doc, "com.sun.star.text.TextSection", name, range, absorb); } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java b/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java index 7f41515dd1c..b75bee17f3e 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java @@ -16,14 +16,13 @@ private UnoUndo() { } public static Optional getXUndoManager(XTextDocument doc) { // https://www.openoffice.org/api/docs/common/ref/com/sun/star/document/XUndoManager.html - return (UnoCast.optUnoQI(XUndoManagerSupplier.class, doc) - .map(e -> e.getUndoManager())); + return (UnoCast.cast(XUndoManagerSupplier.class, doc) + .map(XUndoManagerSupplier::getUndoManager)); } /** - * Each call to enterUndoContext must be paired by a call to - * leaveUndoContext, otherwise, the document's undo stack is - * left in an inconsistent state. + * Each call to enterUndoContext must be paired by a call to leaveUndoContext, otherwise, the + * document's undo stack is left in an inconsistent state. */ public static void enterUndoContext(XTextDocument doc, String title) { Optional um = getXUndoManager(doc); @@ -38,7 +37,7 @@ public static void leaveUndoContext(XTextDocument doc) { try { um.get().leaveUndoContext(); } catch (InvalidStateException ex) { - throw new RuntimeException("leaveUndoContext reported InvalidStateException"); + throw new IllegalStateException("leaveUndoContext reported InvalidStateException"); } } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java b/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java index dd09ae4745a..634edb0c57b 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java @@ -7,13 +7,14 @@ import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; +import com.sun.star.beans.PropertyAttribute; import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; import com.sun.star.beans.UnknownPropertyException; import com.sun.star.beans.XPropertyContainer; import com.sun.star.beans.XPropertySet; import com.sun.star.beans.XPropertySetInfo; -import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.document.XDocumentProperties; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextDocument; import com.sun.star.uno.Any; @@ -33,7 +34,7 @@ public class UnoUserDefinedProperty { private UnoUserDefinedProperty() { } public static Optional getPropertyContainer(XTextDocument doc) { - return UnoTextDocument.getDocumentProperties(doc).map(e -> e.getUserDefinedProperties()); + return UnoTextDocument.getDocumentProperties(doc).map(XDocumentProperties::getUserDefinedProperties); } public static List getListOfNames(XTextDocument doc) { @@ -43,13 +44,12 @@ public static List getListOfNames(XTextDocument doc) { } /** - * @param property Name of a custom document property in the - * current document. + * @param property Name of a custom document property in the current document. * * @return The value of the property or Optional.empty() * - * These properties are used to store extra data about - * individual citation. In particular, the `pageInfo` part. + * These properties are used to store extra data about individual citation. + * In particular, the `pageInfo` part. * */ public static Optional getStringValue(XTextDocument doc, String property) @@ -58,7 +58,7 @@ public static Optional getStringValue(XTextDocument doc, String property Optional propertySet = (UnoUserDefinedProperty.getPropertyContainer(doc) .flatMap(UnoProperties::asPropertySet)); if (propertySet.isEmpty()) { - throw new RuntimeException("getting UserDefinedProperties as XPropertySet failed"); + throw new java.lang.IllegalArgumentException("getting UserDefinedProperties as XPropertySet failed"); } try { String v = propertySet.get().getPropertyValue(property).toString(); @@ -69,17 +69,14 @@ public static Optional getStringValue(XTextDocument doc, String property } /** - * @param property Name of a custom document property in the - * current document. Created if does not exist yet. + * @param property Name of a custom document property in the current document. + * Created if does not exist yet. * * @param value The value to be stored. */ - public static void createStringProperty(XTextDocument doc, String property, String value) + public static void setStringProperty(XTextDocument doc, String property, String value) throws - NotRemoveableException, - PropertyExistException, IllegalTypeException, - IllegalArgumentException, PropertyVetoException, WrappedTargetException { @@ -89,12 +86,12 @@ public static void createStringProperty(XTextDocument doc, String property, Stri Optional container = UnoUserDefinedProperty.getPropertyContainer(doc); if (container.isEmpty()) { - throw new RuntimeException("UnoUserDefinedProperty.getPropertyContainer failed"); + throw new java.lang.IllegalArgumentException("UnoUserDefinedProperty.getPropertyContainer failed"); } Optional propertySet = container.flatMap(UnoProperties::asPropertySet); if (propertySet.isEmpty()) { - throw new RuntimeException("asPropertySet failed"); + throw new java.lang.IllegalArgumentException("asPropertySet failed"); } XPropertySetInfo propertySetInfo = propertySet.get().getPropertySetInfo(); @@ -108,60 +105,53 @@ public static void createStringProperty(XTextDocument doc, String property, Stri } } - container.get().addProperty(property, - com.sun.star.beans.PropertyAttribute.REMOVEABLE, - new Any(Type.STRING, value)); + try { + container.get().addProperty(property, PropertyAttribute.REMOVEABLE, new Any(Type.STRING, value)); + } catch (PropertyExistException ex) { + throw new java.lang.IllegalStateException("Caught PropertyExistException for property assumed not to exist"); + } } /** - * @param property Name of a custom document property in the - * current document. + * @param property Name of a custom document property in the current document. * * Logs warning if does not exist. */ public static void remove(XTextDocument doc, String property) throws - NotRemoveableException, - PropertyExistException, - IllegalTypeException, - IllegalArgumentException { + NotRemoveableException { Objects.requireNonNull(property); Optional container = UnoUserDefinedProperty.getPropertyContainer(doc); if (container.isEmpty()) { - throw new RuntimeException("getUserDefinedPropertiesAsXPropertyContainer failed"); + throw new java.lang.IllegalArgumentException("getUserDefinedPropertiesAsXPropertyContainer failed"); } try { container.get().removeProperty(property); } catch (UnknownPropertyException ex) { - LOGGER.warn(String.format("UnoUserDefinedProperty.remove(%s)" - + " This property was not there to remove", + LOGGER.warn(String.format("UnoUserDefinedProperty.remove(%s) This property was not there to remove", property)); } } /** - * @param property Name of a custom document property in the - * current document. + * @param property Name of a custom document property in the current document. * * Keep silent if property did not exist. */ public static void removeIfExists(XTextDocument doc, String property) throws - NotRemoveableException, - PropertyExistException, - IllegalTypeException, - IllegalArgumentException { + NotRemoveableException { Objects.requireNonNull(property); Optional container = UnoUserDefinedProperty.getPropertyContainer(doc); if (container.isEmpty()) { - throw new RuntimeException("getUserDefinedPropertiesAsXPropertyContainer failed"); + throw new java.lang.IllegalArgumentException("getUserDefinedPropertiesAsXPropertyContainer failed"); } try { diff --git a/src/main/java/org/jabref/model/openoffice/util/OOResult.java b/src/main/java/org/jabref/model/openoffice/util/OOResult.java index 2be478f6d8a..c90bc68ad13 100644 --- a/src/main/java/org/jabref/model/openoffice/util/OOResult.java +++ b/src/main/java/org/jabref/model/openoffice/util/OOResult.java @@ -1,50 +1,39 @@ package org.jabref.model.openoffice.util; +import java.util.NoSuchElementException; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; /* - * error cannot be null - * result cannot be null + * An instance of this class represents either the result of a computation, or an error + * value. Neither of these is allowed to be null. * * Void is not allowed for R, use OOVoidResult instead. * * Out of `isPresent()` and `isError()` exactly one is true. */ public class OOResult { + private final Optional result; private final Optional error; /** * Exactly one of the arguments should be Optional.empty() - * - * @param result - * @param error */ private OOResult(Optional result, Optional error) { this.result = result; this.error = error; } - /** - * @param result Null is not allowed. - */ public static OOResult ok(R result) { return new OOResult<>(Optional.of(result), Optional.empty()); } - /** - * @param error Null is not allowed. - */ public static OOResult error(E error) { return new OOResult<>(Optional.empty(), Optional.of(error)); } - /* - * Test state - */ - public boolean isPresent() { return result.isPresent(); } @@ -61,13 +50,9 @@ public boolean isOK() { return !isError(); } - /* - * getters - */ - public R get() { if (isError()) { - throw new RuntimeException("Cannot get from error"); + throw new NoSuchElementException("Cannot get from error"); } return result.get(); } @@ -76,10 +61,6 @@ public E getError() { return error.get(); } - /* - * Conditionals - */ - public OOResult ifPresent(Consumer fun) { if (isPresent()) { fun.accept(get()); diff --git a/src/main/java/org/jabref/model/openoffice/util/OOTuple3.java b/src/main/java/org/jabref/model/openoffice/util/OOTuple3.java index ca324ebc4ad..8742e06764f 100644 --- a/src/main/java/org/jabref/model/openoffice/util/OOTuple3.java +++ b/src/main/java/org/jabref/model/openoffice/util/OOTuple3.java @@ -1,9 +1,20 @@ package org.jabref.model.openoffice.util; +/** + * This class allows three objects to be packed together, and later accessed as fields `a`, `b` and + * `c`. + * + * Can be used to avoid creating a new class for just this purpose. + * + * Can be useful if you do not have `Trifunction` at hand but need to pass three objects at a time. + * + */ public class OOTuple3 { + public final A a; public final B b; public final C c; + public OOTuple3(A a, B b, C c) { this.a = a; this.b = b; diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java index 03a0b535e34..82d7888afd8 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java @@ -109,7 +109,7 @@ static String runGetNumCitationMarker2b(OOBibStyle style, CitationMarkerNumericEntry... s) { List input = Stream.of(s).collect(Collectors.toList()); OOText res = style.getNumCitationMarker2(input, minGroupingCount); - return res.asString(); + return res.toString(); } static CitationMarkerEntry makeCitationMarkerEntry(BibEntry entry, @@ -178,7 +178,7 @@ void testGetNumCitationMarker() throws IOException { CitationMarkerNumericEntry e2 = numEntry("key", 1, "pp. 55-56"); assertEquals(true, e2.getPageInfo().isPresent()); - assertEquals("pp. 55-56", e2.getPageInfo().get().asString()); + assertEquals("pp. 55-56", e2.getPageInfo().get().toString()); citation = runGetNumCitationMarker2b(style, -1, e2); assertEquals("[1; pp. 55-56]", citation); @@ -250,7 +250,7 @@ void testGetNumCitationMarkerUndefined() throws IOException { */ CitationMarkerNumericBibEntry x = numBibEntry("key", Optional.empty()); assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "] ", - style.getNumCitationMarkerForBibliography(x).asString()); + style.getNumCitationMarkerForBibliography(x).toString()); } @Test @@ -761,13 +761,13 @@ void testGetCitationMarkerJoinFirst() throws IOException { + "; Boström, Wäyrynen, Bodén, Beznosov & NotKruchten, 2006c]", style.createCitationMarker(citationMarkerEntries, true, - NonUniqueCitationMarker.THROWS).asString()); + NonUniqueCitationMarker.THROWS).toString()); assertEquals("Boström, Wäyrynen, Bodén, Beznosov & Kruchten [2006a,b]" + "; Boström, Wäyrynen, Bodén, Beznosov & NotKruchten [2006c]", style.createCitationMarker(citationMarkerEntries, false, - NonUniqueCitationMarker.THROWS).asString()); + NonUniqueCitationMarker.THROWS).toString()); } // Without pageInfo, only the first is isFirstAppearanceOfSource. @@ -789,7 +789,7 @@ void testGetCitationMarkerJoinFirst() throws IOException { + "; Boström et al., 2006c]", style.createCitationMarker(citationMarkerEntries, true, - NonUniqueCitationMarker.THROWS).asString()); + NonUniqueCitationMarker.THROWS).toString()); } // Without pageInfo, only the second is isFirstAppearanceOfSource. @@ -813,7 +813,7 @@ void testGetCitationMarkerJoinFirst() throws IOException { + "; Boström et al., 2006c]", style.createCitationMarker(citationMarkerEntries, true, - NonUniqueCitationMarker.THROWS).asString()); + NonUniqueCitationMarker.THROWS).toString()); } // Without pageInfo, neither is isFirstAppearanceOfSource. @@ -835,7 +835,7 @@ void testGetCitationMarkerJoinFirst() throws IOException { assertEquals("[Boström et al., 2006a,b,c]", style.createCitationMarker(citationMarkerEntries, true, - NonUniqueCitationMarker.THROWS).asString()); + NonUniqueCitationMarker.THROWS).toString()); } // With pageInfo: different entries with identical non-null pageInfo: not joined. @@ -857,7 +857,7 @@ void testGetCitationMarkerJoinFirst() throws IOException { + "; Boström et al., 2006c; p1]", style.createCitationMarker(citationMarkerEntries, true, - NonUniqueCitationMarker.THROWS).asString()); + NonUniqueCitationMarker.THROWS).toString()); } // With pageInfo: same entries with identical non-null pageInfo: collapsed. @@ -878,7 +878,7 @@ void testGetCitationMarkerJoinFirst() throws IOException { assertEquals("[Boström et al., 2006a; p1]", style.createCitationMarker(citationMarkerEntries, true, - NonUniqueCitationMarker.THROWS).asString()); + NonUniqueCitationMarker.THROWS).toString()); } // With pageInfo: same entries with different pageInfo: kept separate. // Empty ("") and missing pageInfos considered equal, thus collapsed. @@ -902,7 +902,7 @@ void testGetCitationMarkerJoinFirst() throws IOException { + "; Boström et al., 2006a]", style.createCitationMarker(citationMarkerEntries, true, - NonUniqueCitationMarker.THROWS).asString()); + NonUniqueCitationMarker.THROWS).toString()); } } } diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java index 9fbe9579ccb..ae5e83abd2f 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java @@ -98,14 +98,14 @@ static String runGetNumCitationMarker2a(OOBibStyle style, List num, int minGroupingCount, boolean inList) { if (inList) { if (num.size() != 1) { - throw new RuntimeException("Numeric label for the bibliography with " - + String.valueOf(num.size()) + " numbers?"); + throw new IllegalArgumentException("Numeric label for the bibliography with " + + String.valueOf(num.size()) + " numbers?"); } int n = num.get(0); CitationMarkerNumericBibEntryImpl x = new CitationMarkerNumericBibEntryImpl("key", (n == 0) ? Optional.empty() : Optional.of(n)); - return style.getNumCitationMarkerForBibliography(x).asString(); + return style.getNumCitationMarkerForBibliography(x).toString(); } else { List input = num.stream() @@ -114,7 +114,7 @@ static String runGetNumCitationMarker2a(OOBibStyle style, n, Optional.empty())) .collect(Collectors.toList()); - return style.getNumCitationMarker2(input, minGroupingCount).asString(); + return style.getNumCitationMarker2(input, minGroupingCount).toString(); } } @@ -131,7 +131,7 @@ static String runGetNumCitationMarker2b(OOBibStyle style, CitationMarkerNumericEntry... s) { List input = Stream.of(s).collect(Collectors.toList()); OOText res = style.getNumCitationMarker2(input, minGroupingCount); - return res.asString(); + return res.toString(); } /* @@ -146,8 +146,8 @@ static CitationMarkerEntry makeCitationMarkerEntry(BibEntry entry, String uniqueLetterQ, String pageInfoQ, boolean isFirstAppearanceOfSource) { - if (!entry.getCitationKey().isPresent()) { - throw new RuntimeException("!entry.getCitationKey().isPresent()"); + if (entry.getCitationKey().isEmpty()) { + throw new IllegalArgumentException("entry.getCitationKey() is empty"); } String citationKey = entry.getCitationKey().get(); Citation result = new Citation(citationKey); @@ -194,7 +194,7 @@ static String getCitationMarker2(OOBibStyle style, } return style.createCitationMarker(citationMarkerEntries, inParenthesis, - NonUniqueCitationMarker.THROWS).asString(); + NonUniqueCitationMarker.THROWS).toString(); } /* From 41f1311103c44d33a54099d87cb59abae063992a Mon Sep 17 00:00:00 2001 From: Antal K Date: Sat, 19 Jun 2021 15:23:49 +0200 Subject: [PATCH 033/103] not using RangeSet --- .../logic/openoffice/frontend/OOFrontend.java | 81 ++++++------------- .../model/openoffice/rangesort/RangeSet.java | 53 ------------ 2 files changed, 23 insertions(+), 111 deletions(-) delete mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java index 6a4f741b793..967a8cf084d 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java @@ -17,7 +17,6 @@ import org.jabref.model.openoffice.rangesort.RangeOverlap; import org.jabref.model.openoffice.rangesort.RangeOverlapBetween; import org.jabref.model.openoffice.rangesort.RangeOverlapWithin; -import org.jabref.model.openoffice.rangesort.RangeSet; import org.jabref.model.openoffice.rangesort.RangeSort; import org.jabref.model.openoffice.rangesort.RangeSortEntry; import org.jabref.model.openoffice.rangesort.RangeSortVisual; @@ -400,69 +399,35 @@ public List> viewCursorRanges(XTextDocumen NoDocumentException, WrappedTargetException { - if (false) { - // Avoid inserting the same mark twice. - RangeSet seen = new RangeSet(); + // We partition by XText and use a single range from + // each partition to get at the corresponding footnotemark range. - List> result = new ArrayList<>(); - - for (RangeForOverlapCheck citationRange : citationRanges) { - - Optional footnoteMarkRange = UnoTextRange.getFootnoteMarkRange(citationRange.range); - - if (footnoteMarkRange.isEmpty()) { - // not in footnote - continue; - } - - boolean seenContains = seen.contains(footnoteMarkRange.get()); - if (!seenContains) { - seen.add(footnoteMarkRange.get()); - result.add(new RangeForOverlapCheck<>(footnoteMarkRange.get(), - citationRange.idWithinKind, - RangeForOverlapCheck.FOOTNOTE_MARK_KIND, - "FootnoteMark for " + citationRange.format())); - } + List> result = new ArrayList<>(); + RangeSort.RangePartitions> partitions = + RangeSort.partitionRanges(citationRanges); + + // Each partition corresponds to an XText, and each footnote has a single XText. + // (This latter ignores the possibility of XTextContents inserted into footnotes.) + // Also: different footnotes cannot share a footnotemark range, we are not creating duplicates. + for (List> partition : partitions.getPartitions()) { + if (partition.isEmpty()) { + continue; } - return result; - } else { - - // RangeSet.add involves a few comparisons anf getText, which is probably costly. - // - // (On the other hand we only insert ranges of footnotes, which probably limits the sizes - // of its partitions) - // - // We can avoid using RangeSet by partitioning only and using a single range from - // each partition to get at the corresponding footnotemark range. - - List> result = new ArrayList<>(); - RangeSort.RangePartitions> partitions = - RangeSort.partitionRanges(citationRanges); - - // Now it is sufficient to check a single entry from each partition. - // Each partition corresponds to an XText, and each footnote has a single XText. - // (This latter ignores the possibility of XTextContents inserted into footnotes.) - // Also: different footnotes cannot share a footnotemark range, we are not creating duplicates. - for (List> partition : partitions.getPartitions()) { - if (partition.isEmpty()) { - continue; - } - RangeForOverlapCheck citationRange = partition.get(0); - - Optional footnoteMarkRange = UnoTextRange.getFootnoteMarkRange(citationRange.range); + RangeForOverlapCheck citationRange = partition.get(0); - if (footnoteMarkRange.isEmpty()) { - // not in footnote - continue; - } + Optional footnoteMarkRange = UnoTextRange.getFootnoteMarkRange(citationRange.range); - result.add(new RangeForOverlapCheck<>(footnoteMarkRange.get(), - citationRange.idWithinKind, - RangeForOverlapCheck.FOOTNOTE_MARK_KIND, - "FootnoteMark for " + citationRange.format())); + if (footnoteMarkRange.isEmpty()) { + // not in footnote + continue; } - return result; + + result.add(new RangeForOverlapCheck<>(footnoteMarkRange.get(), + citationRange.idWithinKind, + RangeForOverlapCheck.FOOTNOTE_MARK_KIND, + "FootnoteMark for " + citationRange.format())); } + return result; } static String rangeOverlapsToMessage(List>> overlaps) { diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java deleted file mode 100644 index e389c902b90..00000000000 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.jabref.model.openoffice.rangesort; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.TreeSet; - -import org.jabref.model.openoffice.uno.UnoTextRange; - -import com.sun.star.text.XText; -import com.sun.star.text.XTextRange; - -public class RangeSet { - - private final Map> partitions; - - public RangeSet() { - this.partitions = new HashMap<>(); - } - - public boolean contains(XTextRange range) { - Objects.requireNonNull(range); - XText partitionKey = range.getText(); - if (!this.partitions.containsKey(partitionKey)) { - return false; - } - return partitions.get(partitionKey).contains(range); - } - - /* - * return false if already contained - * - * Beware: using UnoTextRange::compareStartsThenEnds as comparator involves range.getText() - * twice on each comparison. This makes it costly to use this class. - */ - public boolean add(XTextRange range) { - TreeSet partition = partitions.get(range.getText()); - if (partition == null) { - partition = new TreeSet<>(UnoTextRange::compareStartsThenEnds); - partitions.put(range.getText(), partition); - } - return partition.add(range); - } - - /** - * @return A list of the partitions. - */ - public List> partitionValues() { - return new ArrayList<>(partitions.values()); - } -} From 0f398bd84746956d1f684a3a165e629e60cfcda6 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sat, 19 Jun 2021 15:25:17 +0200 Subject: [PATCH 034/103] not using RangeSet --- .../logic/openoffice/frontend/OOFrontend.java | 81 ++++++------------- .../model/openoffice/rangesort/RangeSet.java | 53 ------------ 2 files changed, 23 insertions(+), 111 deletions(-) delete mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java index 6a4f741b793..967a8cf084d 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java @@ -17,7 +17,6 @@ import org.jabref.model.openoffice.rangesort.RangeOverlap; import org.jabref.model.openoffice.rangesort.RangeOverlapBetween; import org.jabref.model.openoffice.rangesort.RangeOverlapWithin; -import org.jabref.model.openoffice.rangesort.RangeSet; import org.jabref.model.openoffice.rangesort.RangeSort; import org.jabref.model.openoffice.rangesort.RangeSortEntry; import org.jabref.model.openoffice.rangesort.RangeSortVisual; @@ -400,69 +399,35 @@ public List> viewCursorRanges(XTextDocumen NoDocumentException, WrappedTargetException { - if (false) { - // Avoid inserting the same mark twice. - RangeSet seen = new RangeSet(); + // We partition by XText and use a single range from + // each partition to get at the corresponding footnotemark range. - List> result = new ArrayList<>(); - - for (RangeForOverlapCheck citationRange : citationRanges) { - - Optional footnoteMarkRange = UnoTextRange.getFootnoteMarkRange(citationRange.range); - - if (footnoteMarkRange.isEmpty()) { - // not in footnote - continue; - } - - boolean seenContains = seen.contains(footnoteMarkRange.get()); - if (!seenContains) { - seen.add(footnoteMarkRange.get()); - result.add(new RangeForOverlapCheck<>(footnoteMarkRange.get(), - citationRange.idWithinKind, - RangeForOverlapCheck.FOOTNOTE_MARK_KIND, - "FootnoteMark for " + citationRange.format())); - } + List> result = new ArrayList<>(); + RangeSort.RangePartitions> partitions = + RangeSort.partitionRanges(citationRanges); + + // Each partition corresponds to an XText, and each footnote has a single XText. + // (This latter ignores the possibility of XTextContents inserted into footnotes.) + // Also: different footnotes cannot share a footnotemark range, we are not creating duplicates. + for (List> partition : partitions.getPartitions()) { + if (partition.isEmpty()) { + continue; } - return result; - } else { - - // RangeSet.add involves a few comparisons anf getText, which is probably costly. - // - // (On the other hand we only insert ranges of footnotes, which probably limits the sizes - // of its partitions) - // - // We can avoid using RangeSet by partitioning only and using a single range from - // each partition to get at the corresponding footnotemark range. - - List> result = new ArrayList<>(); - RangeSort.RangePartitions> partitions = - RangeSort.partitionRanges(citationRanges); - - // Now it is sufficient to check a single entry from each partition. - // Each partition corresponds to an XText, and each footnote has a single XText. - // (This latter ignores the possibility of XTextContents inserted into footnotes.) - // Also: different footnotes cannot share a footnotemark range, we are not creating duplicates. - for (List> partition : partitions.getPartitions()) { - if (partition.isEmpty()) { - continue; - } - RangeForOverlapCheck citationRange = partition.get(0); - - Optional footnoteMarkRange = UnoTextRange.getFootnoteMarkRange(citationRange.range); + RangeForOverlapCheck citationRange = partition.get(0); - if (footnoteMarkRange.isEmpty()) { - // not in footnote - continue; - } + Optional footnoteMarkRange = UnoTextRange.getFootnoteMarkRange(citationRange.range); - result.add(new RangeForOverlapCheck<>(footnoteMarkRange.get(), - citationRange.idWithinKind, - RangeForOverlapCheck.FOOTNOTE_MARK_KIND, - "FootnoteMark for " + citationRange.format())); + if (footnoteMarkRange.isEmpty()) { + // not in footnote + continue; } - return result; + + result.add(new RangeForOverlapCheck<>(footnoteMarkRange.get(), + citationRange.idWithinKind, + RangeForOverlapCheck.FOOTNOTE_MARK_KIND, + "FootnoteMark for " + citationRange.format())); } + return result; } static String rangeOverlapsToMessage(List>> overlaps) { diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java deleted file mode 100644 index e389c902b90..00000000000 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.jabref.model.openoffice.rangesort; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.TreeSet; - -import org.jabref.model.openoffice.uno.UnoTextRange; - -import com.sun.star.text.XText; -import com.sun.star.text.XTextRange; - -public class RangeSet { - - private final Map> partitions; - - public RangeSet() { - this.partitions = new HashMap<>(); - } - - public boolean contains(XTextRange range) { - Objects.requireNonNull(range); - XText partitionKey = range.getText(); - if (!this.partitions.containsKey(partitionKey)) { - return false; - } - return partitions.get(partitionKey).contains(range); - } - - /* - * return false if already contained - * - * Beware: using UnoTextRange::compareStartsThenEnds as comparator involves range.getText() - * twice on each comparison. This makes it costly to use this class. - */ - public boolean add(XTextRange range) { - TreeSet partition = partitions.get(range.getText()); - if (partition == null) { - partition = new TreeSet<>(UnoTextRange::compareStartsThenEnds); - partitions.put(range.getText(), partition); - } - return partition.add(range); - } - - /** - * @return A list of the partitions. - */ - public List> partitionValues() { - return new ArrayList<>(partitions.values()); - } -} From 7e6667db5c601faa5752d8ab5588c82d29a48b7d Mon Sep 17 00:00:00 2001 From: Antal K Date: Sat, 19 Jun 2021 15:25:54 +0200 Subject: [PATCH 035/103] not using RangeSet --- .../logic/openoffice/frontend/OOFrontend.java | 223 ++++++++---------- .../model/openoffice/rangesort/RangeSet.java | 48 ---- 2 files changed, 97 insertions(+), 174 deletions(-) delete mode 100644 src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java index fd0523a4bf8..967a8cf084d 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java @@ -17,7 +17,6 @@ import org.jabref.model.openoffice.rangesort.RangeOverlap; import org.jabref.model.openoffice.rangesort.RangeOverlapBetween; import org.jabref.model.openoffice.rangesort.RangeOverlapWithin; -import org.jabref.model.openoffice.rangesort.RangeSet; import org.jabref.model.openoffice.rangesort.RangeSort; import org.jabref.model.openoffice.rangesort.RangeSortEntry; import org.jabref.model.openoffice.rangesort.RangeSortVisual; @@ -57,9 +56,7 @@ public OOFrontend(XTextDocument doc) NoDocumentException, WrappedTargetException { - // TODO: dataModel should come from looking at the - // document and preferences. - // + // TODO: dataModel should come from looking at the document and preferences. this.backend = new Backend52(); // Get the citationGroupNames @@ -98,24 +95,19 @@ public Optional healthReport(XTextDocument doc) } /** - * Creates a list of {@code RangeSortable} values for - * our {@code CitationGroup} values. Originally designed to be - * passed to {@code visualSort}. + * Creates a list of {@code RangeSortable} values for our {@code CitationGroup} + * values. Originally designed to be passed to {@code visualSort}. * - * The elements of the returned list are actually of type - * {@code RangeSortEntry}. + * The elements of the returned list are actually of type {@code RangeSortEntry}. * - * The result is sorted within {@code XTextRange.getText()} - * partitions of the citation groups according to their {@code XTextRange} - * (before mapping to footnote marks). + * The result is sorted within {@code XTextRange.getText()} partitions of the citation groups + * according to their {@code XTextRange} (before mapping to footnote marks). * - * In the result, RangeSortable.getIndexInPosition() contains - * unique indexes within the original partition (not after - * mapFootnotesToFootnoteMarks). + * In the result, RangeSortable.getIndexInPosition() contains unique indexes within the original + * partition (not after mapFootnotesToFootnoteMarks). * - * @param mapFootnotesToFootnoteMarks If true, replace ranges in - * footnotes with the range of the corresponding footnote - * mark. This is used for numbering the citations. + * @param mapFootnotesToFootnoteMarks If true, replace ranges in footnotes with the range of the + * corresponding footnote mark. This is used for numbering the citations. * */ private List> @@ -128,27 +120,24 @@ public Optional healthReport(XTextDocument doc) for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { XTextRange range = (this .getMarkRange(doc, cg) - .orElseThrow(RuntimeException::new)); + .orElseThrow(IllegalStateException::new)); sortables.add(new RangeSortEntry<>(range, 0, cg)); } /* * At this point we are almost ready to return sortables. * - * But we may want to number citations in a footnote - * as if it appeared where the footnote mark is. + * But we may want to number citations in a footnote as if it appeared where the footnote + * mark is. * - * The following code replaces ranges within footnotes with - * the range for the corresponding footnote mark. + * The following code replaces ranges within footnotes with the range for the corresponding + * footnote mark. * - * This brings further ambiguity if we have multiple - * citation groups within the same footnote: for the comparison - * they become indistinguishable. Numbering between them is - * not controlled. Also combineCiteMarkers will see them in - * the wrong order (if we use this comparison), and will not - * be able to merge. To avoid these, we sort textually within - * each .getText() partition and add indexInPosition - * accordingly. + * This brings further ambiguity if we have multiple citation groups within the same + * footnote: for the comparison they become indistinguishable. Numbering between them is + * not controlled. Also combineCiteMarkers will see them in the wrong order (if we use this + * comparison), and will not be able to merge. To avoid these, we sort textually within + * each .getText() partition and add indexInPosition accordingly. * */ @@ -174,53 +163,45 @@ public Optional healthReport(XTextDocument doc) } } result.add(sortable); - } + } } return result.stream().map(e -> e).collect(Collectors.toList()); } /** - * @param mapFootnotesToFootnoteMarks If true, sort reference - * marks in footnotes as if they appeared at the - * corresponding footnote mark. + * @param mapFootnotesToFootnoteMarks If true, sort reference marks in footnotes as if they + * appeared at the corresponding footnote mark. * * @return citation groups sorted by their visual positions. * - * Limitation: for two column layout visual (top-down, - * left-right) order does not match the expected (textual) - * order. + * Limitation: for two column layout visual (top-down, left-right) order does not match the + * expected (textual) order. * */ - private List - getVisuallySortedCitationGroups(XTextDocument doc, - boolean mapFootnotesToFootnoteMarks, - FunctionalTextViewCursor fcursor) + private List getVisuallySortedCitationGroups(XTextDocument doc, + boolean mapFootnotesToFootnoteMarks, + FunctionalTextViewCursor fcursor) throws WrappedTargetException, NoDocumentException, JabRefException { - List> sortables = - createVisualSortInput(doc, mapFootnotesToFootnoteMarks); + List> sortables = createVisualSortInput(doc, mapFootnotesToFootnoteMarks); - List> sorted = - RangeSortVisual.visualSort(sortables, - doc, - fcursor); + List> sorted = RangeSortVisual.visualSort(sortables, doc, fcursor); - List result = - (sorted.stream().map(e -> e.getContent()).collect(Collectors.toList())); + List result = (sorted.stream() + .map(RangeSortable::getContent) + .collect(Collectors.toList())); return result; } /** - * Return citation groups in visual order within (but not across) - * XText partitions. + * Return citation groups in visual order within (but not across) XText partitions. * - * This is (1) sufficient for combineCiteMarkers which looks for - * consecutive XTextRanges within each XText, (2) not confused by - * multicolumn layout or multipage display. + * This is (1) sufficient for combineCiteMarkers which looks for consecutive XTextRanges within + * each XText, (2) not confused by multicolumn layout or multipage display. */ public List getCitationGroupsSortedWithinPartitions(XTextDocument doc, boolean mapFootnotesToFootnoteMarks) @@ -236,19 +217,17 @@ public Optional healthReport(XTextDocument doc) } /** - * Create a citation group for the given citation keys, at the - * end of position. + * Create a citation group for the given citation keys, at the end of position. * - * On return {@code position} is collapsed, and is after the - * inserted space, or at the end of the reference mark. + * On return {@code position} is collapsed, and is after the inserted space, or at the end of + * the reference mark. * * @param citationKeys In storage order * @param pageInfos In storage order * @param citationType * @param position Collapsed to its end. - * @param insertSpaceAfter If true, we insert a space after the mark, that - * carries on format of characters from - * the original position. + * @param insertSpaceAfter If true, we insert a space after the mark, that carries on format of + * characters from the original position. */ public CitationGroup createCitationGroup(XTextDocument doc, List citationKeys, @@ -267,7 +246,7 @@ public CitationGroup createCitationGroup(XTextDocument doc, Objects.requireNonNull(pageInfos); if (pageInfos.size() != citationKeys.size()) { - throw new RuntimeException("pageInfos.size != citationKeys.size"); + throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); } CitationGroup cg = backend.createCitationGroup(doc, citationKeys, @@ -357,8 +336,8 @@ public List> citationRanges(XTextDocument new ArrayList<>(citationGroups.numberOfCitationGroups()); for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { - XTextRange range = this.getMarkRange(doc, cg).orElseThrow(RuntimeException::new); - String description = cg.cgid.citationGroupIdAsString(); // cg.cgRangeStorage.nrGetRangeName(); + XTextRange range = this.getMarkRange(doc, cg).orElseThrow(IllegalStateException::new); + String description = cg.cgid.citationGroupIdAsString(); result.add(new RangeForOverlapCheck<>(range, cg.cgid, RangeForOverlapCheck.REFERENCE_MARK_KIND, @@ -404,56 +383,54 @@ public List> viewCursorRanges(XTextDocumen } /** - * @return A range for each footnote mark where the footnote - * contains at least one citation group. + * @return A range for each footnote mark where the footnote contains at least one citation group. * - * Purpose: We do not want markers of footnotes containing - * reference marks to overlap with reference - * marks. Overwriting these footnote marks might kill our - * reference marks in the footnote. + * Purpose: We do not want markers of footnotes containing reference marks to overlap with + * reference marks. Overwriting these footnote marks might kill our reference marks in the + * footnote. * - * Note: Here we directly communicate to the document, not - * through the backend. This is because mapping ranges to - * footnote marks does not depend on how do we mark or - * structure those ranges. + * Note: Here we directly communicate to the document, not through the backend. This is because + * mapping ranges to footnote marks does not depend on how do we mark or structure those + * ranges. */ public List> - footnoteMarkRanges(XTextDocument doc, - List> citationRanges) + footnoteMarkRanges(XTextDocument doc, List> citationRanges) throws NoDocumentException, WrappedTargetException { - // Avoid inserting the same mark twice. - // Could use RangeSet if we had that. - RangeSet seen = new RangeSet(); + // We partition by XText and use a single range from + // each partition to get at the corresponding footnotemark range. List> result = new ArrayList<>(); + RangeSort.RangePartitions> partitions = + RangeSort.partitionRanges(citationRanges); + + // Each partition corresponds to an XText, and each footnote has a single XText. + // (This latter ignores the possibility of XTextContents inserted into footnotes.) + // Also: different footnotes cannot share a footnotemark range, we are not creating duplicates. + for (List> partition : partitions.getPartitions()) { + if (partition.isEmpty()) { + continue; + } + RangeForOverlapCheck citationRange = partition.get(0); - for (RangeForOverlapCheck citationRange : citationRanges) { - - Optional footnoteMarkRange = - UnoTextRange.getFootnoteMarkRange(citationRange.range); + Optional footnoteMarkRange = UnoTextRange.getFootnoteMarkRange(citationRange.range); if (footnoteMarkRange.isEmpty()) { // not in footnote continue; } - boolean seenContains = seen.contains(footnoteMarkRange.get()); - if (!seenContains) { - seen.add(footnoteMarkRange.get()); - result.add(new RangeForOverlapCheck<>(footnoteMarkRange.get(), - citationRange.idWithinKind, - RangeForOverlapCheck.FOOTNOTE_MARK_KIND, - "FootnoteMark for " + citationRange.format())); - } + result.add(new RangeForOverlapCheck<>(footnoteMarkRange.get(), + citationRange.idWithinKind, + RangeForOverlapCheck.FOOTNOTE_MARK_KIND, + "FootnoteMark for " + citationRange.format())); } return result; } - static String - rangeOverlapsToMessage(List>> overlaps) { + static String rangeOverlapsToMessage(List>> overlaps) { if (overlaps.size() == 0) { return "(*no overlaps*)"; @@ -481,6 +458,7 @@ public List> viewCursorRanges(XTextDocumen * Check for any overlap between userRanges and protected ranges. * * Assume userRanges is small (usually 1 elements for checking the cursor) + * * Returns on first problem found. */ public OOVoidResult @@ -500,11 +478,10 @@ public List> viewCursorRanges(XTextDocumen ranges.addAll(footnoteMarkRanges(doc, citationRanges)); List>> overlaps = - RangeOverlapBetween.findFirst( - doc, - userRanges, - ranges, - requireSeparation); + RangeOverlapBetween.findFirst(doc, + userRanges, + ranges, + requireSeparation); if (overlaps.size() == 0) { return OOVoidResult.ok(); @@ -518,11 +495,10 @@ public List> viewCursorRanges(XTextDocumen * @param reportAtMost Limit number of overlaps reported (0 for no limit) * */ - public OOVoidResult - checkRangeOverlaps(XTextDocument doc, - List> userRanges, - boolean requireSeparation, - int reportAtMost) + public OOVoidResult checkRangeOverlaps(XTextDocument doc, + List> userRanges, + boolean requireSeparation, + int reportAtMost) throws NoDocumentException, WrappedTargetException { @@ -550,33 +526,29 @@ public List> viewCursorRanges(XTextDocumen * * Called from: ManageCitationsDialogViewModel constructor. * - * @return A list with entries corresponding to citations in the - * text, in arbitrary order (same order as from - * getJabRefReferenceMarkNames). + * @return A list with entries corresponding to citations in the text, in arbitrary order (same + * order as from getJabRefReferenceMarkNames). * - * Note: visual or alphabetic order could be more - * manageable for the user. We could provide these - * here, but switching between them needs change on - * GUI (adding a toggle or selector). + * Note: visual or alphabetic order could be more manageable for the user. We + * could provide these here, but switching between them needs change on GUI + * (adding a toggle or selector). * - * Note: CitationEntry implements Comparable, where - * compareTo() and equals() are based on refMarkName. - * The order used in the "Manage citations" dialog + * Note: CitationEntry implements Comparable, where compareTo() and equals() are + * based on refMarkName. The order used in the "Manage citations" dialog * does not seem to use that. * - * The 1st is labeled "Citation" (show citation in bold, - * and some context around it). + * The 1st is labeled "Citation" (show citation in bold, and some context + * around it). * - * The columns can be sorted by clicking on the column title. - * For the "Citation" column, the sorting is based on the content, - * (the context before the citation), not on the citation itself. + * The columns can be sorted by clicking on the column title. For the + * "Citation" column, the sorting is based on the content, (the context + * before the citation), not on the citation itself. * - * In the "Extra information ..." column some visual indication - * of the editable part could be helpful. + * In the "Extra information ..." column some visual indication of the + * editable part could be helpful. * - * Wish: selecting an entry (or a button in the line) in - * the GUI could move the cursor in the document to - * the entry. + * Wish: selecting an entry (or a button in the line) in the GUI could move the cursor + * in the document to the entry. */ public List getCitationEntries(XTextDocument doc) throws @@ -608,8 +580,7 @@ public void imposeGlobalOrder(XTextDocument doc, FunctionalTextViewCursor fcurso boolean mapFootnotesToFootnoteMarks = true; List sortedCitationGroups = getVisuallySortedCitationGroups(doc, mapFootnotesToFootnoteMarks, fcursor); - List sortedCitationGroupIds = - OOListUtil.map(sortedCitationGroups, cg -> cg.cgid); + List sortedCitationGroupIds = OOListUtil.map(sortedCitationGroups, cg -> cg.cgid); citationGroups.setGlobalOrder(sortedCitationGroupIds); } } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java deleted file mode 100644 index f7fbe37ba25..00000000000 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSet.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.jabref.model.openoffice.rangesort; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.TreeSet; - -import org.jabref.model.openoffice.uno.UnoTextRange; - -import com.sun.star.text.XText; -import com.sun.star.text.XTextRange; - -public class RangeSet { - - private final Map> partitions; - - public RangeSet() { - this.partitions = new HashMap<>(); - } - - public boolean contains(XTextRange range) { - Objects.requireNonNull(range); - XText partitionKey = range.getText(); - if (!this.partitions.containsKey(partitionKey)) { - return false; - } - return partitions.get(partitionKey).contains(range); - } - - /* return false if already contained */ - public boolean add(XTextRange range) { - TreeSet partition = partitions.get(range.getText()); - if (partition == null) { - partition = new TreeSet<>(UnoTextRange::compareStartsThenEnds); - partitions.put(range.getText(), partition); - } - return partition.add(range); - } - - /** - * @return A list of the partitions. - */ - public List> partitionValues() { - return new ArrayList<>(partitions.values()); - } -} From 00fa0ad790a6fa91f6f298a705b2f4a2d14a1914 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sat, 19 Jun 2021 15:35:50 +0200 Subject: [PATCH 036/103] merged --- .../openoffice/BibEntryNotFoundException.java | 16 - .../openoffice/ConnectionLostException.java | 11 - .../org/jabref/gui/openoffice/OOBibBase.java | 1424 ----------------- .../UndefinedCharacterFormatException.java | 19 - .../org/jabref/logic/openoffice/OOUtil.java | 285 ---- .../openoffice/UndefinedBibtexEntry.java | 22 - .../UndefinedParagraphFormatException.java | 18 - .../logic/openoffice/style/OOBibStyle.java | 384 ----- src/main/resources/l10n/JabRef_en.properties | 1 - .../openoffice/style/OOBibStyleTest.java | 117 +- .../style/OOBibStyleTestHelper.java | 51 +- 11 files changed, 101 insertions(+), 2247 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/openoffice/BibEntryNotFoundException.java delete mode 100644 src/main/java/org/jabref/gui/openoffice/ConnectionLostException.java delete mode 100644 src/main/java/org/jabref/gui/openoffice/OOBibBase.java delete mode 100644 src/main/java/org/jabref/gui/openoffice/UndefinedCharacterFormatException.java delete mode 100644 src/main/java/org/jabref/logic/openoffice/OOUtil.java delete mode 100644 src/main/java/org/jabref/logic/openoffice/UndefinedBibtexEntry.java delete mode 100644 src/main/java/org/jabref/logic/openoffice/UndefinedParagraphFormatException.java diff --git a/src/main/java/org/jabref/gui/openoffice/BibEntryNotFoundException.java b/src/main/java/org/jabref/gui/openoffice/BibEntryNotFoundException.java deleted file mode 100644 index b3db5f8f9e7..00000000000 --- a/src/main/java/org/jabref/gui/openoffice/BibEntryNotFoundException.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.jabref.gui.openoffice; - -class BibEntryNotFoundException extends Exception { - - private final String citationKey; - - public BibEntryNotFoundException(String citationKey, String message) { - super(message); - - this.citationKey = citationKey; - } - - public String getCitationKey() { - return citationKey; - } -} diff --git a/src/main/java/org/jabref/gui/openoffice/ConnectionLostException.java b/src/main/java/org/jabref/gui/openoffice/ConnectionLostException.java deleted file mode 100644 index 36fc16e5e3f..00000000000 --- a/src/main/java/org/jabref/gui/openoffice/ConnectionLostException.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.jabref.gui.openoffice; - -/** - * This exception is used to indicate that connection to OpenOffice has been lost. - */ -class ConnectionLostException extends RuntimeException { - - public ConnectionLostException(String s) { - super(s); - } -} diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase.java deleted file mode 100644 index 540c5f9216b..00000000000 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase.java +++ /dev/null @@ -1,1424 +0,0 @@ -package org.jabref.gui.openoffice; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import org.jabref.architecture.AllowedToUseAwt; -import org.jabref.gui.DialogService; -import org.jabref.logic.bibtex.comparator.FieldComparator; -import org.jabref.logic.bibtex.comparator.FieldComparatorStack; -import org.jabref.logic.l10n.Localization; -import org.jabref.logic.layout.Layout; -import org.jabref.logic.openoffice.OOUtil; -import org.jabref.logic.openoffice.UndefinedBibtexEntry; -import org.jabref.logic.openoffice.UndefinedParagraphFormatException; -import org.jabref.logic.openoffice.style.OOBibStyle; -import org.jabref.logic.openoffice.style.OOPreFormatter; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.StandardField; -import org.jabref.model.openoffice.uno.CreationException; -import org.jabref.model.openoffice.uno.NoDocumentException; - -import com.sun.star.awt.Point; -import com.sun.star.beans.IllegalTypeException; -import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; -import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.beans.XPropertyContainer; -import com.sun.star.beans.XPropertySet; -import com.sun.star.comp.helper.BootstrapException; -import com.sun.star.container.NoSuchElementException; -import com.sun.star.container.XEnumeration; -import com.sun.star.container.XEnumerationAccess; -import com.sun.star.container.XNameAccess; -import com.sun.star.container.XNamed; -import com.sun.star.document.XDocumentPropertiesSupplier; -import com.sun.star.frame.XComponentLoader; -import com.sun.star.frame.XController; -import com.sun.star.frame.XDesktop; -import com.sun.star.frame.XModel; -import com.sun.star.lang.DisposedException; -import com.sun.star.lang.IllegalArgumentException; -import com.sun.star.lang.Locale; -import com.sun.star.lang.WrappedTargetException; -import com.sun.star.lang.XComponent; -import com.sun.star.lang.XMultiComponentFactory; -import com.sun.star.lang.XMultiServiceFactory; -import com.sun.star.text.XBookmarksSupplier; -import com.sun.star.text.XDocumentIndexesSupplier; -import com.sun.star.text.XFootnote; -import com.sun.star.text.XReferenceMarksSupplier; -import com.sun.star.text.XText; -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.text.XTextRangeCompare; -import com.sun.star.text.XTextSection; -import com.sun.star.text.XTextSectionsSupplier; -import com.sun.star.text.XTextViewCursor; -import com.sun.star.text.XTextViewCursorSupplier; -import com.sun.star.uno.Any; -import com.sun.star.uno.Type; -import com.sun.star.uno.UnoRuntime; -import com.sun.star.uno.XComponentContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class for manipulating the Bibliography of the currently start document in OpenOffice. - */ -@AllowedToUseAwt("Requires AWT for italics and bold") -class OOBibBase { - - private static final OOPreFormatter POSTFORMATTER = new OOPreFormatter(); - - private static final String BIB_SECTION_NAME = "JR_bib"; - private static final String BIB_SECTION_END_NAME = "JR_bib_end"; - private static final String BIB_CITATION = "JR_cite"; - private static final Pattern CITE_PATTERN = Pattern.compile(OOBibBase.BIB_CITATION + "\\d*_(\\d*)_(.*)"); - - private static final String CHAR_STYLE_NAME = "CharStyleName"; - - private static final int AUTHORYEAR_PAR = 1; - private static final int AUTHORYEAR_INTEXT = 2; - private static final int INVISIBLE_CIT = 3; - - private static final Logger LOGGER = LoggerFactory.getLogger(OOBibBase.class); - private XMultiServiceFactory mxDocFactory; - private XTextDocument mxDoc; - private XText text; - private final XDesktop xDesktop; - private XTextViewCursorSupplier xViewCursorSupplier; - private XComponent xCurrentComponent; - private XPropertySet propertySet; - - private XPropertyContainer userProperties; - private final boolean atEnd; - private final Comparator entryComparator; - private final Comparator yearAuthorTitleComparator; - private final FieldComparator authComp = new FieldComparator(StandardField.AUTHOR); - private final FieldComparator yearComp = new FieldComparator(StandardField.YEAR); - - private final FieldComparator titleComp = new FieldComparator(StandardField.TITLE); - private final List> authorYearTitleList = new ArrayList<>(3); - - private final List> yearAuthorTitleList = new ArrayList<>(3); - private final Map uniquefiers = new HashMap<>(); - private List sortedReferenceMarks; - - private final DialogService dialogService; - - public OOBibBase(Path loPath, boolean atEnd, DialogService dialogService) throws IllegalAccessException, InvocationTargetException, BootstrapException, CreationException, IOException, ClassNotFoundException { - - this.dialogService = dialogService; - - authorYearTitleList.add(authComp); - authorYearTitleList.add(yearComp); - authorYearTitleList.add(titleComp); - - yearAuthorTitleList.add(yearComp); - yearAuthorTitleList.add(authComp); - yearAuthorTitleList.add(titleComp); - - entryComparator = new FieldComparatorStack<>(authorYearTitleList); - yearAuthorTitleComparator = new FieldComparatorStack<>(yearAuthorTitleList); - - this.atEnd = atEnd; - - xDesktop = simpleBootstrap(loPath); - } - - public boolean isConnectedToDocument() { - return xCurrentComponent != null; - } - - public XTextDocument selectComponent(List list) { - List viewModel = list.stream().map(DocumentTitleViewModel::new).collect(Collectors.toList()); - // this whole method is part of a background task when auto-detecting instances, so we need to show dialog in FX thread - Optional selectedDocument = dialogService.showChoiceDialogAndWait(Localization.lang("Select document"), Localization.lang("Found documents:"), Localization.lang("Use selected document"), viewModel); - return selectedDocument.map(DocumentTitleViewModel::getXtextDocument).orElse(null); - } - - public Optional getCurrentDocumentTitle() { - return getDocumentTitle(mxDoc); - } - - private Optional getDocumentTitle(XTextDocument doc) { - if (doc == null) { - return Optional.empty(); - } else { - try { - return Optional.of(String.valueOf(OOUtil.getProperty(doc.getCurrentController().getFrame(), "Title"))); - } catch (UnknownPropertyException | WrappedTargetException e) { - LOGGER.warn("Could not get document title", e); - return Optional.empty(); - } - } - } - - public void selectDocument() throws NoDocumentException, NoSuchElementException, WrappedTargetException { - List textDocumentList = getTextDocuments(); - XTextDocument selected; - if (textDocumentList.isEmpty()) { - // No text documents found. - throw new NoDocumentException("No Writer documents found"); - } else if (textDocumentList.size() == 1) { - // Get the only one - selected = textDocumentList.get(0); - } else { - // Bring up a dialog - selected = selectComponent(textDocumentList); - } - - if (selected == null) { - return; - } - xCurrentComponent = UnoRuntime.queryInterface(XComponent.class, selected); - mxDoc = selected; - - UnoRuntime.queryInterface(XDocumentIndexesSupplier.class, xCurrentComponent); - - XModel xModel = UnoRuntime.queryInterface(XModel.class, xCurrentComponent); - XController xController = xModel.getCurrentController(); - xViewCursorSupplier = UnoRuntime.queryInterface(XTextViewCursorSupplier.class, xController); - - // get a reference to the body text of the document - text = mxDoc.getText(); - - // Access the text document's multi service factory: - mxDocFactory = UnoRuntime.queryInterface(XMultiServiceFactory.class, mxDoc); - - XDocumentPropertiesSupplier supp = UnoRuntime.queryInterface(XDocumentPropertiesSupplier.class, mxDoc); - userProperties = supp.getDocumentProperties().getUserDefinedProperties(); - propertySet = UnoRuntime.queryInterface(XPropertySet.class, userProperties); - } - - private List getTextDocuments() throws NoSuchElementException, WrappedTargetException { - List result = new ArrayList<>(); - XEnumerationAccess enumAccess = xDesktop.getComponents(); - XEnumeration componentEnumeration = enumAccess.createEnumeration(); - - // TODO: http://api.openoffice.org/docs/DevelopersGuide/OfficeDev/OfficeDev.xhtml#1_1_3_2_1_2_Frame_Hierarchies - - while (componentEnumeration.hasMoreElements()) { - Object nextElement = componentEnumeration.nextElement(); - XComponent component = UnoRuntime.queryInterface(XComponent.class, nextElement); - XTextDocument document = UnoRuntime.queryInterface(XTextDocument.class, component); - if (document != null) { - result.add(document); - } - } - return result; - } - - private XDesktop simpleBootstrap(Path loPath) - throws CreationException, BootstrapException { - - // Get the office component context: - XComponentContext xContext = org.jabref.gui.openoffice.Bootstrap.bootstrap(loPath); - // Get the office service manager: - XMultiComponentFactory xServiceManager = xContext.getServiceManager(); - // Create the desktop, which is the root frame of the - // hierarchy of frames that contain viewable components: - Object desktop; - try { - desktop = xServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", xContext); - } catch (Exception e) { - throw new CreationException(e.getMessage()); - } - XDesktop resultDesktop = UnoRuntime.queryInterface(XDesktop.class, desktop); - - UnoRuntime.queryInterface(XComponentLoader.class, desktop); - - return resultDesktop; - } - - public Optional getCustomProperty(String property) throws UnknownPropertyException, WrappedTargetException { - if (propertySet.getPropertySetInfo().hasPropertyByName(property)) { - return Optional.ofNullable(propertySet.getPropertyValue(property).toString()); - } - return Optional.empty(); - } - - public void updateSortedReferenceMarks() throws WrappedTargetException, NoSuchElementException { - sortedReferenceMarks = getSortedReferenceMarks(getReferenceMarks()); - } - - public void setCustomProperty(String property, String value) throws UnknownPropertyException, - NotRemoveableException, PropertyExistException, IllegalTypeException, IllegalArgumentException { - if (propertySet.getPropertySetInfo().hasPropertyByName(property)) { - userProperties.removeProperty(property); - } - if (value != null) { - userProperties.addProperty(property, com.sun.star.beans.PropertyAttribute.REMOVEABLE, - new Any(Type.STRING, value)); - } - } - - /** - * This method inserts a cite marker in the text for the given BibEntry, and may refresh the bibliography. - * - * @param entries The entries to cite. - * @param database The database the entry belongs to. - * @param style The bibliography style we are using. - * @param inParenthesis Indicates whether it is an in-text citation or a citation in parenthesis. This is not relevant if numbered citations are used. - * @param withText Indicates whether this should be a normal citation (true) or an empty (invisible) citation (false). - * @param sync Indicates whether the reference list should be refreshed. - * @throws IllegalTypeException - * @throws PropertyExistException - * @throws NotRemoveableException - * @throws UnknownPropertyException - * @throws UndefinedCharacterFormatException - * @throws NoSuchElementException - * @throws WrappedTargetException - * @throws IOException - * @throws PropertyVetoException - * @throws CreationException - * @throws BibEntryNotFoundException - * @throws UndefinedParagraphFormatException - */ - public void insertEntry(List entries, BibDatabase database, - List allBases, OOBibStyle style, - boolean inParenthesis, boolean withText, String pageInfo, boolean sync) - throws IllegalArgumentException, - UnknownPropertyException, NotRemoveableException, PropertyExistException, IllegalTypeException, - UndefinedCharacterFormatException, WrappedTargetException, NoSuchElementException, PropertyVetoException, - IOException, CreationException, BibEntryNotFoundException, UndefinedParagraphFormatException { - - try { - - XTextViewCursor xViewCursor = xViewCursorSupplier.getViewCursor(); - - if (entries.size() > 1) { - if (style.getBooleanCitProperty(OOBibStyle.MULTI_CITE_CHRONOLOGICAL)) { - entries.sort(yearAuthorTitleComparator); - } else { - entries.sort(entryComparator); - } - } - - String keyString = String.join(",", - entries.stream().map(entry -> entry.getCitationKey().orElse("")).collect(Collectors.toList())); - // Insert bookmark: - String bName = getUniqueReferenceMarkName(keyString, - withText ? inParenthesis ? OOBibBase.AUTHORYEAR_PAR : OOBibBase.AUTHORYEAR_INTEXT : OOBibBase.INVISIBLE_CIT); - - // If we should store metadata for page info, do that now: - if (pageInfo != null) { - LOGGER.info("Storing page info: " + pageInfo); - setCustomProperty(bName, pageInfo); - } - - xViewCursor.getText().insertString(xViewCursor, " ", false); - if (style.isFormatCitations()) { - XPropertySet xCursorProps = UnoRuntime.queryInterface(XPropertySet.class, xViewCursor); - String charStyle = style.getCitationCharacterFormat(); - try { - xCursorProps.setPropertyValue(CHAR_STYLE_NAME, charStyle); - } catch (UnknownPropertyException | PropertyVetoException | IllegalArgumentException | - WrappedTargetException ex) { - // Setting the character format failed, so we throw an exception that - // will result in an error message for the user. Before that, - // delete the space we inserted: - xViewCursor.goLeft((short) 1, true); - xViewCursor.setString(""); - throw new UndefinedCharacterFormatException(charStyle); - } - } - xViewCursor.goLeft((short) 1, false); - Map databaseMap = new HashMap<>(); - for (BibEntry entry : entries) { - databaseMap.put(entry, database); - } - String citeText = style.isNumberEntries() ? "-" : style.getCitationMarker(entries, databaseMap, - inParenthesis, null, null); - insertReferenceMark(bName, citeText, xViewCursor, withText, style); - - xViewCursor.collapseToEnd(); - xViewCursor.goRight((short) 1, false); - - XTextRange position = xViewCursor.getEnd(); - - if (sync) { - // To account for numbering and for uniqiefiers, we must refresh the cite markers: - updateSortedReferenceMarks(); - refreshCiteMarkers(allBases, style); - - // Insert it at the current position: - rebuildBibTextSection(allBases, style); - } - - // Go back to the relevant position: - xViewCursor.gotoRange(position, false); - } catch (DisposedException ex) { - // We need to catch this one here because the OpenOfficePanel class is - // loaded before connection, and therefore cannot directly reference - // or catch a DisposedException (which is in a OO JAR file). - throw new ConnectionLostException(ex.getMessage()); - } - } - - public List getJabRefReferenceMarks(XNameAccess nameAccess) { - String[] names = nameAccess.getElementNames(); - // Remove all reference marks that don't look like JabRef citations: - List result = new ArrayList<>(); - if (names != null) { - for (String name : names) { - if (CITE_PATTERN.matcher(name).find()) { - result.add(name); - } - } - } - return result; - } - - /** - * Refresh all cite markers in the document. - * - * @param databases The databases to get entries from. - * @param style The bibliography style to use. - * @return A list of those referenced citation keys that could not be resolved. - * @throws UndefinedCharacterFormatException - * @throws NoSuchElementException - * @throws IllegalArgumentException - * @throws WrappedTargetException - * @throws BibEntryNotFoundException - * @throws CreationException - * @throws IOException - * @throws PropertyVetoException - * @throws UnknownPropertyException - */ - public List refreshCiteMarkers(List databases, OOBibStyle style) - throws WrappedTargetException, IllegalArgumentException, NoSuchElementException, - UndefinedCharacterFormatException, UnknownPropertyException, PropertyVetoException, IOException, - CreationException, BibEntryNotFoundException { - try { - return refreshCiteMarkersInternal(databases, style); - } catch (DisposedException ex) { - // We need to catch this one here because the OpenOfficePanel class is - // loaded before connection, and therefore cannot directly reference - // or catch a DisposedException (which is in a OO JAR file). - throw new ConnectionLostException(ex.getMessage()); - } - } - - private List refreshCiteMarkersInternal(List databases, OOBibStyle style) - throws WrappedTargetException, IllegalArgumentException, NoSuchElementException, - UndefinedCharacterFormatException, UnknownPropertyException, PropertyVetoException, - CreationException, BibEntryNotFoundException { - - List cited = findCitedKeys(); - Map linkSourceBase = new HashMap<>(); - Map entries = findCitedEntries(databases, cited, linkSourceBase); - - XNameAccess xReferenceMarks = getReferenceMarks(); - - List names; - if (style.isSortByPosition()) { - // We need to sort the reference marks according to their order of appearance: - names = sortedReferenceMarks; - } else if (style.isNumberEntries()) { - // We need to sort the reference marks according to the sorting of the bibliographic - // entries: - SortedMap newMap = new TreeMap<>(entryComparator); - for (Map.Entry bibtexEntryBibtexDatabaseEntry : entries.entrySet()) { - newMap.put(bibtexEntryBibtexDatabaseEntry.getKey(), bibtexEntryBibtexDatabaseEntry.getValue()); - } - entries = newMap; - // Rebuild the list of cited keys according to the sort order: - cited.clear(); - for (BibEntry entry : entries.keySet()) { - cited.add(entry.getCitationKey().orElse(null)); - } - names = Arrays.asList(xReferenceMarks.getElementNames()); - } else { - names = sortedReferenceMarks; - } - - // Remove all reference marks that don't look like JabRef citations: - List tmp = new ArrayList<>(); - for (String name : names) { - if (CITE_PATTERN.matcher(name).find()) { - tmp.add(name); - } - } - names = tmp; - - Map numbers = new HashMap<>(); - int lastNum = 0; - // First compute citation markers for all citations: - String[] citMarkers = new String[names.size()]; - String[][] normCitMarkers = new String[names.size()][]; - String[][] bibtexKeys = new String[names.size()][]; - - int minGroupingCount = style.getIntCitProperty(OOBibStyle.MINIMUM_GROUPING_COUNT); - - int[] types = new int[names.size()]; - for (int i = 0; i < names.size(); i++) { - Matcher citeMatcher = CITE_PATTERN.matcher(names.get(i)); - if (citeMatcher.find()) { - String typeStr = citeMatcher.group(1); - int type = Integer.parseInt(typeStr); - types[i] = type; // Remember the type in case we need to uniquefy. - String[] keys = citeMatcher.group(2).split(","); - bibtexKeys[i] = keys; - BibEntry[] cEntries = new BibEntry[keys.length]; - for (int j = 0; j < cEntries.length; j++) { - BibDatabase database = linkSourceBase.get(keys[j]); - Optional tmpEntry = Optional.empty(); - if (database != null) { - tmpEntry = database.getEntryByCitationKey(keys[j]); - } - if (tmpEntry.isPresent()) { - cEntries[j] = tmpEntry.get(); - } else { - LOGGER.info("Citation key not found: '" + keys[j] + '\''); - LOGGER.info("Problem with reference mark: '" + names.get(i) + '\''); - throw new BibEntryNotFoundException(names.get(i), Localization - .lang("Could not resolve BibTeX entry for citation marker '%0'.", names.get(i))); - } - } - - String[] normCitMarker = new String[keys.length]; - String citationMarker; - if (style.isCitationKeyCiteMarkers()) { - StringBuilder sb = new StringBuilder(); - normCitMarkers[i] = new String[keys.length]; - for (int j = 0; j < keys.length; j++) { - normCitMarkers[i][j] = cEntries[j].getCitationKey().orElse(null); - sb.append(cEntries[j].getCitationKey().orElse("")); - if (j < (keys.length - 1)) { - sb.append(','); - } - } - citationMarker = sb.toString(); - } else if (style.isNumberEntries()) { - if (style.isSortByPosition()) { - // We have sorted the citation markers according to their order of appearance, - // so we simply count up for each marker referring to a new entry: - List num = new ArrayList<>(keys.length); - for (int j = 0; j < keys.length; j++) { - if (cEntries[j] instanceof UndefinedBibtexEntry) { - num.add(j, -1); - } else { - num.add(j, lastNum + 1); - if (numbers.containsKey(keys[j])) { - num.set(j, numbers.get(keys[j])); - } else { - numbers.put(keys[j], num.get(j)); - lastNum = num.get(j); - } - } - } - citationMarker = style.getNumCitationMarker(num, minGroupingCount, false); - for (int j = 0; j < keys.length; j++) { - normCitMarker[j] = style.getNumCitationMarker(Collections.singletonList(num.get(j)), - minGroupingCount, false); - } - } else { - // We need to find the number of the cited entry in the bibliography, - // and use that number for the cite marker: - List num = findCitedEntryIndex(names.get(i), cited); - - if (num.isEmpty()) { - throw new BibEntryNotFoundException(names.get(i), Localization - .lang("Could not resolve BibTeX entry for citation marker '%0'.", names.get(i))); - } else { - citationMarker = style.getNumCitationMarker(num, minGroupingCount, false); - } - - for (int j = 0; j < keys.length; j++) { - List list = new ArrayList<>(1); - list.add(num.get(j)); - normCitMarker[j] = style.getNumCitationMarker(list, minGroupingCount, false); - } - } - } else { - - if (cEntries.length > 1) { - if (style.getBooleanCitProperty(OOBibStyle.MULTI_CITE_CHRONOLOGICAL)) { - Arrays.sort(cEntries, yearAuthorTitleComparator); - } else { - Arrays.sort(cEntries, entryComparator); - } - // Update key list to match the new sorting: - for (int j = 0; j < cEntries.length; j++) { - bibtexKeys[i][j] = cEntries[j].getCitationKey().orElse(null); - } - } - - citationMarker = style.getCitationMarker(Arrays.asList(cEntries), entries, - type == OOBibBase.AUTHORYEAR_PAR, null, null); - // We need "normalized" (in parenthesis) markers for uniqueness checking purposes: - for (int j = 0; j < cEntries.length; j++) { - normCitMarker[j] = style.getCitationMarker(Collections.singletonList(cEntries[j]), entries, - true, null, new int[] {-1}); - } - } - citMarkers[i] = citationMarker; - normCitMarkers[i] = normCitMarker; - } - } - - uniquefiers.clear(); - if (!style.isCitationKeyCiteMarkers() && !style.isNumberEntries()) { - // See if there are duplicate citations marks referring to different entries. If so, we need to - // use uniquefiers: - Map> refKeys = new HashMap<>(); - Map> refNums = new HashMap<>(); - for (int i = 0; i < citMarkers.length; i++) { - String[] markers = normCitMarkers[i]; // compare normalized markers, since the actual markers can be different - for (int j = 0; j < markers.length; j++) { - String marker = markers[j]; - String currentKey = bibtexKeys[i][j]; - if (refKeys.containsKey(marker)) { - // Ok, we have seen this exact marker before. - if (!refKeys.get(marker).contains(currentKey)) { - // ... but not for this entry. - refKeys.get(marker).add(currentKey); - refNums.get(marker).add(i); - } - } else { - List l = new ArrayList<>(1); - l.add(currentKey); - refKeys.put(marker, l); - List l2 = new ArrayList<>(1); - l2.add(i); - refNums.put(marker, l2); - } - } - } - // Go through the collected lists and see where we need to uniquefy: - for (Map.Entry> stringListEntry : refKeys.entrySet()) { - List keys = stringListEntry.getValue(); - if (keys.size() > 1) { - // This marker appears for more than one unique entry: - int uniq = 'a'; - for (String key : keys) { - // Update the map of uniquefiers for the benefit of both the following generation of new - // citation markers, and for the method that builds the bibliography: - uniquefiers.put(key, String.valueOf((char) uniq)); - uniq++; - } - } - } - - // Finally, go through all citation markers, and update those referring to entries in our current list: - int maxAuthorsFirst = style.getIntCitProperty(OOBibStyle.MAX_AUTHORS_FIRST); - Set seenBefore = new HashSet<>(); - for (int j = 0; j < bibtexKeys.length; j++) { - boolean needsChange = false; - int[] firstLimAuthors = new int[bibtexKeys[j].length]; - String[] uniquif = new String[bibtexKeys[j].length]; - BibEntry[] cEntries = new BibEntry[bibtexKeys[j].length]; - for (int k = 0; k < bibtexKeys[j].length; k++) { - String currentKey = bibtexKeys[j][k]; - firstLimAuthors[k] = -1; - if (maxAuthorsFirst > 0) { - if (!seenBefore.contains(currentKey)) { - firstLimAuthors[k] = maxAuthorsFirst; - } - seenBefore.add(currentKey); - } - String uniq = uniquefiers.get(currentKey); - Optional tmpEntry = Optional.empty(); - if (uniq == null) { - if (firstLimAuthors[k] > 0) { - needsChange = true; - BibDatabase database = linkSourceBase.get(currentKey); - if (database != null) { - tmpEntry = database.getEntryByCitationKey(currentKey); - } - } else { - BibDatabase database = linkSourceBase.get(currentKey); - if (database != null) { - tmpEntry = database.getEntryByCitationKey(currentKey); - } - } - uniquif[k] = ""; - } else { - needsChange = true; - BibDatabase database = linkSourceBase.get(currentKey); - if (database != null) { - tmpEntry = database.getEntryByCitationKey(currentKey); - } - uniquif[k] = uniq; - } - if (tmpEntry.isPresent()) { - cEntries[k] = tmpEntry.get(); - } - } - if (needsChange) { - citMarkers[j] = style.getCitationMarker(Arrays.asList(cEntries), entries, - types[j] == OOBibBase.AUTHORYEAR_PAR, uniquif, firstLimAuthors); - } - } - } - - // Refresh all reference marks with the citation markers we computed: - boolean hadBibSection = getBookmarkRange(OOBibBase.BIB_SECTION_NAME) != null; - // Check if we are supposed to set a character format for citations: - boolean mustTestCharFormat = style.isFormatCitations(); - for (int i = 0; i < names.size(); i++) { - Object referenceMark = xReferenceMarks.getByName(names.get(i)); - XTextContent bookmark = UnoRuntime.queryInterface(XTextContent.class, referenceMark); - - XTextCursor cursor = bookmark.getAnchor().getText().createTextCursorByRange(bookmark.getAnchor()); - - if (mustTestCharFormat) { - // If we are supposed to set character format for citations, must run a test before we - // delete old citation markers. Otherwise, if the specified character format doesn't - // exist, we end up deleting the markers before the process crashes due to a the missing - // format, with catastrophic consequences for the user. - mustTestCharFormat = false; // need to do this only once - XPropertySet xCursorProps = UnoRuntime.queryInterface(XPropertySet.class, cursor); - String charStyle = style.getCitationCharacterFormat(); - try { - xCursorProps.setPropertyValue(CHAR_STYLE_NAME, charStyle); - } catch (UnknownPropertyException | PropertyVetoException | IllegalArgumentException | - WrappedTargetException ex) { - throw new UndefinedCharacterFormatException(charStyle); - } - } - - text.removeTextContent(bookmark); - - insertReferenceMark(names.get(i), citMarkers[i], cursor, types[i] != OOBibBase.INVISIBLE_CIT, style); - if (hadBibSection && (getBookmarkRange(OOBibBase.BIB_SECTION_NAME) == null)) { - // We have overwritten the marker for the start of the reference list. - // We need to add it again. - cursor.collapseToEnd(); - OOUtil.insertParagraphBreak(text, cursor); - insertBookMark(OOBibBase.BIB_SECTION_NAME, cursor); - } - } - - List unresolvedKeys = new ArrayList<>(); - for (BibEntry entry : entries.keySet()) { - if (entry instanceof UndefinedBibtexEntry) { - String key = ((UndefinedBibtexEntry) entry).getKey(); - if (!unresolvedKeys.contains(key)) { - unresolvedKeys.add(key); - } - } - } - return unresolvedKeys; - } - - private List getSortedReferenceMarks(final XNameAccess nameAccess) - throws WrappedTargetException, NoSuchElementException { - XTextViewCursorSupplier cursorSupplier = UnoRuntime.queryInterface(XTextViewCursorSupplier.class, - mxDoc.getCurrentController()); - - XTextViewCursor viewCursor = cursorSupplier.getViewCursor(); - XTextRange initialPos = viewCursor.getStart(); - List names = Arrays.asList(nameAccess.getElementNames()); - List positions = new ArrayList<>(names.size()); - for (String name : names) { - XTextContent textContent = UnoRuntime.queryInterface(XTextContent.class, nameAccess.getByName(name)); - XTextRange range = textContent.getAnchor(); - // Check if we are inside a footnote: - if (UnoRuntime.queryInterface(XFootnote.class, range.getText()) != null) { - // Find the linking footnote marker: - XFootnote footer = UnoRuntime.queryInterface(XFootnote.class, range.getText()); - // The footnote's anchor gives the correct position in the text: - range = footer.getAnchor(); - } - - positions.add(findPosition(viewCursor, range)); - } - Set set = new TreeSet<>(); - for (int i = 0; i < positions.size(); i++) { - set.add(new ComparableMark(names.get(i), positions.get(i))); - } - - List result = new ArrayList<>(set.size()); - for (ComparableMark mark : set) { - result.add(mark.getName()); - } - viewCursor.gotoRange(initialPos, false); - - return result; - } - - public XNameAccess getReferenceMarks() { - XReferenceMarksSupplier supplier = UnoRuntime.queryInterface(XReferenceMarksSupplier.class, xCurrentComponent); - return supplier.getReferenceMarks(); - } - - private String getUniqueReferenceMarkName(String bibtexKey, int type) { - XNameAccess xNamedRefMarks = getReferenceMarks(); - int i = 0; - String name = OOBibBase.BIB_CITATION + '_' + type + '_' + bibtexKey; - while (xNamedRefMarks.hasByName(name)) { - name = OOBibBase.BIB_CITATION + i + '_' + type + '_' + bibtexKey; - i++; - } - return name; - } - - public void rebuildBibTextSection(List databases, OOBibStyle style) - throws NoSuchElementException, WrappedTargetException, IllegalArgumentException, - CreationException, PropertyVetoException, UnknownPropertyException, UndefinedParagraphFormatException { - List cited = findCitedKeys(); - Map linkSourceBase = new HashMap<>(); - Map entries = findCitedEntries(databases, cited, linkSourceBase); // Although entries are redefined without use, this also updates linkSourceBase - - List names = sortedReferenceMarks; - - if (style.isSortByPosition()) { - // We need to sort the entries according to their order of appearance: - entries = getSortedEntriesFromSortedRefMarks(names, linkSourceBase); - } else { - SortedMap newMap = new TreeMap<>(entryComparator); - for (Map.Entry bibtexEntryBibtexDatabaseEntry : findCitedEntries(databases, cited, - linkSourceBase).entrySet()) { - newMap.put(bibtexEntryBibtexDatabaseEntry.getKey(), bibtexEntryBibtexDatabaseEntry.getValue()); - } - entries = newMap; - } - clearBibTextSectionContent2(); - populateBibTextSection(entries, style); - } - - private List findCitedKeys() throws NoSuchElementException, WrappedTargetException { - XNameAccess xNamedMarks = getReferenceMarks(); - String[] names = xNamedMarks.getElementNames(); - List keys = new ArrayList<>(); - for (String name1 : names) { - Object bookmark = xNamedMarks.getByName(name1); - UnoRuntime.queryInterface(XTextContent.class, bookmark); - - List newKeys = parseRefMarkName(name1); - for (String key : newKeys) { - if (!keys.contains(key)) { - keys.add(key); - } - } - } - - return keys; - } - - private Map findCitedEntries(List databases, List keys, - Map linkSourceBase) { - Map entries = new LinkedHashMap<>(); - for (String key : keys) { - boolean found = false; - for (BibDatabase database : databases) { - Optional entry = database.getEntryByCitationKey(key); - if (entry.isPresent()) { - entries.put(entry.get(), database); - linkSourceBase.put(key, database); - found = true; - break; - } - } - - if (!found) { - entries.put(new UndefinedBibtexEntry(key), null); - } - } - return entries; - } - - private Point findPosition(XTextViewCursor cursor, XTextRange range) { - cursor.gotoRange(range, false); - return cursor.getPosition(); - } - - /** - * Extract the list of citation keys from a reference mark name. - * - * @param name The reference mark name. - * @return The list of citation keys encoded in the name. - */ - public List parseRefMarkName(String name) { - List keys = new ArrayList<>(); - Matcher citeMatcher = CITE_PATTERN.matcher(name); - if (citeMatcher.find()) { - String[] keystring = citeMatcher.group(2).split(","); - for (String aKeystring : keystring) { - if (!keys.contains(aKeystring)) { - keys.add(aKeystring); - } - } - } - return keys; - } - - /** - * Resolve the citation key from a citation reference marker name, and look up the index of the key in a list of keys. - * - * @param citRefName The name of the ReferenceMark representing the citation. - * @param keys A List of citation keys representing the entries in the bibliography. - * @return the indices of the cited keys, -1 if a key is not found. Returns null if the ref name could not be resolved as a citation. - */ - private List findCitedEntryIndex(String citRefName, List keys) { - Matcher citeMatcher = CITE_PATTERN.matcher(citRefName); - if (citeMatcher.find()) { - List keyStrings = Arrays.asList(citeMatcher.group(2).split(",")); - List result = new ArrayList<>(keyStrings.size()); - for (String key : keyStrings) { - int ind = keys.indexOf(key); - result.add(ind == -1 ? -1 : 1 + ind); - } - return result; - } else { - return Collections.emptyList(); - } - } - - private Map getSortedEntriesFromSortedRefMarks(List names, - Map linkSourceBase) { - - Map newList = new LinkedHashMap<>(); - for (String name : names) { - Matcher citeMatcher = CITE_PATTERN.matcher(name); - if (citeMatcher.find()) { - String[] keys = citeMatcher.group(2).split(","); - for (String key : keys) { - BibDatabase database = linkSourceBase.get(key); - Optional origEntry = Optional.empty(); - if (database != null) { - origEntry = database.getEntryByCitationKey(key); - } - if (origEntry.isPresent()) { - if (!newList.containsKey(origEntry.get())) { - newList.put(origEntry.get(), database); - } - } else { - LOGGER.info("Citation key not found: '" + key + "'"); - LOGGER.info("Problem with reference mark: '" + name + "'"); - newList.put(new UndefinedBibtexEntry(key), null); - } - } - } - } - - return newList; - } - - public String getCitationContext(XNameAccess nameAccess, String refMarkName, int charBefore, int charAfter, - boolean htmlMarkup) - throws NoSuchElementException, WrappedTargetException { - Object referenceMark = nameAccess.getByName(refMarkName); - XTextContent bookmark = UnoRuntime.queryInterface(XTextContent.class, referenceMark); - - XTextCursor cursor = bookmark.getAnchor().getText().createTextCursorByRange(bookmark.getAnchor()); - String citPart = cursor.getString(); - int flex = 8; - for (int i = 0; i < charBefore; i++) { - try { - cursor.goLeft((short) 1, true); - if ((i >= (charBefore - flex)) && Character.isWhitespace(cursor.getString().charAt(0))) { - break; - } - } catch (IndexOutOfBoundsException ex) { - LOGGER.warn("Problem going left", ex); - } - } - int length = cursor.getString().length(); - int added = length - citPart.length(); - cursor.collapseToStart(); - for (int i = 0; i < (charAfter + length); i++) { - try { - cursor.goRight((short) 1, true); - if (i >= ((charAfter + length) - flex)) { - String strNow = cursor.getString(); - if (Character.isWhitespace(strNow.charAt(strNow.length() - 1))) { - break; - } - } - } catch (IndexOutOfBoundsException ex) { - LOGGER.warn("Problem going right", ex); - } - } - - String result = cursor.getString(); - if (htmlMarkup) { - result = result.substring(0, added) + "" + citPart + "" + result.substring(length); - } - return result.trim(); - } - - private void insertFullReferenceAtCursor(XTextCursor cursor, Map entries, OOBibStyle style, - String parFormat) - throws UndefinedParagraphFormatException, IllegalArgumentException, - UnknownPropertyException, PropertyVetoException, WrappedTargetException { - Map correctEntries; - // If we don't have numbered entries, we need to sort the entries before adding them: - if (style.isSortByPosition()) { - // Use the received map directly - correctEntries = entries; - } else { - // Sort map - Map newMap = new TreeMap<>(entryComparator); - newMap.putAll(entries); - correctEntries = newMap; - } - int number = 1; - for (Map.Entry entry : correctEntries.entrySet()) { - if (entry.getKey() instanceof UndefinedBibtexEntry) { - continue; - } - OOUtil.insertParagraphBreak(text, cursor); - if (style.isNumberEntries()) { - int minGroupingCount = style.getIntCitProperty(OOBibStyle.MINIMUM_GROUPING_COUNT); - OOUtil.insertTextAtCurrentLocation(text, cursor, - style.getNumCitationMarker(Collections.singletonList(number++), minGroupingCount, true), Collections.emptyList()); - } - Layout layout = style.getReferenceFormat(entry.getKey().getType()); - layout.setPostFormatter(POSTFORMATTER); - OOUtil.insertFullReferenceAtCurrentLocation(text, cursor, layout, parFormat, entry.getKey(), - entry.getValue(), uniquefiers.get(entry.getKey().getCitationKey().orElse(null))); - } - } - - private void createBibTextSection2(boolean end) - throws IllegalArgumentException, CreationException { - - XTextCursor mxDocCursor = text.createTextCursor(); - if (end) { - mxDocCursor.gotoEnd(false); - } - OOUtil.insertParagraphBreak(text, mxDocCursor); - // Create a new TextSection from the document factory and access it's XNamed interface - XNamed xChildNamed; - try { - xChildNamed = UnoRuntime.queryInterface(XNamed.class, - mxDocFactory.createInstance("com.sun.star.text.TextSection")); - } catch (Exception e) { - throw new CreationException(e.getMessage()); - } - // Set the new sections name to 'Child_Section' - xChildNamed.setName(OOBibBase.BIB_SECTION_NAME); - // Access the Child_Section's XTextContent interface and insert it into the document - XTextContent xChildSection = UnoRuntime.queryInterface(XTextContent.class, xChildNamed); - text.insertTextContent(mxDocCursor, xChildSection, false); - } - - private void clearBibTextSectionContent2() - throws NoSuchElementException, WrappedTargetException, IllegalArgumentException, CreationException { - - // Check if the section exists: - XTextSectionsSupplier supplier = UnoRuntime.queryInterface(XTextSectionsSupplier.class, mxDoc); - if (supplier.getTextSections().hasByName(OOBibBase.BIB_SECTION_NAME)) { - XTextSection section = (XTextSection) ((Any) supplier.getTextSections().getByName(OOBibBase.BIB_SECTION_NAME)) - .getObject(); - // Clear it: - XTextCursor cursor = text.createTextCursorByRange(section.getAnchor()); - cursor.gotoRange(section.getAnchor(), false); - cursor.setString(""); - } else { - createBibTextSection2(atEnd); - } - } - - private void populateBibTextSection(Map entries, OOBibStyle style) - throws NoSuchElementException, WrappedTargetException, PropertyVetoException, - UnknownPropertyException, UndefinedParagraphFormatException, IllegalArgumentException, CreationException { - XTextSectionsSupplier supplier = UnoRuntime.queryInterface(XTextSectionsSupplier.class, mxDoc); - XTextSection section = (XTextSection) ((Any) supplier.getTextSections().getByName(OOBibBase.BIB_SECTION_NAME)) - .getObject(); - XTextCursor cursor = text.createTextCursorByRange(section.getAnchor()); - OOUtil.insertTextAtCurrentLocation(text, cursor, (String) style.getProperty(OOBibStyle.TITLE), - (String) style.getProperty(OOBibStyle.REFERENCE_HEADER_PARAGRAPH_FORMAT)); - insertFullReferenceAtCursor(cursor, entries, style, - (String) style.getProperty(OOBibStyle.REFERENCE_PARAGRAPH_FORMAT)); - insertBookMark(OOBibBase.BIB_SECTION_END_NAME, cursor); - } - - private XTextContent insertBookMark(String name, XTextCursor position) - throws IllegalArgumentException, CreationException { - Object bookmark; - try { - bookmark = mxDocFactory.createInstance("com.sun.star.text.Bookmark"); - } catch (Exception e) { - throw new CreationException(e.getMessage()); - } - // name the bookmark - XNamed xNamed = UnoRuntime.queryInterface(XNamed.class, bookmark); - xNamed.setName(name); - // get XTextContent interface - XTextContent xTextContent = UnoRuntime.queryInterface(XTextContent.class, bookmark); - // insert bookmark at the end of the document - // instead of mxDocText.getEnd you could use a text cursor's XTextRange interface or any XTextRange - text.insertTextContent(position, xTextContent, true); - position.collapseToEnd(); - return xTextContent; - } - - private void insertReferenceMark(String name, String citationText, XTextCursor position, boolean withText, - OOBibStyle style) - throws UnknownPropertyException, WrappedTargetException, - PropertyVetoException, IllegalArgumentException, UndefinedCharacterFormatException, CreationException { - - // Check if there is "page info" stored for this citation. If so, insert it into - // the citation text before inserting the citation: - Optional pageInfo = getCustomProperty(name); - String citText; - if ((pageInfo.isPresent()) && !pageInfo.get().isEmpty()) { - citText = style.insertPageInfo(citationText, pageInfo.get()); - } else { - citText = citationText; - } - - Object bookmark; - try { - bookmark = mxDocFactory.createInstance("com.sun.star.text.ReferenceMark"); - } catch (Exception e) { - throw new CreationException(e.getMessage()); - } - // Name the reference - XNamed xNamed = UnoRuntime.queryInterface(XNamed.class, bookmark); - xNamed.setName(name); - - if (withText) { - position.setString(citText); - XPropertySet xCursorProps = UnoRuntime.queryInterface(XPropertySet.class, position); - - // Set language to [None]: - xCursorProps.setPropertyValue("CharLocale", new Locale("zxx", "", "")); - if (style.isFormatCitations()) { - String charStyle = style.getCitationCharacterFormat(); - try { - xCursorProps.setPropertyValue(CHAR_STYLE_NAME, charStyle); - } catch (UnknownPropertyException | PropertyVetoException | IllegalArgumentException | - WrappedTargetException ex) { - throw new UndefinedCharacterFormatException(charStyle); - } - } - } else { - position.setString(""); - } - - // get XTextContent interface - XTextContent xTextContent = UnoRuntime.queryInterface(XTextContent.class, bookmark); - - position.getText().insertTextContent(position, xTextContent, true); - - // Check if we should italicize the "et al." string in citations: - boolean italicize = style.getBooleanCitProperty(OOBibStyle.ITALIC_ET_AL); - if (italicize) { - String etAlString = style.getStringCitProperty(OOBibStyle.ET_AL_STRING); - int index = citText.indexOf(etAlString); - if (index >= 0) { - italicizeOrBold(position, true, index, index + etAlString.length()); - } - } - - position.collapseToEnd(); - } - - private void removeReferenceMark(String name) throws NoSuchElementException, WrappedTargetException { - XNameAccess xReferenceMarks = getReferenceMarks(); - if (xReferenceMarks.hasByName(name)) { - Object referenceMark = xReferenceMarks.getByName(name); - XTextContent bookmark = UnoRuntime.queryInterface(XTextContent.class, referenceMark); - text.removeTextContent(bookmark); - } - } - - /** - * Get the XTextRange corresponding to the named bookmark. - * - * @param name The name of the bookmark to find. - * @return The XTextRange for the bookmark. - * @throws WrappedTargetException - * @throws NoSuchElementException - */ - private XTextRange getBookmarkRange(String name) throws NoSuchElementException, WrappedTargetException { - XNameAccess xNamedBookmarks = getBookmarks(); - - // retrieve bookmark by name - if (!xNamedBookmarks.hasByName(name)) { - return null; - } - Object foundBookmark = xNamedBookmarks.getByName(name); - XTextContent xFoundBookmark = UnoRuntime.queryInterface(XTextContent.class, foundBookmark); - return xFoundBookmark.getAnchor(); - } - - private XNameAccess getBookmarks() { - // query XBookmarksSupplier from document model and get bookmarks collection - XBookmarksSupplier xBookmarksSupplier = UnoRuntime.queryInterface(XBookmarksSupplier.class, xCurrentComponent); - XNameAccess xNamedBookmarks = xBookmarksSupplier.getBookmarks(); - return xNamedBookmarks; - } - - private void italicizeOrBold(XTextCursor position, boolean italicize, int start, int end) - throws UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException { - XTextRange range = position.getStart(); - XTextCursor cursor = position.getText().createTextCursorByRange(range); - cursor.goRight((short) start, false); - cursor.goRight((short) (end - start), true); - XPropertySet xcp = UnoRuntime.queryInterface(XPropertySet.class, cursor); - if (italicize) { - xcp.setPropertyValue("CharPosture", com.sun.star.awt.FontSlant.ITALIC); - } else { - xcp.setPropertyValue("CharWeight", com.sun.star.awt.FontWeight.BOLD); - } - } - - public void combineCiteMarkers(List databases, OOBibStyle style) - throws IOException, WrappedTargetException, NoSuchElementException, IllegalArgumentException, - UndefinedCharacterFormatException, UnknownPropertyException, PropertyVetoException, CreationException, - BibEntryNotFoundException { - XNameAccess nameAccess = getReferenceMarks(); - // TODO: doesn't work for citations in footnotes/tables - List names = getSortedReferenceMarks(nameAccess); - - final XTextRangeCompare compare = UnoRuntime.queryInterface(XTextRangeCompare.class, text); - - int piv = 0; - boolean madeModifications = false; - while (piv < (names.size() - 1)) { - XTextRange range1 = UnoRuntime.queryInterface(XTextContent.class, nameAccess.getByName(names.get(piv))) - .getAnchor().getEnd(); - XTextRange range2 = UnoRuntime.queryInterface(XTextContent.class, nameAccess.getByName(names.get(piv + 1))) - .getAnchor().getStart(); - if (range1.getText() != range2.getText()) { - piv++; - continue; - } - XTextCursor mxDocCursor = range1.getText().createTextCursorByRange(range1); - mxDocCursor.goRight((short) 1, true); - boolean couldExpand = true; - while (couldExpand && (compare.compareRegionEnds(mxDocCursor, range2) > 0)) { - couldExpand = mxDocCursor.goRight((short) 1, true); - } - String cursorText = mxDocCursor.getString(); - // Check if the string contains no line breaks and only whitespace: - if ((cursorText.indexOf('\n') == -1) && cursorText.trim().isEmpty()) { - - // If we are supposed to set character format for citations, test this before - // making any changes. This way we can throw an exception before any reference - // marks are removed, preventing damage to the user's document: - if (style.isFormatCitations()) { - XPropertySet xCursorProps = UnoRuntime.queryInterface(XPropertySet.class, mxDocCursor); - String charStyle = style.getCitationCharacterFormat(); - try { - xCursorProps.setPropertyValue(CHAR_STYLE_NAME, charStyle); - } catch (UnknownPropertyException | PropertyVetoException | IllegalArgumentException | - WrappedTargetException ex) { - // Setting the character format failed, so we throw an exception that - // will result in an error message for the user: - throw new UndefinedCharacterFormatException(charStyle); - } - } - - List keys = parseRefMarkName(names.get(piv)); - keys.addAll(parseRefMarkName(names.get(piv + 1))); - removeReferenceMark(names.get(piv)); - removeReferenceMark(names.get(piv + 1)); - List entries = new ArrayList<>(); - for (String key : keys) { - for (BibDatabase database : databases) { - Optional entry = database.getEntryByCitationKey(key); - if (entry.isPresent()) { - entries.add(entry.get()); - break; - } - } - } - Collections.sort(entries, new FieldComparator(StandardField.YEAR)); - String keyString = String.join(",", entries.stream().map(entry -> entry.getCitationKey().orElse("")) - .collect(Collectors.toList())); - // Insert bookmark: - String bName = getUniqueReferenceMarkName(keyString, OOBibBase.AUTHORYEAR_PAR); - insertReferenceMark(bName, "tmp", mxDocCursor, true, style); - names.set(piv + 1, bName); - madeModifications = true; - } - piv++; - } - if (madeModifications) { - updateSortedReferenceMarks(); - refreshCiteMarkers(databases, style); - } - } - - /** - * Do the opposite of combineCiteMarkers. - * Combined markers are split, with a space inserted between. - */ - public void unCombineCiteMarkers(List databases, OOBibStyle style) - throws IOException, WrappedTargetException, NoSuchElementException, IllegalArgumentException, - UndefinedCharacterFormatException, UnknownPropertyException, PropertyVetoException, CreationException, - BibEntryNotFoundException { - XNameAccess nameAccess = getReferenceMarks(); - List names = getSortedReferenceMarks(nameAccess); - - final XTextRangeCompare compare = UnoRuntime.queryInterface(XTextRangeCompare.class, text); - - int pivot = 0; - boolean madeModifications = false; - while (pivot < (names.size())) { - XTextRange range1 = UnoRuntime.queryInterface(XTextContent.class, nameAccess.getByName(names.get(pivot))) - .getAnchor(); - - XTextCursor textCursor = range1.getText().createTextCursorByRange(range1); - - // If we are supposed to set character format for citations, test this before - // making any changes. This way we can throw an exception before any reference - // marks are removed, preventing damage to the user's document: - if (style.isFormatCitations()) { - XPropertySet xCursorProps = UnoRuntime.queryInterface(XPropertySet.class, textCursor); - String charStyle = style.getCitationCharacterFormat(); - try { - xCursorProps.setPropertyValue(CHAR_STYLE_NAME, charStyle); - } catch (UnknownPropertyException | PropertyVetoException | IllegalArgumentException | - WrappedTargetException ex) { - // Setting the character format failed, so we throw an exception that - // will result in an error message for the user: - throw new UndefinedCharacterFormatException(charStyle); - } - } - - List keys = parseRefMarkName(names.get(pivot)); - if (keys.size() > 1) { - removeReferenceMark(names.get(pivot)); - - // Insert bookmark for each key - int last = keys.size() - 1; - int i = 0; - for (String key : keys) { - String newName = getUniqueReferenceMarkName(key, OOBibBase.AUTHORYEAR_PAR); - insertReferenceMark(newName, "tmp", textCursor, true, style); - textCursor.collapseToEnd(); - if (i != last) { - textCursor.setString(" "); - textCursor.collapseToEnd(); - } - i++; - } - madeModifications = true; - } - pivot++; - } - if (madeModifications) { - updateSortedReferenceMarks(); - refreshCiteMarkers(databases, style); - } - } - - public BibDatabase generateDatabase(List databases) - throws NoSuchElementException, WrappedTargetException { - BibDatabase resultDatabase = new BibDatabase(); - List cited = findCitedKeys(); - List entriesToInsert = new ArrayList<>(); - - // For each cited key - for (String key : cited) { - // Loop through the available databases - for (BibDatabase loopDatabase : databases) { - Optional entry = loopDatabase.getEntryByCitationKey(key); - // If entry found - if (entry.isPresent()) { - BibEntry clonedEntry = (BibEntry) entry.get().clone(); - // Insert a copy of the entry - entriesToInsert.add(clonedEntry); - // Check if the cloned entry has a crossref field - clonedEntry.getField(StandardField.CROSSREF).ifPresent(crossref -> { - // If the crossref entry is not already in the database - if (!resultDatabase.getEntryByCitationKey(crossref).isPresent()) { - // Add it if it is in the current library - loopDatabase.getEntryByCitationKey(crossref).ifPresent(entriesToInsert::add); - } - }); - - // Be happy with the first found BibEntry and move on to next key - break; - } - } - } - resultDatabase.insertEntries(entriesToInsert); - return resultDatabase; - } - - private static class ComparableMark implements Comparable { - - private final String name; - private final Point position; - - public ComparableMark(String name, Point position) { - this.name = name; - this.position = position; - } - - @Override - public int compareTo(ComparableMark other) { - if (position.Y == other.position.Y) { - return position.X - other.position.X; - } else { - return position.Y - other.position.Y; - } - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (o instanceof ComparableMark) { - ComparableMark other = (ComparableMark) o; - return (this.position.X == other.position.X) && (this.position.Y == other.position.Y) - && Objects.equals(this.name, other.name); - } - return false; - } - - public String getName() { - return name; - } - - @Override - public int hashCode() { - return Objects.hash(position, name); - } - } - - private class DocumentTitleViewModel { - - private final XTextDocument xTextDocument; - private final String description; - - public DocumentTitleViewModel(XTextDocument xTextDocument) { - this.xTextDocument = xTextDocument; - this.description = getDocumentTitle(xTextDocument).orElse(""); - } - - public XTextDocument getXtextDocument() { - return xTextDocument; - } - - @Override - public String toString() { - return description; - } - } -} diff --git a/src/main/java/org/jabref/gui/openoffice/UndefinedCharacterFormatException.java b/src/main/java/org/jabref/gui/openoffice/UndefinedCharacterFormatException.java deleted file mode 100644 index 4ab29ca2fa5..00000000000 --- a/src/main/java/org/jabref/gui/openoffice/UndefinedCharacterFormatException.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.jabref.gui.openoffice; - -/** - * Exception used to indicate that the plugin attempted to set a character format that is - * not defined in the current OpenOffice document. - */ -class UndefinedCharacterFormatException extends Exception { - - private final String formatName; - - public UndefinedCharacterFormatException(String formatName) { - super(); - this.formatName = formatName; - } - - public String getFormatName() { - return formatName; - } -} diff --git a/src/main/java/org/jabref/logic/openoffice/OOUtil.java b/src/main/java/org/jabref/logic/openoffice/OOUtil.java deleted file mode 100644 index 9efab82773c..00000000000 --- a/src/main/java/org/jabref/logic/openoffice/OOUtil.java +++ /dev/null @@ -1,285 +0,0 @@ -package org.jabref.logic.openoffice; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.jabref.architecture.AllowedToUseAwt; -import org.jabref.logic.layout.Layout; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.Field; -import org.jabref.model.entry.field.UnknownField; - -import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.beans.XPropertySet; -import com.sun.star.lang.WrappedTargetException; -import com.sun.star.text.ControlCharacter; -import com.sun.star.text.XParagraphCursor; -import com.sun.star.text.XText; -import com.sun.star.text.XTextCursor; -import com.sun.star.uno.UnoRuntime; - -/** - * Utility methods for processing OO Writer documents. - */ -@AllowedToUseAwt("Requires AWT for changing document properties") -public class OOUtil { - - private static final String CHAR_STRIKEOUT = "CharStrikeout"; - private static final String CHAR_UNDERLINE = "CharUnderline"; - private static final String PARA_STYLE_NAME = "ParaStyleName"; - private static final String CHAR_CASE_MAP = "CharCaseMap"; - private static final String CHAR_POSTURE = "CharPosture"; - private static final String CHAR_WEIGHT = "CharWeight"; - private static final String CHAR_ESCAPEMENT_HEIGHT = "CharEscapementHeight"; - private static final String CHAR_ESCAPEMENT = "CharEscapement"; - - public enum Formatting { - BOLD, - ITALIC, - SMALLCAPS, - SUPERSCRIPT, - SUBSCRIPT, - UNDERLINE, - STRIKEOUT, - MONOSPACE - } - - private static final Pattern HTML_TAG = Pattern.compile(""); - - private static final Field UNIQUEFIER_FIELD = new UnknownField("uniq"); - - private OOUtil() { - // Just to hide the public constructor - } - - /** - * Insert a reference, formatted using a Layout, at the position of a given cursor. - * - * @param text The text to insert in. - * @param cursor The cursor giving the insert location. - * @param layout The Layout to format the reference with. - * @param parStyle The name of the paragraph style to use. - * @param entry The entry to insert. - * @param database The database the entry belongs to. - * @param uniquefier Uniqiefier letter, if any, to append to the entry's year. - */ - public static void insertFullReferenceAtCurrentLocation(XText text, XTextCursor cursor, - Layout layout, String parStyle, BibEntry entry, BibDatabase database, String uniquefier) - throws UndefinedParagraphFormatException, UnknownPropertyException, PropertyVetoException, - WrappedTargetException, IllegalArgumentException { - - // Backup the value of the uniq field, just in case the entry already has it: - Optional oldUniqVal = entry.getField(UNIQUEFIER_FIELD); - - // Set the uniq field with the supplied uniquefier: - if (uniquefier == null) { - entry.clearField(UNIQUEFIER_FIELD); - } else { - entry.setField(UNIQUEFIER_FIELD, uniquefier); - } - - // Do the layout for this entry: - String formattedText = layout.doLayout(entry, database); - - // Afterwards, reset the old value: - if (oldUniqVal.isPresent()) { - entry.setField(UNIQUEFIER_FIELD, oldUniqVal.get()); - } else { - entry.clearField(UNIQUEFIER_FIELD); - } - - // Insert the formatted text: - OOUtil.insertOOFormattedTextAtCurrentLocation(text, cursor, formattedText, parStyle); - } - - /** - * Insert a text with formatting indicated by HTML-like tags, into a text at the position given by a cursor. - * - * @param text The text to insert in. - * @param cursor The cursor giving the insert location. - * @param lText The marked-up text to insert. - * @param parStyle The name of the paragraph style to use. - * @throws WrappedTargetException - * @throws PropertyVetoException - * @throws UnknownPropertyException - * @throws IllegalArgumentException - */ - public static void insertOOFormattedTextAtCurrentLocation(XText text, XTextCursor cursor, String lText, - String parStyle) throws UndefinedParagraphFormatException, UnknownPropertyException, PropertyVetoException, - WrappedTargetException, IllegalArgumentException { - - XParagraphCursor parCursor = UnoRuntime.queryInterface( - XParagraphCursor.class, cursor); - XPropertySet props = UnoRuntime.queryInterface( - XPropertySet.class, parCursor); - - try { - props.setPropertyValue(PARA_STYLE_NAME, parStyle); - } catch (com.sun.star.lang.IllegalArgumentException ex) { - throw new UndefinedParagraphFormatException(parStyle); - } - - List formatting = new ArrayList<>(); - // We need to extract formatting. Use a simple regexp search iteration: - int piv = 0; - Matcher m = OOUtil.HTML_TAG.matcher(lText); - while (m.find()) { - String currentSubstring = lText.substring(piv, m.start()); - if (!currentSubstring.isEmpty()) { - OOUtil.insertTextAtCurrentLocation(text, cursor, currentSubstring, formatting); - } - String tag = m.group(); - // Handle tags: - if ("".equals(tag)) { - formatting.add(Formatting.BOLD); - } else if ("".equals(tag)) { - formatting.remove(Formatting.BOLD); - } else if ("".equals(tag) || "".equals(tag)) { - formatting.add(Formatting.ITALIC); - } else if ("".equals(tag) || "".equals(tag)) { - formatting.remove(Formatting.ITALIC); - } else if ("".equals(tag)) { - formatting.add(Formatting.MONOSPACE); - } else if ("".equals(tag)) { - formatting.remove(Formatting.MONOSPACE); - } else if ("".equals(tag)) { - formatting.add(Formatting.SMALLCAPS); - } else if ("".equals(tag)) { - formatting.remove(Formatting.SMALLCAPS); - } else if ("".equals(tag)) { - formatting.add(Formatting.SUPERSCRIPT); - } else if ("".equals(tag)) { - formatting.remove(Formatting.SUPERSCRIPT); - } else if ("".equals(tag)) { - formatting.add(Formatting.SUBSCRIPT); - } else if ("".equals(tag)) { - formatting.remove(Formatting.SUBSCRIPT); - } else if ("".equals(tag)) { - formatting.add(Formatting.UNDERLINE); - } else if ("".equals(tag)) { - formatting.remove(Formatting.UNDERLINE); - } else if ("".equals(tag)) { - formatting.add(Formatting.STRIKEOUT); - } else if ("".equals(tag)) { - formatting.remove(Formatting.STRIKEOUT); - } - - piv = m.end(); - } - - if (piv < lText.length()) { - OOUtil.insertTextAtCurrentLocation(text, cursor, lText.substring(piv), formatting); - } - - cursor.collapseToEnd(); - } - - public static void insertParagraphBreak(XText text, XTextCursor cursor) throws IllegalArgumentException { - text.insertControlCharacter(cursor, ControlCharacter.PARAGRAPH_BREAK, true); - cursor.collapseToEnd(); - } - - public static void insertTextAtCurrentLocation(XText text, XTextCursor cursor, String string, - List formatting) - throws UnknownPropertyException, PropertyVetoException, WrappedTargetException, - IllegalArgumentException { - text.insertString(cursor, string, true); - // Access the property set of the cursor, and set the currently selected text - // (which is the string we just inserted) to be bold - XPropertySet xCursorProps = UnoRuntime.queryInterface( - XPropertySet.class, cursor); - if (formatting.contains(Formatting.BOLD)) { - xCursorProps.setPropertyValue(CHAR_WEIGHT, - com.sun.star.awt.FontWeight.BOLD); - } else { - xCursorProps.setPropertyValue(CHAR_WEIGHT, - com.sun.star.awt.FontWeight.NORMAL); - } - - if (formatting.contains(Formatting.ITALIC)) { - xCursorProps.setPropertyValue(CHAR_POSTURE, - com.sun.star.awt.FontSlant.ITALIC); - } else { - xCursorProps.setPropertyValue(CHAR_POSTURE, - com.sun.star.awt.FontSlant.NONE); - } - - if (formatting.contains(Formatting.SMALLCAPS)) { - xCursorProps.setPropertyValue(CHAR_CASE_MAP, - com.sun.star.style.CaseMap.SMALLCAPS); - } else { - xCursorProps.setPropertyValue(CHAR_CASE_MAP, - com.sun.star.style.CaseMap.NONE); - } - - // TODO: the tag doesn't work - /* - if (formatting.contains(Formatting.MONOSPACE)) { - xCursorProps.setPropertyValue("CharFontPitch", - com.sun.star.awt.FontPitch.FIXED); - } - else { - xCursorProps.setPropertyValue("CharFontPitch", - com.sun.star.awt.FontPitch.VARIABLE); - } */ - if (formatting.contains(Formatting.SUBSCRIPT)) { - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT, - (byte) -101); - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT_HEIGHT, - (byte) 58); - } else if (formatting.contains(Formatting.SUPERSCRIPT)) { - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT, - (byte) 101); - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT_HEIGHT, - (byte) 58); - } else { - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT, - (byte) 0); - xCursorProps.setPropertyValue(CHAR_ESCAPEMENT_HEIGHT, - (byte) 100); - } - - if (formatting.contains(Formatting.UNDERLINE)) { - xCursorProps.setPropertyValue(CHAR_UNDERLINE, com.sun.star.awt.FontUnderline.SINGLE); - } else { - xCursorProps.setPropertyValue(CHAR_UNDERLINE, com.sun.star.awt.FontUnderline.NONE); - } - - if (formatting.contains(Formatting.STRIKEOUT)) { - xCursorProps.setPropertyValue(CHAR_STRIKEOUT, com.sun.star.awt.FontStrikeout.SINGLE); - } else { - xCursorProps.setPropertyValue(CHAR_STRIKEOUT, com.sun.star.awt.FontStrikeout.NONE); - } - cursor.collapseToEnd(); - } - - public static void insertTextAtCurrentLocation(XText text, XTextCursor cursor, String string, String parStyle) - throws WrappedTargetException, PropertyVetoException, UnknownPropertyException, - UndefinedParagraphFormatException { - text.insertString(cursor, string, true); - XParagraphCursor parCursor = UnoRuntime.queryInterface( - XParagraphCursor.class, cursor); - // Access the property set of the cursor, and set the currently selected text - // (which is the string we just inserted) to be bold - XPropertySet props = UnoRuntime.queryInterface( - XPropertySet.class, parCursor); - try { - props.setPropertyValue(PARA_STYLE_NAME, parStyle); - } catch (IllegalArgumentException ex) { - throw new UndefinedParagraphFormatException(parStyle); - } - cursor.collapseToEnd(); - } - - public static Object getProperty(Object o, String property) - throws UnknownPropertyException, WrappedTargetException { - XPropertySet props = UnoRuntime.queryInterface( - XPropertySet.class, o); - return props.getPropertyValue(property); - } -} diff --git a/src/main/java/org/jabref/logic/openoffice/UndefinedBibtexEntry.java b/src/main/java/org/jabref/logic/openoffice/UndefinedBibtexEntry.java deleted file mode 100644 index 8a1a7cf5e8f..00000000000 --- a/src/main/java/org/jabref/logic/openoffice/UndefinedBibtexEntry.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.jabref.logic.openoffice; - -import org.jabref.logic.openoffice.style.OOBibStyle; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.StandardField; - -/** - * Subclass of BibEntry for representing entries referenced in a document that can't be found in JabRef's current database. - */ -public class UndefinedBibtexEntry extends BibEntry { - - private final String key; - - public UndefinedBibtexEntry(String key) { - this.key = key; - setField(StandardField.AUTHOR, OOBibStyle.UNDEFINED_CITATION_MARKER); - } - - public String getKey() { - return key; - } -} diff --git a/src/main/java/org/jabref/logic/openoffice/UndefinedParagraphFormatException.java b/src/main/java/org/jabref/logic/openoffice/UndefinedParagraphFormatException.java deleted file mode 100644 index 361f8d44f54..00000000000 --- a/src/main/java/org/jabref/logic/openoffice/UndefinedParagraphFormatException.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.jabref.logic.openoffice; - -/** - * Exception used to indicate that the plugin attempted to set a paragraph format that is not defined in the current OpenOffice document. - */ -public class UndefinedParagraphFormatException extends Exception { - - private final String formatName; - - public UndefinedParagraphFormatException(String formatName) { - super(); - this.formatName = formatName; - } - - public String getFormatName() { - return formatName; - } -} diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index feccb727f53..1cc0ae78f4a 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -25,11 +25,6 @@ import org.jabref.logic.layout.LayoutFormatter; import org.jabref.logic.layout.LayoutFormatterPreferences; import org.jabref.logic.layout.LayoutHelper; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.Author; -import org.jabref.model.entry.AuthorList; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.FieldFactory; import org.jabref.model.entry.field.OrFields; import org.jabref.model.entry.field.StandardField; @@ -44,7 +39,6 @@ import org.jabref.model.openoffice.style.NonUniqueCitationMarker; import org.jabref.model.openoffice.style.PageInfo; import org.jabref.model.openoffice.util.OOListUtil; -import org.jabref.model.strings.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -447,351 +441,6 @@ public Layout getReferenceFormat(EntryType type) { } } - /* begin_old */ - /** - * Format a number-based citation marker for the given number. - * - * @param number The citation numbers. - * @return The text for the citation. - */ - public String getNumCitationMarker(List number, int minGroupingCount, boolean inList) { - String bracketBefore = getStringCitProperty(BRACKET_BEFORE); - if (inList && (citProperties.containsKey(BRACKET_BEFORE_IN_LIST))) { - bracketBefore = getStringCitProperty(BRACKET_BEFORE_IN_LIST); - } - String bracketAfter = getStringCitProperty(BRACKET_AFTER); - if (inList && (citProperties.containsKey(BRACKET_AFTER_IN_LIST))) { - bracketAfter = getStringCitProperty(BRACKET_AFTER_IN_LIST); - } - // Sort the numbers: - List lNum = new ArrayList<>(number); - Collections.sort(lNum); - StringBuilder sb = new StringBuilder(bracketBefore); - int combineFrom = -1; - int written = 0; - for (int i = 0; i < lNum.size(); i++) { - int i1 = lNum.get(i); - if (combineFrom < 0) { - // Check if next entry is the next in the ref list: - if ((i < (lNum.size() - 1)) && (lNum.get(i + 1) == (i1 + 1)) && (i1 > 0)) { - combineFrom = i1; - } else { - // Add single entry: - if (i > 0) { - sb.append(getStringCitProperty(CITATION_SEPARATOR)); - } - sb.append(lNum.get(i) > 0 ? String.valueOf(lNum.get(i)) : OOBibStyle.UNDEFINED_CITATION_MARKER); - written++; - } - } else { - // We are building a list of combined entries. - // Check if it ends here: - if ((i == (lNum.size() - 1)) || (lNum.get(i + 1) != (i1 + 1))) { - if (written > 0) { - sb.append(getStringCitProperty(CITATION_SEPARATOR)); - } - if ((minGroupingCount > 0) && (((i1 + 1) - combineFrom) >= minGroupingCount)) { - sb.append(combineFrom); - sb.append(getStringCitProperty(GROUPED_NUMBERS_SEPARATOR)); - sb.append(i1); - written++; - } else { - // Either we should never group, or there aren't enough - // entries in this case to group. Output all: - for (int jj = combineFrom; jj <= i1; jj++) { - sb.append(jj); - if (jj < i1) { - sb.append(getStringCitProperty(CITATION_SEPARATOR)); - } - written++; - } - } - combineFrom = -1; - } - // If it doesn't end here, just keep iterating. - } - } - sb.append(bracketAfter); - return sb.toString(); - } - /* end_old */ - - /* begin_old */ - public String getCitationMarker(List entries, Map database, boolean inParenthesis, - String[] uniquefiers, int[] unlimAuthors) { - // Look for groups of uniquefied entries that should be combined in the output. - // E.g. (Olsen, 2005a, b) should be output instead of (Olsen, 2005a; Olsen, 2005b). - int piv = -1; - String tmpMarker = null; - if (uniquefiers != null) { - for (int i = 0; i < uniquefiers.length; i++) { - - if ((uniquefiers[i] == null) || uniquefiers[i].isEmpty()) { - // This entry has no uniquefier. - // Check if we just passed a group of more than one entry with uniquefier: - if ((piv > -1) && (i > (piv + 1))) { - // Do the grouping: - group(entries, uniquefiers, piv, i - 1); - } - - piv = -1; - } else { - BibEntry currentEntry = entries.get(i); - if (piv == -1) { - piv = i; - tmpMarker = getAuthorYearParenthesisMarker(Collections.singletonList(currentEntry), database, - null, unlimAuthors); - } else { - // See if this entry can go into a group with the previous one: - String thisMarker = getAuthorYearParenthesisMarker(Collections.singletonList(currentEntry), - database, null, unlimAuthors); - - String authorField = getStringCitProperty(AUTHOR_FIELD); - int maxAuthors = getIntCitProperty(MAX_AUTHORS); - String author = getCitationMarkerField(currentEntry, database.get(currentEntry), - authorField); - AuthorList al = AuthorList.parse(author); - int prevALim = unlimAuthors[i - 1]; // i always at least 1 here - if (!thisMarker.equals(tmpMarker) - || ((al.getNumberOfAuthors() > maxAuthors) && (unlimAuthors[i] != prevALim))) { - // No match. Update piv to exclude the previous entry. But first check if the - // previous entry was part of a group: - if ((piv > -1) && (i > (piv + 1))) { - // Do the grouping: - group(entries, uniquefiers, piv, i - 1); - } - tmpMarker = thisMarker; - piv = i; - } - } - } - - } - // Finished with the loop. See if the last entries form a group: - if (piv >= 0) { - // Do the grouping: - group(entries, uniquefiers, piv, uniquefiers.length - 1); - } - } - - if (inParenthesis) { - return getAuthorYearParenthesisMarker(entries, database, uniquefiers, unlimAuthors); - } else { - return getAuthorYearInTextMarker(entries, database, uniquefiers, unlimAuthors); - } - } - /* end_old */ - - /* begin_old */ - /** - * Modify entry and uniquefier arrays to facilitate a grouped presentation of uniquefied entries. - * - * @param entries The entry array. - * @param uniquefiers The uniquefier array. - * @param from The first index to group (inclusive) - * @param to The last index to group (inclusive) - */ - private void group(List entries, String[] uniquefiers, int from, int to) { - String separator = getStringCitProperty(UNIQUEFIER_SEPARATOR); - StringBuilder sb = new StringBuilder(uniquefiers[from]); - for (int i = from + 1; i <= to; i++) { - sb.append(separator); - sb.append(uniquefiers[i]); - entries.set(i, null); - } - uniquefiers[from] = sb.toString(); - } - /* end_old */ - - /* begin_old */ - /** - * This method produces (Author, year) style citation strings in many different forms. - * - * @param entries The list of BibEntry to get fields from. - * @param database A map of BibEntry-BibDatabase pairs. - * @param uniquifiers Optional parameter to separate similar citations. Elements can be null if not needed. - * @return The formatted citation. - */ - private String getAuthorYearParenthesisMarker(List entries, Map database, - String[] uniquifiers, int[] unlimAuthors) { - - String authorField = getStringCitProperty(AUTHOR_FIELD); // The bibtex field providing author names, e.g. "author" or "editor". - int maxA = getIntCitProperty(MAX_AUTHORS); // The maximum number of authors to write out in full without using etal. Set to - // -1 to always write out all authors. - String yearSep = getStringCitProperty(YEAR_SEPARATOR); // The String to separate authors from year, e.g. "; ". - String startBrace = getStringCitProperty(BRACKET_BEFORE); // The opening parenthesis. - String endBrace = getStringCitProperty(BRACKET_AFTER); // The closing parenthesis. - String citationSeparator = getStringCitProperty(CITATION_SEPARATOR); // The String to separate citations from each other. - String yearField = getStringCitProperty(YEAR_FIELD); // The bibtex field providing the year, e.g. "year". - String andString = getStringCitProperty(AUTHOR_LAST_SEPARATOR); // The String to add between the two last author names, e.g. " & ". - StringBuilder sb = new StringBuilder(startBrace); - for (int j = 0; j < entries.size(); j++) { - BibEntry currentEntry = entries.get(j); - - // Check if this entry has been nulled due to grouping with the previous entry(ies): - if (currentEntry == null) { - continue; - } - - if (j > 0) { - sb.append(citationSeparator); - } - - BibDatabase currentDatabase = database.get(currentEntry); - int unlimA = unlimAuthors == null ? -1 : unlimAuthors[j]; - int maxAuthors = unlimA > 0 ? unlimA : maxA; - - String author = getCitationMarkerField(currentEntry, currentDatabase, authorField); - String authorString = createAuthorList(author, maxAuthors, andString, yearSep); - sb.append(authorString); - String year = getCitationMarkerField(currentEntry, currentDatabase, yearField); - if (year != null) { - sb.append(year); - } - if ((uniquifiers != null) && (uniquifiers[j] != null)) { - sb.append(uniquifiers[j]); - } - } - sb.append(endBrace); - return sb.toString(); - } - /* end_old */ - - /* begin_old */ - /** - * This method produces "Author (year)" style citation strings in many different forms. - * - * @param entries The list of BibEntry to get fields from. - * @param database A map of BibEntry-BibDatabase pairs. - * @param uniquefiers Optional parameters to separate similar citations. Can be null if not needed. - * @return The formatted citation. - */ - private String getAuthorYearInTextMarker(List entries, Map database, - String[] uniquefiers, - int[] unlimAuthors) { - String authorField = getStringCitProperty(AUTHOR_FIELD); // The bibtex field providing author names, e.g. "author" or "editor". - int maxA = getIntCitProperty(MAX_AUTHORS); // The maximum number of authors to write out in full without using etal. Set to - // -1 to always write out all authors. - String yearSep = getStringCitProperty(IN_TEXT_YEAR_SEPARATOR); // The String to separate authors from year, e.g. "; ". - String startBrace = getStringCitProperty(BRACKET_BEFORE); // The opening parenthesis. - String endBrace = getStringCitProperty(BRACKET_AFTER); // The closing parenthesis. - String citationSeparator = getStringCitProperty(CITATION_SEPARATOR); // The String to separate citations from each other. - String yearField = getStringCitProperty(YEAR_FIELD); // The bibtex field providing the year, e.g. "year". - String andString = getStringCitProperty(AUTHOR_LAST_SEPARATOR_IN_TEXT); // The String to add between the two last author names, e.g. " & ". - - if (andString == null) { - // Use the default one if no explicit separator for text is defined - andString = getStringCitProperty(AUTHOR_LAST_SEPARATOR); - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < entries.size(); i++) { - BibEntry currentEntry = entries.get(i); - - // Check if this entry has been nulled due to grouping with the previous entry(ies): - if (currentEntry == null) { - continue; - } - - BibDatabase currentDatabase = database.get(currentEntry); - int unlimA = unlimAuthors == null ? -1 : unlimAuthors[i]; - int maxAuthors = unlimA > 0 ? unlimA : maxA; - - if (i > 0) { - sb.append(citationSeparator); - } - String author = getCitationMarkerField(currentEntry, currentDatabase, authorField); - String authorString = createAuthorList(author, maxAuthors, andString, yearSep); - sb.append(authorString); - sb.append(startBrace); - String year = getCitationMarkerField(currentEntry, currentDatabase, yearField); - if (year != null) { - sb.append(year); - } - if ((uniquefiers != null) && (uniquefiers[i] != null)) { - sb.append(uniquefiers[i]); - } - sb.append(endBrace); - } - return sb.toString(); - - } - /* end_old */ - - /* begin_old */ - /* moved to OOBibStyleGetCitationMarker */ - /** - * This method looks up a field for an entry in a database. Any number of backup fields can be used - * if the primary field is empty. - * - * @param entry The entry. - * @param database The database the entry belongs to. - * @param fields The field, or succession of fields, to look up. If backup fields are needed, separate - * field names by /. E.g. to use "author" with "editor" as backup, specify StandardField.orFields(StandardField.AUTHOR, StandardField.EDITOR). - * @return The resolved field content, or an empty string if the field(s) were empty. - */ - private String getCitationMarkerField(BibEntry entry, BibDatabase database, String fields) { - Objects.requireNonNull(entry, "Entry cannot be null"); - Objects.requireNonNull(database, "database cannot be null"); - - Set authorFields = FieldFactory.parseOrFields(getStringCitProperty(AUTHOR_FIELD)); - for (Field field : FieldFactory.parseOrFields(fields)) { - Optional content = entry.getResolvedFieldOrAlias(field, database); - - if ((content.isPresent()) && !content.get().trim().isEmpty()) { - if (authorFields.contains(field) && StringUtil.isInCurlyBrackets(content.get())) { - return "{" + fieldFormatter.format(content.get()) + "}"; - } - return fieldFormatter.format(content.get()); - } - } - // No luck? Return an empty string: - return ""; - } - /* end_old */ - - /* begin_old */ - /* moved to OOBibStyleGetCitationMarker */ - /** - * Look up the nth author and return the proper last name for citation markers. - * - * @param al The author list. - * @param number The number of the author to return. - * @return The author name, or an empty String if inapplicable. - */ - private String getAuthorLastName(AuthorList al, int number) { - StringBuilder sb = new StringBuilder(); - - if (al.getNumberOfAuthors() > number) { - Author a = al.getAuthor(number); - a.getVon().filter(von -> !von.isEmpty()).ifPresent(von -> sb.append(von).append(' ')); - sb.append(a.getLast().orElse("")); - } - - return sb.toString(); - } - /* end_old */ - - /* begin_old */ - /* to be removed */ - /** - * Take a finished citation and insert a string at the end (but inside the end bracket) - * separated by "PageInfoSeparator" - * - * @param citation - * @param pageInfo - * @return - */ - public String insertPageInfo(String citation, String pageInfo) { - String bracketAfter = getStringCitProperty(BRACKET_AFTER); - if (citation.endsWith(bracketAfter)) { - String first = citation.substring(0, citation.length() - bracketAfter.length()); - return first + getStringCitProperty(PAGE_INFO_SEPARATOR) + pageInfo + bracketAfter; - } else { - return citation + getStringCitProperty(PAGE_INFO_SEPARATOR) + pageInfo; - } - } - /* end_old */ - /** * Convenience method for checking the property for whether we use number citations or * author-year citations. @@ -917,39 +566,6 @@ public int hashCode() { return Objects.hash(path, name, citProperties, properties); } - /* begin_old */ - /* moved to OOBibStyleGetCitationMarker as formatAuthorList */ - private String createAuthorList(String author, int maxAuthors, String andString, - String yearSep) { - Objects.requireNonNull(author); - String etAlString = getStringCitProperty(ET_AL_STRING); // The String to represent authors that are not mentioned, e.g. " et al." - String authorSep = getStringCitProperty(AUTHOR_SEPARATOR); // The String to add between author names except the last two, e.g. ", ". - String oxfordComma = getStringCitProperty(OXFORD_COMMA); // The String to put after the second to last author in case of three or more authors - StringBuilder sb = new StringBuilder(); - AuthorList al = AuthorList.parse(author); - if (!al.isEmpty()) { - sb.append(getAuthorLastName(al, 0)); - } - if ((al.getNumberOfAuthors() > 1) && ((al.getNumberOfAuthors() <= maxAuthors) || (maxAuthors < 0))) { - int j = 1; - while (j < (al.getNumberOfAuthors() - 1)) { - sb.append(authorSep); - sb.append(getAuthorLastName(al, j)); - j++; - } - if (al.getNumberOfAuthors() > 2) { - sb.append(oxfordComma); - } - sb.append(andString); - sb.append(getAuthorLastName(al, al.getNumberOfAuthors() - 1)); - } else if (al.getNumberOfAuthors() > maxAuthors) { - sb.append(etAlString); - } - sb.append(yearSep); - return sb.toString(); - } - /* end_old */ - enum BibStyleMode { NONE, LAYOUT, diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 54f586b7da3..7199b57e0ed 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -1022,7 +1022,6 @@ Problem\ modifying\ citation=Problem modifying citation Problem\ collecting\ citations=Problem collecting citations Citation=Citation Connecting...=Connecting... -Could\ not\ resolve\ BibTeX\ entry\ for\ citation\ marker\ '%0'.=Could not resolve BibTeX entry for citation marker '%0'. Select\ style=Select style Journals=Journals Cite=Cite diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java index 82d7888afd8..33dfffb3431 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java @@ -144,6 +144,22 @@ static String getCitationMarker2(OOBibStyle style, pageInfo); } + static String getCitationMarker2b(OOBibStyle style, + List entries, + Map entryDBMap, + boolean inParenthesis, + String[] uniquefiers, + Boolean[] isFirstAppearanceOfSource, + String[] pageInfo) { + return OOBibStyleTestHelper.getCitationMarker2b(style, + entries, + entryDBMap, + inParenthesis, + uniquefiers, + isFirstAppearanceOfSource, + pageInfo ); + } + /* * end helpers */ @@ -152,35 +168,16 @@ static String getCitationMarker2(OOBibStyle style, void testGetNumCitationMarker() throws IOException { OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, layoutFormatterPreferences); - assertEquals("[1] ", style.getNumCitationMarker(Arrays.asList(1), -1, true)); assertEquals("[1] ", runGetNumCitationMarker2a(style, Arrays.asList(1), -1, true)); - assertEquals("[1]", style.getNumCitationMarker(Arrays.asList(1), -1, false)); assertEquals("[1]", runGetNumCitationMarker2a(style, Arrays.asList(1), -1, false)); assertEquals("[1]", runGetNumCitationMarker2b(style, -1, numEntry("key", 1, null))); - assertEquals("[1] ", style.getNumCitationMarker(Arrays.asList(1), 0, true)); assertEquals("[1] ", runGetNumCitationMarker2a(style, Arrays.asList(1), 0, true)); - /* - * The following tests as for a numeric label for a - * bibliography entry containing more than one numbers. - * We do not need this, not reproduced. - */ - assertEquals("[1-3] ", style.getNumCitationMarker(Arrays.asList(1, 2, 3), 1, true)); - assertEquals("[1; 2; 3] ", style.getNumCitationMarker(Arrays.asList(1, 2, 3), 5, true)); - assertEquals("[1; 2; 3] ", style.getNumCitationMarker(Arrays.asList(1, 2, 3), -1, true)); - assertEquals("[1; 3; 12] ", style.getNumCitationMarker(Arrays.asList(1, 12, 3), 1, true)); - assertEquals("[3-5; 7; 10-12] ", style.getNumCitationMarker(Arrays.asList(12, 7, 3, 4, 11, 10, 5), 1, true)); - - String citation = style.getNumCitationMarker(Arrays.asList(1), -1, false); - assertEquals("[1; pp. 55-56]", style.insertPageInfo(citation, "pp. 55-56")); - CitationMarkerNumericEntry e2 = numEntry("key", 1, "pp. 55-56"); assertEquals(true, e2.getPageInfo().isPresent()); - assertEquals("pp. 55-56", e2.getPageInfo().get().toString()); - citation = runGetNumCitationMarker2b(style, -1, e2); - assertEquals("[1; pp. 55-56]", citation); + assertEquals("pp. 55-56", e2.getPageInfo().get().asString()); OOBibStyleTestHelper.testGetNumCitationMarkerExtra(style); } @@ -189,26 +186,6 @@ void testGetNumCitationMarker() throws IOException { void testGetNumCitationMarkerUndefined() throws IOException { OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, layoutFormatterPreferences); - /* - * Testing bibliography labels with multiple numbers again. - * Not reproduced. - */ - assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "; 2-4] ", - style.getNumCitationMarker(Arrays.asList(4, 2, 3, 0), 1, true)); - - assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "] ", - style.getNumCitationMarker(Arrays.asList(0), 1, true)); - - assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "; 1-3] ", - style.getNumCitationMarker(Arrays.asList(1, 2, 3, 0), 1, true)); - - assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "; " + OOBibStyle.UNDEFINED_CITATION_MARKER + "; " - + OOBibStyle.UNDEFINED_CITATION_MARKER + "] ", - style.getNumCitationMarker(Arrays.asList(0, 0, 0), 1, true)); - - /* - * We have these instead: - */ // unresolved citations look like [??key] assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "]", @@ -292,28 +269,22 @@ void testGetCitationMarker() throws IOException { assertEquals(3, style.getMaxAuthors()); assertEquals(-1, style.getMaxAuthorsFirst()); - assertEquals("[Boström et al., 2006]", - style.getCitationMarker(Collections.singletonList(entry), entryDBMap, true, null, null)); assertEquals("[Boström et al., 2006]", getCitationMarker2(style, Collections.singletonList(entry), entryDBMap, true, null, null, null)); - assertEquals("Boström et al. [2006]", - style.getCitationMarker(Collections.singletonList(entry), entryDBMap, false, null, new int[]{3})); assertEquals("Boström et al. [2006]", getCitationMarker2(style, Collections.singletonList(entry), entryDBMap, false, null, new Boolean[]{false}, null)); - assertEquals("[Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006]", - style.getCitationMarker(Collections.singletonList(entry), entryDBMap, true, null, new int[]{5})); assertEquals("[Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006]", getCitationMarker2(style, Collections.singletonList(entry), entryDBMap, true, null, - new Boolean[]{true} /* corresponds to -1, not 5 */, + new Boolean[]{true}, null)); } @@ -399,7 +370,6 @@ void testInstitutionAuthorMarker() throws IOException { database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); - assertEquals("[JabRef Development Team, 2016]", style.getCitationMarker(entries, entryDBMap, true, null, null)); assertEquals("[JabRef Development Team, 2016]", getCitationMarker2(style, @@ -420,10 +390,11 @@ void testVonAuthorMarker() throws IOException { entry.setField(StandardField.AUTHOR, "Alpha von Beta"); entry.setField(StandardField.TITLE, "JabRef Manual"); entry.setField(StandardField.YEAR, "2016"); + entry.setCitationKey("a1"); database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); - assertEquals("[von Beta, 2016]", style.getCitationMarker(entries, entryDBMap, true, null, null)); + assertEquals("[von Beta, 2016]", getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); } @Test @@ -438,10 +409,11 @@ void testNullAuthorMarker() throws IOException { BibEntry entry = new BibEntry(); entry.setType(StandardEntryType.Article); entry.setField(StandardField.YEAR, "2016"); + entry.setCitationKey("a1"); database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); - assertEquals("[, 2016]", style.getCitationMarker(entries, entryDBMap, true, null, null)); + assertEquals("[, 2016]", getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); } @Test @@ -456,10 +428,11 @@ void testNullYearMarker() throws IOException { BibEntry entry = new BibEntry(); entry.setType(StandardEntryType.Article); entry.setField(StandardField.AUTHOR, "Alpha von Beta"); + entry.setCitationKey("a1"); database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); - assertEquals("[von Beta, ]", style.getCitationMarker(entries, entryDBMap, true, null, null)); + assertEquals("[von Beta, ]", getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); } @Test @@ -473,10 +446,11 @@ void testEmptyEntryMarker() throws IOException { BibEntry entry = new BibEntry(); entry.setType(StandardEntryType.Article); + entry.setCitationKey("a1"); database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); - assertEquals("[, ]", style.getCitationMarker(entries, entryDBMap, true, null, null)); + assertEquals("[, ]", getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); } @Test @@ -492,17 +466,20 @@ void testGetCitationMarkerInParenthesisUniquefiers() throws IOException { entry1.setField(StandardField.AUTHOR, "Alpha Beta"); entry1.setField(StandardField.TITLE, "Paper 1"); entry1.setField(StandardField.YEAR, "2000"); + entry1.setCitationKey("a1"); entries.add(entry1); database.insertEntry(entry1); BibEntry entry3 = new BibEntry(); entry3.setField(StandardField.AUTHOR, "Alpha Beta"); entry3.setField(StandardField.TITLE, "Paper 2"); entry3.setField(StandardField.YEAR, "2000"); + entry3.setCitationKey("a3"); entries.add(entry3); database.insertEntry(entry3); BibEntry entry2 = new BibEntry(); entry2.setField(StandardField.AUTHOR, "Gamma Epsilon"); entry2.setField(StandardField.YEAR, "2001"); + entry2.setCitationKey("a2"); entries.add(entry2); database.insertEntry(entry2); for (BibEntry entry : database.getEntries()) { @@ -510,9 +487,12 @@ void testGetCitationMarkerInParenthesisUniquefiers() throws IOException { } assertEquals("[Beta, 2000; Beta, 2000; Epsilon, 2001]", - style.getCitationMarker(entries, entryDBMap, true, null, null)); + getCitationMarker2b(style, entries, entryDBMap, true, null, null, null)); assertEquals("[Beta, 2000a,b; Epsilon, 2001]", - style.getCitationMarker(entries, entryDBMap, true, new String[]{"a", "b", ""}, new int[]{1, 1, 1})); + getCitationMarker2(style, entries, entryDBMap, true, + new String[]{"a", "b", ""}, + new Boolean[]{false, false, false}, + null)); } @Test @@ -528,27 +508,33 @@ void testGetCitationMarkerInTextUniquefiers() throws IOException { entry1.setField(StandardField.AUTHOR, "Alpha Beta"); entry1.setField(StandardField.TITLE, "Paper 1"); entry1.setField(StandardField.YEAR, "2000"); + entry1.setCitationKey("a1"); entries.add(entry1); database.insertEntry(entry1); BibEntry entry3 = new BibEntry(); entry3.setField(StandardField.AUTHOR, "Alpha Beta"); entry3.setField(StandardField.TITLE, "Paper 2"); entry3.setField(StandardField.YEAR, "2000"); + entry3.setCitationKey("a3"); entries.add(entry3); database.insertEntry(entry3); BibEntry entry2 = new BibEntry(); entry2.setField(StandardField.AUTHOR, "Gamma Epsilon"); entry2.setField(StandardField.YEAR, "2001"); entries.add(entry2); + entry2.setCitationKey("a2"); database.insertEntry(entry2); for (BibEntry entry : database.getEntries()) { entryDBMap.put(entry, database); } assertEquals("Beta [2000]; Beta [2000]; Epsilon [2001]", - style.getCitationMarker(entries, entryDBMap, false, null, null)); + getCitationMarker2b(style, entries, entryDBMap, false, null, null, null)); assertEquals("Beta [2000a,b]; Epsilon [2001]", - style.getCitationMarker(entries, entryDBMap, false, new String[]{"a", "b", ""}, new int[]{1, 1, 1})); + getCitationMarker2(style, entries, entryDBMap, false, + new String[]{"a", "b", ""}, + new Boolean[]{false, false, false}, + null)); } @Test @@ -564,18 +550,21 @@ void testGetCitationMarkerInParenthesisUniquefiersThreeSameAuthor() throws IOExc entry1.setField(StandardField.AUTHOR, "Alpha Beta"); entry1.setField(StandardField.TITLE, "Paper 1"); entry1.setField(StandardField.YEAR, "2000"); + entry1.setCitationKey("a1"); entries.add(entry1); database.insertEntry(entry1); BibEntry entry2 = new BibEntry(); entry2.setField(StandardField.AUTHOR, "Alpha Beta"); entry2.setField(StandardField.TITLE, "Paper 2"); entry2.setField(StandardField.YEAR, "2000"); + entry2.setCitationKey("a2"); entries.add(entry2); database.insertEntry(entry2); BibEntry entry3 = new BibEntry(); entry3.setField(StandardField.AUTHOR, "Alpha Beta"); entry3.setField(StandardField.TITLE, "Paper 3"); entry3.setField(StandardField.YEAR, "2000"); + entry3.setCitationKey("a3"); entries.add(entry3); database.insertEntry(entry3); for (BibEntry entry : database.getEntries()) { @@ -583,7 +572,10 @@ void testGetCitationMarkerInParenthesisUniquefiersThreeSameAuthor() throws IOExc } assertEquals("[Beta, 2000a,b,c]", - style.getCitationMarker(entries, entryDBMap, true, new String[]{"a", "b", "c"}, new int[]{1, 1, 1})); + getCitationMarker2(style, entries, entryDBMap, true, + new String[]{"a", "b", "c"}, + new Boolean[]{false, false, false}, + null)); } @Test @@ -599,18 +591,21 @@ void testGetCitationMarkerInTextUniquefiersThreeSameAuthor() throws IOException entry1.setField(StandardField.AUTHOR, "Alpha Beta"); entry1.setField(StandardField.TITLE, "Paper 1"); entry1.setField(StandardField.YEAR, "2000"); + entry1.setCitationKey("a1"); entries.add(entry1); database.insertEntry(entry1); BibEntry entry2 = new BibEntry(); entry2.setField(StandardField.AUTHOR, "Alpha Beta"); entry2.setField(StandardField.TITLE, "Paper 2"); entry2.setField(StandardField.YEAR, "2000"); + entry2.setCitationKey("a2"); entries.add(entry2); database.insertEntry(entry2); BibEntry entry3 = new BibEntry(); entry3.setField(StandardField.AUTHOR, "Alpha Beta"); entry3.setField(StandardField.TITLE, "Paper 3"); entry3.setField(StandardField.YEAR, "2000"); + entry3.setCitationKey("a3"); entries.add(entry3); database.insertEntry(entry3); for (BibEntry entry : database.getEntries()) { @@ -618,7 +613,10 @@ void testGetCitationMarkerInTextUniquefiersThreeSameAuthor() throws IOException } assertEquals("Beta [2000a,b,c]", - style.getCitationMarker(entries, entryDBMap, false, new String[]{"a", "b", "c"}, new int[]{1, 1, 1})); + getCitationMarker2(style, entries, entryDBMap, false, + new String[]{"a", "b", "c"}, + new Boolean[]{false, false, false}, + null)); } @Test @@ -672,11 +670,12 @@ void testEmptyStringPropertyAndOxfordComma() throws Exception { entry.setField(StandardField.AUTHOR, "Alpha von Beta and Gamma Epsilon and Ypsilon Tau"); entry.setField(StandardField.TITLE, "JabRef Manual"); entry.setField(StandardField.YEAR, "2016"); + entry.setCitationKey("a1"); database.insertEntry(entry); entries.add(entry); entryDBMap.put(entry, database); assertEquals("von Beta, Epsilon, & Tau, 2016", - style.getCitationMarker(entries, entryDBMap, true, null, null)); + getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); } @Test diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java index ae5e83abd2f..4123a5be1fc 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java @@ -163,13 +163,14 @@ static CitationMarkerEntry makeCitationMarkerEntry(BibEntry entry, * Similar to old API. pageInfo is new, and unlimAuthors is * replaced with isFirstAppearanceOfSource */ - static String getCitationMarker2(OOBibStyle style, - List entries, - Map entryDBMap, - boolean inParenthesis, - String[] uniquefiers, - Boolean[] isFirstAppearanceOfSource, - String[] pageInfo) { + static String getCitationMarker2ab(OOBibStyle style, + List entries, + Map entryDBMap, + boolean inParenthesis, + String[] uniquefiers, + Boolean[] isFirstAppearanceOfSource, + String[] pageInfo, + NonUniqueCitationMarker nonunique) { if (uniquefiers == null) { uniquefiers = new String[entries.size()]; Arrays.fill(uniquefiers, null); @@ -194,7 +195,41 @@ static String getCitationMarker2(OOBibStyle style, } return style.createCitationMarker(citationMarkerEntries, inParenthesis, - NonUniqueCitationMarker.THROWS).toString(); + nonunique).asString(); + } + + static String getCitationMarker2(OOBibStyle style, + List entries, + Map entryDBMap, + boolean inParenthesis, + String[] uniquefiers, + Boolean[] isFirstAppearanceOfSource, + String[] pageInfo) { + return getCitationMarker2ab(style, + entries, + entryDBMap, + inParenthesis, + uniquefiers, + isFirstAppearanceOfSource, + pageInfo, + NonUniqueCitationMarker.THROWS); + } + + static String getCitationMarker2b(OOBibStyle style, + List entries, + Map entryDBMap, + boolean inParenthesis, + String[] uniquefiers, + Boolean[] isFirstAppearanceOfSource, + String[] pageInfo) { + return getCitationMarker2ab(style, + entries, + entryDBMap, + inParenthesis, + uniquefiers, + isFirstAppearanceOfSource, + pageInfo, + NonUniqueCitationMarker.FORGIVEN); } /* From 361d3efe518f517f8efa6283ffb6e06b7ae682c7 Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 13:39:46 +0200 Subject: [PATCH 037/103] cleanup --- .../logic/openoffice/style/OOBibStyleTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java index 33dfffb3431..e79ad393fd0 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java @@ -160,6 +160,22 @@ static String getCitationMarker2b(OOBibStyle style, pageInfo ); } + static String getCitationMarker2b(OOBibStyle style, + List entries, + Map entryDBMap, + boolean inParenthesis, + String[] uniquefiers, + Boolean[] isFirstAppearanceOfSource, + String[] pageInfo) { + return OOBibStyleTestHelper.getCitationMarker2b(style, + entries, + entryDBMap, + inParenthesis, + uniquefiers, + isFirstAppearanceOfSource, + pageInfo ); + } + /* * end helpers */ From 614b7f72bbdfc50c02cdda4ba450c9aa4621ba98 Mon Sep 17 00:00:00 2001 From: Antal K Date: Thu, 3 Jun 2021 16:14:14 +0200 Subject: [PATCH 038/103] remove duplicate --- .../logic/openoffice/style/OOBibStyleTest.java | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java index e79ad393fd0..f4140cbbbe8 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java @@ -157,23 +157,7 @@ static String getCitationMarker2b(OOBibStyle style, inParenthesis, uniquefiers, isFirstAppearanceOfSource, - pageInfo ); - } - - static String getCitationMarker2b(OOBibStyle style, - List entries, - Map entryDBMap, - boolean inParenthesis, - String[] uniquefiers, - Boolean[] isFirstAppearanceOfSource, - String[] pageInfo) { - return OOBibStyleTestHelper.getCitationMarker2b(style, - entries, - entryDBMap, - inParenthesis, - uniquefiers, - isFirstAppearanceOfSource, - pageInfo ); + pageInfo); } /* From 292f351ff7d14846e3d98d640161f35eb058bd49 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sat, 19 Jun 2021 15:45:50 +0200 Subject: [PATCH 039/103] toString --- .../java/org/jabref/logic/openoffice/style/OOBibStyleTest.java | 2 +- .../org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java index f4140cbbbe8..a6088ef3a63 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java @@ -177,7 +177,7 @@ void testGetNumCitationMarker() throws IOException { CitationMarkerNumericEntry e2 = numEntry("key", 1, "pp. 55-56"); assertEquals(true, e2.getPageInfo().isPresent()); - assertEquals("pp. 55-56", e2.getPageInfo().get().asString()); + assertEquals("pp. 55-56", e2.getPageInfo().get().toString()); OOBibStyleTestHelper.testGetNumCitationMarkerExtra(style); } diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java index 4123a5be1fc..8a6b4585d19 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java @@ -195,7 +195,7 @@ static String getCitationMarker2ab(OOBibStyle style, } return style.createCitationMarker(citationMarkerEntries, inParenthesis, - nonunique).asString(); + nonunique).toString(); } static String getCitationMarker2(OOBibStyle style, From 956992ef546765b69124aa5b3fe991e4fea85e18 Mon Sep 17 00:00:00 2001 From: Antal K Date: Wed, 30 Jun 2021 00:11:25 +0200 Subject: [PATCH 040/103] add docs/openoffice --- docs/SUMMARY.md | 8 +- docs/openoffice/README.md | 1 + docs/openoffice/code-reorganization.md | 188 +++++ docs/openoffice/layers-v1.svg | 915 +++++++++++++++++++++++ docs/openoffice/ooresult-alternatives.md | 503 +++++++++++++ docs/openoffice/ooresult-ooerror.md | 232 ++++++ docs/openoffice/order-of-appearance.md | 118 +++ docs/openoffice/overview.md | 302 ++++++++ docs/openoffice/problems.md | 99 +++ 9 files changed, 2365 insertions(+), 1 deletion(-) create mode 100644 docs/openoffice/README.md create mode 100644 docs/openoffice/code-reorganization.md create mode 100644 docs/openoffice/layers-v1.svg create mode 100644 docs/openoffice/ooresult-alternatives.md create mode 100644 docs/openoffice/ooresult-ooerror.md create mode 100644 docs/openoffice/order-of-appearance.md create mode 100644 docs/openoffice/overview.md create mode 100644 docs/openoffice/problems.md diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index f66102da3a8..f1e8d4a7013 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -19,4 +19,10 @@ * [Readings on Coding](readings-on-coding/README.md) * [Readings on JavaFX](readings-on-coding/javafx.md) * [Useful development tooling](readings-on-coding/tools.md) - +* [The OpenOffice/LibreOffice panel](openoffice/README.md) + * [Overview](openoffice/overview.md) + * [Order of appearance of citation groups](openoffice/order-of-appearance.md) + * [Problems](openoffice/problems.md) + * [Code reorganization](openoffice/code-reorganization.md) + * [About `OOError`, `OOResult` and `OOVoidResult`](openoffice/ooresult-ooerror.md) + * [Alternatives to using OOResult and OOVoidResult in OOBibBase](openoffice/ooresult-alternatives.md) diff --git a/docs/openoffice/README.md b/docs/openoffice/README.md new file mode 100644 index 00000000000..5587cc8291e --- /dev/null +++ b/docs/openoffice/README.md @@ -0,0 +1 @@ +# OpenOffice/LibreOffice integration diff --git a/docs/openoffice/code-reorganization.md b/docs/openoffice/code-reorganization.md new file mode 100644 index 00000000000..b91aa53984c --- /dev/null +++ b/docs/openoffice/code-reorganization.md @@ -0,0 +1,188 @@ + +# Code reorganization + +Why + +- Separate backend +- Separate GUI code (dialogs) and logic +- Data is now organized around `Citation`, `CitationGroup` instead of arrays for citation group + fields, and arrays of arrays for citation fields. + Also take `citationKey` as the central data unit, this is what we start with: unresolved `citationKeys` + do not stop processing. Although we cannot sort them by author and year, we can still emit a marker + that acts as a placeholder and shows the user the problematic key. + +## Result + +### Layers + +![Layers](layers-v1.svg) + +### By directories + +- `model` + - `util` : general utilities + - (`OOPair`, `OOTuple3`) collect two or three objects without creating a new class + - `OOResult` : while an Optional.empty can comunicate failure, it cannot provide details. + `OOResult` allows an arbitrary error object to be provided in case of failure. + - `OOVoidResult` : for functions returning no result on success, only diagnostics on failure. + - `OOListUtil`: some utilities working on List + - `uno` : helpers for various tasks via UNO. + These are conceptually independent of JabRef code and logic. + - `ootext` : to separate decisions on the format of references and citation marks from + the actual insertion into the document, the earlier method + [OOUtil.insertOOFormattedTextAtCurrentLocation](https://github.com/JabRef/jabref/blob/475b2989ffa8ec61c3327c62ed8f694149f83220/src/main/java/org/jabref/logic/openoffice/OOUtil.java#L112) + was extended to handle new tags that describe actions earlier done in code. + - This became [OOTextIntoOO.write](https://github.com/antalk2/jabref/blob/122d5133fa6c7b44245c5ba5600d398775718664/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java#L149) + - `(change)` Now all output to the document goes through this, not only those from Layout. This allows the citation markers and `jstyle:Title` to use these tags. + - This allows some backward-compatible extensions to jstyle. + `(change)` [Added](https://github.com/antalk2/jabref/blob/122d5133fa6c7b44245c5ba5600d398775718664/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java#L92) + some extra keywords, in `{prefix}_MARKUP_BEFORE`, `{prefix}_MARKUP_AFTER` pairs to allow bracketing some parts of citation marks with text and/or open/close tag pairs. + - [OOFormat](https://github.com/antalk2/jabref/blob/improve-reversibility-rebased-03/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java) + contains helpers to create the appropriate tags + - [OOText](https://github.com/antalk2/jabref/blob/improve-reversibility-rebased-03/src/main/java/org/jabref/model/openoffice/ootext/OOText.java) formalizes + the distinction from `String`. I did not change `String` to `OOText` in old code, (in particular in OOStyle). + - `rangesort` : ordering objects that have an `XTextRange`, optionally with an extra integer to break ties. + - `RangeSort.partitionAndSortRanges` : since `XTextRangeCompare` can only compare `XTextRange` values in + the same `XText`, we partition them accordingly and only sort within each partiion. + - `RangeSortable` (interface), `RangeSortEntry` (implements) : + When we replace `XTextRange` of citation marks in footnotes with the range of the footnote mark, + multiple citation marks may be mapped to the same location. To preserve the order between these, + `RangeSortable` allows this order to be indicated by returning appropriate indices from `getIndexInPosition` + - `RangeSortVisual` : sort in top-to-bottom left-to-right order. + Needs a functional `XTextViewCursor`. + Works on `RangeSortable` values. + - `FunctionalTextViewCursor` : helper to get a functional `XTextViewCursor` (cannot always) + - `RangeOverlapWithin` : check for overlaps within a set of `XTextRange` values. Probably O(n*log(n)). Used for all-to-all check of protected ranges. + - `RangeOverlapBetween` : check for overlaps between two sets of `XTextRange` values. Assumes one set is small. O(n*k). + Used for checking if the cursor is in a protected range. + - `backend` : interfaces to be provided by backends. + May change as new backends may need different APIs. + - `style` : data structures and interfaces used while going from ordered list of citation groups + to formatted citation markers and bibliography. Does not communicate with the document. Too long to fit here, starting a new section. + +## model/style + +At the core, + +- we have `Citation` values + - represented in the document by their `citationKey` + - each may have a `pageInfo` +- A citation group (`CitationGroup`) has + - a list of citations (`citationsInStorageOrder`) + - an identifier `CitationGroupId cgid` + - this allows to refer to the group + - also used to associate the group to its citation markers location (outside the style part, + in [Backend](https://github.com/antalk2/jabref/blob/fed0952cbdaf7a76bcb09b3db5ac48f34f5ca388/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java#L46)) + - `OODataModel dataModel` is here, in order to handle old (Jabref5.2) structure where pageInfo belonged to + CitationGroup not Citation + - `referenceMarkNameForLinking` is optional: can be used to crosslink to the citation marker + from the bibliography. +- `CitationGroups` represents the collection of citation groups. +Processing starts with creating a `CitationGroups` instance from the data stored in the document. + +- `CitedKey` represents a cited source, with ordered backreferences (using `CitationPath`) to the correponding +citations. + +- `CitedKeys` is just an order-preserving collection of `CitedKeys` that also supports lookup by +`citationKey`. While producing citation markers, we also create a corresponding `CitedKeys` +instance, and store it in `CitationGroups.bibliography`. This is already sorted, its entries have +`uniqueLetter` or `number` assigned, but not converted to markup yet. + +Common processing steps: + +- We need `globalOrder` for the citation groups (provided externally) +`CitationGroups.setGlobalOrder()` +- We need to look up each citationKey in the bibliography databases: + - `CitationGroups.lookupCitations` collects the cited keys, + looks up each, then distributes the results to the citations. + Uses a temporary `CitedKeys` instance, based on unsorted citations and citation groups. +- `CitationGroups.imposeLocalOrder` fills `localOrder` in each `CitationGroup` + +- Now we have order of appearance for the citations (`globalOrder` and `localOrder`). + We can create a `CitedKeys` instance (`bibliography`) according to this order. + +- For citations numbered in order of first appearance we number the sources and distribute the numbers +to the corresponding citations. +- For citations numbered in order of bibliography, we sort the bibliography, number, distribute. + +- For author-year citations we have to decide on the letters `uniqueLetter` used to distinguish +sources. This needs order of first appearance of the sources and recognizing clashing citation markers. +This is done in logic, in [`OOProcessAuthorYearMarkers.createUniqueLetters()`](https://github.com/antalk2/jabref/blob/122d5133fa6c7b44245c5ba5600d398775718664/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java#L49) +- We also mark first appearance of each source ([`setIsFirstAppearanceOfSourceInCitations`](https://github.com/antalk2/jabref/blob/fed0952cbdaf7a76bcb09b3db5ac48f34f5ca388/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java#L146)) + +The entry point for this processing is: [`OOProcess.produceCitationMarkers`](https://github.com/antalk2/jabref/blob/fed0952cbdaf7a76bcb09b3db5ac48f34f5ca388/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java#L69). +It fills +- each `CitationGroup.citationMarker` +- `CitationGroups.bibliography` + - From bibliography `OOFormatBibliography.formatBibliography()` creates an `OOText` + ready to be written to the document. + + +## logic/style + +- `StyleLoader` : not changed (knows about default styles) Used by GUI +- `OOPreFormatter` : LaTeX code to unicode and OOText tags. (not changed) +- `OOBibStyle` : is mostly concerned by loading/parsing jstyle files and presenting its pieces +to the rest. Originally it also contains code to format numeric and author-year citation markers. + - Details of their new implementations are in + [`OOBibStyleGetNumCitationMarker`](https://github.com/antalk2/jabref/blob/improve-reversibility-rebased-03/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java) and + [`OOBibStyleGetCitationMarker`](https://github.com/antalk2/jabref/blob/improve-reversibility-rebased-03/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java) + - The new implementations + - support pageInfo for each citation + - support unresolved citations + - instead of `List` and (`List` plus arrays and database) they expect + more self-contained entries `List`, `List`. + - We have distinct methods for `getNormalizedCitationMarker(CitationMarkerNormEntry)` and + `getNumCitationMarkerForBibliography(CitationMarkerNumericBibEntry)`. + - The corresponding interfaces in model/style: + - `CitationMarkerNumericEntry` + - `CitationMarkerEntry` + - `CitationMarkerNumericBibEntry` + - `CitationMarkerNormEntry` + describe their expected input entries. +- [`OOProcess.produceCitationMarkers`](https://github.com/antalk2/jabref/blob/fed0952cbdaf7a76bcb09b3db5ac48f34f5ca388/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java#L69) +is the main entry point for style application. Calls to specific implementations +in `OOProcessCitationKeyMarkers`, `OOProcessNumericMarkers` and `OOProcessAuthorYearMarkers` +according to jstyle flags. + +## logic/backend + +Details of encoding and retrieving data stored in a document as well as +the citation maker locations. Also contains dataModel-dependent code +(which could probably be moved out once the datamodel is settled). + +Creating and finding the bibliography (providing a cursor to write at) should be here too. +These are currently in `UpdateBibliography` + +## logic/frontend + +- `OOFrontend` : has a `Backend` and `CitationGroups` + - Its constructor creates a backend, reads data from the document and creates a CitationGroups instance. + - provides functionality that requires both access to the document and the CitationGroups instance +- `RangeForOverlapCheck` used in `OOFrontend` +- `UpdateBibliography` : Create, find and update the bibliography in the document using output from + `produceCitationMarkers()` +- `UpdateCitationMarkers` create `CitationGroup`, update citation markers using output from + `produceCitationMarkers()` + + +## logic/action + +GUI-independent part of implementations of GUI actions. + +## gui + +- `OOError` : common error messages and dialog titles + - adds `title` to `Jabrefexception` + - converts from some common exception types using type-specific message + - contains some dialog messages that do not correspond to exceptions + +- `OOBibBase2` : most activity was moved out from here to parts discussed above. + - connecting / selecting a document moved to `OOBibBaseConnect` + - the rest connects higher parts of the GUI to actions in logic + - does argument and precondition checking + - catches all exceptions + - shows error and warning dialogs + - adds `enterUndoContext`, `leaveUndoContext` around action code + + diff --git a/docs/openoffice/layers-v1.svg b/docs/openoffice/layers-v1.svg new file mode 100644 index 00000000000..f9b8239d504 --- /dev/null +++ b/docs/openoffice/layers-v1.svg @@ -0,0 +1,915 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + document content (UNO) + + frontend + + actions + + OOBibBase2 + + backend + + style + + OOTextIntoOO + + rangesort + data in doc, ranges + order ranges + fill ranges + markup text + XTextDocument + Backend, CitationGroups + + + + GUI: + BibEntry, BibDatabase, OOBibStyle + provides input in terms of these types + + provides connection to doc + Cite, Update, Merge, Separate, Manage, Export + Connect + Load Style + Create OOFrontend instance + Catch exceptions, Undo + Forward requests to actions + Check preconditions + + locations + citation keys + pageInfo + citation type + + + lookup, localOrder, number, + uniqueLetter, sort bibliography, + format citationMarkers, + format bibliography + + + or visually + within XText + + checkRangeOverlaps, checkRangeOverlapsWithCursor + connects the parts below + getVisuallySortedCitationGroups, imposeGlobalOrder + UpdateCitationMarkers, UpdateBibliography + lock screen refresh + GUI-independent part of actions + + + diff --git a/docs/openoffice/ooresult-alternatives.md b/docs/openoffice/ooresult-alternatives.md new file mode 100644 index 00000000000..83f8ca67232 --- /dev/null +++ b/docs/openoffice/ooresult-alternatives.md @@ -0,0 +1,503 @@ + +# Alternatives to `OOResult` during precondition checking in `OOBibBase` + +(Talk about ADRs prompted me to think about alternatives to what I used.) + +Situation: + +- some tests return no data, only report problems +- we may need to get some resources that might not be available + (for example: connection to a document, a functional textview cursor) +- some test depend on these resources + + +One strategy could be to use a single try-catch around the whole body, +then showing a message based on the type of exceptions thrown. + +**[base case]** +```java +try { + A a = f(); + B b = g(a); + realAction(a,b); +} catch (FirstExceptionType ex) { + showDialog( title, messageForFirstExceptionType(ex) ); +} catch (SecondExceptionType ex) { + showDialog( title, messageForSecondExceptionType(ex) ); +} catch (Exception ex) { + showDialog( title, messageForOtherExceptions(ex) ); +} +``` + +This our base case. + +It is not clear from the code, nor within the catch branches (unless +we start looking into stack traces) which call (`f()`, `g(a)` or +`realAction(a,b)`) resulted in the exception. This limits the +specificity of the message and makes it hard to think about the "why" +can we get this exception here? + +## Catch around each call? + +A more detailed strategy would be to try-catch around each call. +In case we need a result from the call, this means either increasingly indented +code (try-in-try). + +```java +try { + A a = f(); + try { + B b = g(a); + try { + realAction(ab); + } catch (...){ + showDialog(); + } + } catch (G ex) { + showDialog(title, ex); // title describes which GUI action we are in + } +} catch (F ex) { + // could an F be thrown in g? + showDialog( title, ex ); +} +``` + +or (declare and fill later) + +```java +A a = null; +try { + a = f(); +} catch (F ex) { + showDialog(title, ex); + return; +} +B b = null; +try { + b = g(a); +} catch (G ex) { + showDialog(title, ex); + return; +} +try { + realAction(ab); +} catch (...){ + showDialog(); +} +``` + +In either case, the code becomes littered with exception handling code. + +## Catch in wrappers? + +We might push the try-catch into its own function. +If the wrapper is called multiple times, this may reduce duplication of the +catch-and-assign-message part. + +We can show an error dialog here: `title` carries some information +from the caller, the exeption caught brings some from below. + +We still need to notify the action handler (the caller) about +failure. Since we have shown the dialog, we do not need to provide a +message. + +### Notify caller with `Optional` result. + +With `Optional` we get something like this: + +**[dialog in wrap, return Optional]** + +```java +Optional wrap_f(String title) { + try { + return Optional.of(f()); + } catch (F ex) { + showDialog(title, ex); + return Optional.empty(); + } +} + +Optional wrap_g(String title, A a) { + try { + return Optional.of(g(a)); + } catch (G ex) { + showDialog(title, ex); + return Optional.empty(); + } +} +``` + +and use it like this: + +```java +Optional a = wrap_f(title); +if (a.isEmpty()) { return; } + +Optional b = wrap_g(title, a.get()); +if (b.isEmpty()) { return; } + +try { + realAction(a.get(), b.get()); +} catch (...) { +} +``` + +This looks fairly regular. + +If `g` did not need `a`, we could simplify to + +```java +Optional a = wrap_f(title); +Optional b = wrap_g(title); +if (a.isEmpty() || b.isEmpty()) { return; } + +try { + realAction(a.get(), b.get()); +} catch (...) { +} +``` + +### Notify caller with `Result` result. + +With `Result` we get something like this: + +**[dialog in wrap, return OOResult]** + +```java +OOResult wrap_f() { + try { + return OOResult.ok(f()); + } catch (F ex) { + return OOResult.error(OOError.from(ex)); + } catch (F2 ex) { + String message = "..."; + return OOResult.error(new OOError(message, ex)); // [1] + } +} +// [1] : this OOError constructor (explicit message but no title) is missing + +Optional wrap_g(A a) { + try { + return OOResult.ok(g(a)); + } catch (G ex) { + return OOResult.error(OOError.from(ex)); + } +} +``` + +and use it like this: + +```java +OOResult a = wrap_f(); +if (testDialog(title, a)) { // [1] + return; +} + +// [1] needs boolean testDialog(String title, OOResultLike... a); +// where OOResultLike is an interface with `OOVoidResult asVoidResult()` +// and is implemented by OOResult and OOVoidResult + +OOResult b = wrap_g(a.get()); +if (testDialog(title, b)) { return; } // (checkstyle makes this 3 lines) + +try { + realAction(a.get(), b.get()); +} catch (...) { +} +``` + +If `g` did not need `a`, we could simplify to + +```java +Optional a = wrap_f(); +Optional b = wrap_g(); +if (testDialog(title, a, b)) { // a single dialog can show both messages + return; +} + +try { + realAction(a.get(), b.get()); +} catch (...) { +} +``` + + + +### Notify caller by throwing an exception + +Or we can throw an exception to notify the caller. + +To simplify code in the caller, I assume we are using an exception +type not used elsewhere, but shared by all precondition checks. + +**[dialog in wrap, PreconditionException]** + +```java +A wrap_f(String title) throws PreconditionException { + try { + return f(); + } catch (F ex) { + showDialog(title, ex) + throw new PreconditionException(); + } +} + +B wrap_g(String title, A a) throws PreconditionException { + try { + return g(a); + } catch (G ex) { + showDialog(title, ex); + throw new PreconditionException(); + } +} +``` + +use + +```java +try { + A a = wrap_f(title); + B b = wrap_g(title, a); + try { + realAction(a, b); + } catch (...) { + showDialog(...) + } +} catch( PreconditionException ) { + // Only precondition checks get us here. + return; +} +``` + +or (since PreconditionException is not thrown from realAction) + +```java +try { + A a = wrap_f(title); + B b = wrap_g(title, a); + realAction(a, b); +} catch (...) { + // Only realAction gets us here + showDialog(...) +} catch( PreconditionException ) { + // Only precondition checks get us here. + return; +} +``` + +or (separate try-catch for preconditions and realAction) + +```java +A a = null; +B b = null; +try { + a = wrap_f(title); + b = wrap_g(title, a); +} catch( PreconditionException ) { + return; +} +try { + realAction(a, b); +} catch (...) { +} +``` + +or to reduce passing around the title part: + +**[PreconditionException, dialog in catch]** + +```java +A wrap_f() throws PreconditionException { + try { + return f(); + } catch (F ex) { + throw new PreconditionException(message, ex); + } +} + +B wrap_g(A a) throws PreconditionException { + try { + return g(a); + } catch (G ex) { + throw new PreconditionException(message, ex); + } +} +``` + +use + +```java +try { + A a = wrap_f(); + B b = wrap_g(a); + try { + realAction(a, b); + } catch (...) { + showDialog(...); + } +} catch(PreconditionException ex) { + showDialog(title, ex.message ); + return; +} +``` + +or + +``` +try { + A a = wrap_f(); + B b = wrap_g(a); + realAction(a, b); +} catch (...) { + showDialog(...); +} catch(PreconditionException ex) { + showDialog(title, ex.message ); + return; +} +``` + + +## Push associating the message further down + +As [the developers guide](https://jabref.readthedocs.io/en/latest/getting-into-the-code/code-howtos/#throwing-and-catching-exceptions) +suggest, we could "Catch and wrap all API exceptions" and rethrow them +as a `JabRefException` or some exception derived from it. In this case the try-catch part goes even further down, and +in principle we could just + +```java +try { + A a = f(); + B b = g(a); + realAction(a, b); +} catch(JabRefException ex) { + showDialog(title, ex.message ); + return; +} +``` + +Constraints: + +- conversion to `JabRefException` cannot be done in `model` (since JabRefException is in `logic`) +- `JabRefException` expects a localized message. Or we need to remember +which `JabRefException` instances are localized and which need to be caught +for localizing the message. +- At the bottom we usually have very little information on higher level +contexts: at a failure like `NoSuchProperty` we cannot tell which set +of properties did we look in and why. +For messages originating too deeply, we might want to override or extend the message anyway. +- for each exeption we might want to handle programmatically, we need a variant based +on `JabRefException` + +So we might end up: + +```java +try { + A a = f(); + B b = g(a); + realAction(a, b); +} catch(FDerivedFromJabRefException ex) { + showDialog(title, messageForF ); +} catch(GDerivedFromJabRefException ex) { + showDialog(title, messageForG ); +} catch(JabRefException ex) { + showDialog(title, ex.message ); +} catch(Exception ex) { // [1] + showDialog(title, ex.message, ex ); + // [1] does "never catch Exception or Throwable" apply at this point? + // Probably should not: we are promising not to throw. +} +``` + +which looks very similar to the original version. + +This again loses the information: can `GDerivedFromJabRefException` +come from `realAction` or `f` or not? This is because we have pushed +down the last catch/throw indefinitely (eliminating `wrap_f`) into a +depth, where we cannot necessarily assign an appropriate message. + +To a lesser extent this also happens in `wrap_f`: it only knows about +the action that called it what we provide (`title` or nothing). It knows +the precondition it checks: probably an optimal location to assign a message. + +**Summary**: going from top to bottom, we move to increasingly more local context, +our knowledge shifts towards the "in which part of the code did we have a problem" +and away from the high level ("which action"). + +One natural point to meet information from these to levels +is the top level of action handlers. For precondition checking code +a wrapper around code elsewhere may be considered. +Using such wrappers may reduce duplication if called in multiple actions. + +We still have to signal failure to the action handler: the options considered +above were using an `Optional` and throwing an exception with the appropriate message. + +The more promising variants were + +- **[dialog in wrap, return Optional]** + `Optional wrap_f(String title)` (showDialog inside) + - pro: explicit return in caller + - con: explicit return in caller (boilerplate) + - con: passing in the title is repeated + - would be 'pro' if we wanted title to vary within an action + +- **[PreconditionException, dialog in catch]** + `A wrap_f() throws PreconditionException` + (with `showDialog` under `catch(PreconditionException ex)`) + - con: hidden control flow + - pro: no repeated `if(){return}` boilerplate + - pro: title used only once + +**[using OOResult]** +```java +final String title = "Could not insert citation"; + +OOResult odoc = getXTextDocument(); +if (testDialog(title, + odoc, + styleIsRequired(style), + selectedBibEntryIsRequired(entries, OOError::noEntriesSelectedForCitation))) { + return; +} +XTextDocument doc = odoc.get(); + +OOResult ofr = getFrontend(doc); +if (testDialog(title, ofr)) { + return; +} +OOFrontend fr = ofr.get(); + +OOResult cursor = getUserCursorForTextInsertion(doc); +if (testDialog(title, cursor)) { + return; +} +... +``` + + +**[using PreconditionException, dialog in catch]** +```java +final String title = "Could not insert citation"; + +try { + XTextDocument doc = getXTextDocument(); + styleIsRequired(style); + selectedBibEntryIsRequired(entries, OOError::noEntriesSelectedForCitation); + OOFrontend fr = getFrontend(doc); + XTextCursor cursor = getUserCursorForTextInsertion(doc); + ... +} catch (PreconditionException ex) { + showDialog(title, ex); +} catch (...) { +} +``` + +I would suggest using the latter, +- probably using `OOError` for `PreconditionException` + - In this case `OOError` being in `gui` becomes an asset: we can be sure + code in `logic` cannot throw it. +- We lose the capability to collect mmessages in a single dialog (we + stop processing at the first problem). +- The division between precondition checking (only throws + PreconditionException) and `realAction`becomes invisible in the + action code. + diff --git a/docs/openoffice/ooresult-ooerror.md b/docs/openoffice/ooresult-ooerror.md new file mode 100644 index 00000000000..ec243e0a0dc --- /dev/null +++ b/docs/openoffice/ooresult-ooerror.md @@ -0,0 +1,232 @@ +# About `OOError`, `OOResult` and `OOVoidResult` + +## Context + +### Relieve GUI panel code + +On the question of where should we catch exceptions in relation to GUI +code it was suggested (Jonatan Asketorp +https://github.com/koppor/jabref/pull/496#discussion_r629695493, "most +of them (all?) should be handled latest in the ViewModel.") that +catching them early could help simplifying the higher levels. + +### Same messages in different contexts + +Some types of exceptions are caught in *different GUI actions*, often +resulting in basically the same error dialog, possibly only differing in +the indicated context (which GUI action). + +Problems found during *precondition checking* (for example: do we have +a connection to a document) and error conditions (for example: lost +connection to a document during an action) can overlap. + +### OOBibBase as a precondition and exception handling layer + +Since most of the code originally in `OOBibBase` was moved to `logic` and +almost all GUI actions go through `OOBibBase`, it seemed a good location +to collect precondition checking and exception handling code. + +Note: some of the precondition checking still needs to stay in `OpenOfficePanel`: +for example to provide a list of selected `BibEntry` instances, it needs to go through some steps +from `frame.getCurrentLibraryTab()` to `(!entries.isEmpty() && checkThatEntriesHaveKeys(entries))` + +To avoid `OOBibBase` depending on the higher level `OpenOfficePanel` +message texts needed in `OOBibBase` were moved from `OpenOfficePanel` to `OOError`. +(Others stayed, but could be moved if that seems worthwile) + +## OOError + +- `OOError` is a collection of data used in error dialogs. + - It is a `JabRefException` with an added field: `localizedTitle` + - It can store: a dialog title, a localized message (optionally a non-localized message as well) and a `Throwable` + - I used it in `OOBibBase` as a unified format for errors to be shown in an error dialog. + - Static constructors in `OOError` provide uniform translation from some exception types to + `OOError` with the corresponding localized messages: + `public static OOError from(SomeException ex)` + There is also `public static OOError fromMisc(Exception ex)` for exception types + not handled individually. (It has a different name, to avoid ambiguity) + + - Another set of contructors provide messages for some preconditions. + For example `public static OOError noDataBaseIsOpenForCiting()` + +Some questions: + +- Should we use static data instead of static methods for the precondition-related messages? + - pro: why create a new instance for each error? + - con: `OOError.setTitle()` currently just sets `this.localizedTitle` and returns `this`. + For static instances this would modify a shared resource unless we create a new copy in `setTitle`. + However `setTitle` can be called repeatedly on the same object: as we bubble up, we can be more specific + about the context. + +- Should we remove title from `OOError`? + - pro: we almost always override its original value + - con: may need to duplicate the title in different files (preconditions for an action in OpenOfficePanel + and in OOBibBase) + +- Should we include `OOError.showErrorDialog` ? + - pro: since it was intended *for* error dialogs, it is nice to provide this. + - con: the reference to `DialogService` forces it to `gui`, thus it cannot be used in `logic` or `model` + +- Should we use `JabRefException` as base? + - pro: `JabRefException` is mentioned as the standard form of errors in the developers guide. + [All Exceptions we throw should be or extend JabRefException](https://jabref.readthedocs.io/en/latest/getting-into-the-code/code-howtos/#throwing-and-catching-exceptions) + - against: `JabRefException` is in `logic` cannot be used in model. + (Could this be resolved by moving `JabRefException` to `model`?) + +## OOResult + +During precondition checking + +1. some tests return no data, only report problems +2. we may need to get some resources that might not be available + (for example: connection to a document, a functional textview cursor) +3. some test depend on these resources + +While concentrating on these and on "do not throw exceptions here" +... using a https://en.wikipedia.org/wiki/Result_type as a return +value from precondition checking code seemed a good fit: + +- Instead of throwing an exception, we can return some data describing the problem. +- Conceptually it is a data structure that either holds the result (of a computation) or and error value. +- It can be considered as an extended `Optional`, that can provide details on "why empty"? +- It can be considered as an alternative to throwing an exception: we return an `error` instead. +- Methods throwing checked exceptions cannot be used with for example `List.map`. + Methods returning a Result could. + +- `Result` shares the problem (with any other solutions) that in a +function several types of errors may occur, but we can only return a +single error type. Java solves this using checked exceptions being all +descendants of Exception. (Also adds try/catch/catch to select cases +based on the exceptions type, and some checking against forgotten +cases of checked exception types) + +In `OOBibBase` I used `OOError` as the unified error type: it can +store error messages and wrap exceptions. It contains everything we need +for an error dialog. On the other hand it does not support programmatic +dissection. + +### Implementation + +Unlike `Optional` and `List`, `Result` (in the sense used here) did not get into +java standard libraries. There are some implementations of this idea for java on the net: + + * https://github.com/bgerstle/result-java/ + * https://github.com/MrKloan/result-type + * https://gist.github.com/david-bakin/35d55daeeaee1eb71cea + * https://www.baeldung.com/vavr-try + +Generics allow an implementation built around + +``` +class OOResult { + private final Optional result; + private final Optional error; +} +``` + +with an assumption that at any time exactly one of `result` and `error` is present. + +> `class X { boolean isOK; Object data; }` expresses this assumption more directly, +> (but omits the relation between the type parameters `` and the type in `data`) + +- Since `OOResult` encodes the state `isOK` in `result.isPresent()` (and equivalently in `errror.isEmpty()`), + we cannot allow construction of instances where both values are `isEmpty`. + In particular, `OOResult.ok(null)` and `OOResult.error(null)` are not + allowed: it would make the state `isOK` ambiguous. + It would also break the similarity to `Optional` to allow both `isEmpty` and `isOK` to be true. + +- Not allowing null, has a consequence on `OOResult` + According to + [baeldung.com/java-void-type](https://www.baeldung.com/java-void-type), + the only possible value for `Void` is `null` which we excluded. + + `OOResult.ok(null)` would look strange: in this case we need + `ok()` without arguments. + +To solve this problem, I introduced + +```java +class OOVoidResult { + private final Optional error; + ... +} +``` + +with methods on the error side similar to those in `OOError`, and +`OOVoidResult.ok()` to construct the success case with no data. + +### The relation between `Optional` and `OOVoidResult` + +* Both `Optional` and `OOVoidResult` can store 0 or 1 values, + in this respect they are equivalent + + * Actually, `OOVoidResult` is just a wrapper around an `Optional` + +* In terms of communication to human readers when used, their + connotation in respect to success and failure is the opposite: + + * `Optional.empty()` normally suggests failure, `OOVoidResult.ok()` mean success. + * `Optional.of(something)` probably means success, `OOVoidResult.error(something)` indicates failure. + * `OOVoidResult` is "the other half" (the failure branch) of `OOResult` + + * its content is accessed through `getError`, `mapError`, `ifError`, not `get`, `map`, `ifPresent` + +`OOVoidResult` allows + +* a clear distinction between success and failure when + calls to "get" something that might not be available (`Optional`) and + calls to precondition checking where we can only get reasons for failure + (`OOVoidResult`) + appear together. + Using `Optional` for both is possible, but is more error-prone. + +* it also allows using uniform verbs (`isError`, `getError`, + `ifError`, return `OO{Void}Result.error`) for "we have a problem" + when + + * checking preconditions (`OOVoidResult`) is mixed with + * "I need an X" orelse "we have a problem" (`OOResult`) + +* at a functions head: + + * `OOVoidResult function()` says: no result, but may get an error message + * `Optional function()` says: a `String` result or nothing. + +**Summary**: technically could use `Optional` for both situation, but it would be less precise, +leaving more room for confusion and bugs. `OOVoidResult` forces use of `getError` instead of `get`, +and `isError` or `isOk` instead of `isPresent`or `isEmpty`. + +## What does OOResult buy us? + + +The promise of `Result` is that we can avoid throwing exceptions and +return errors instead. This allows the caller to handle these latter +as data, for example may summarize / collect them for example into a single +message dialog. + +Handling the result needs some code in the caller. If we only needed checks that +return only errors (not results), the code could look like this (with possibly more tests listed): + +```java +OOResult odoc = getXTextDocument(); +if (testDialog(title, + odoc, + styleIsRequired(style), + selectedBibEntryIsRequired(entries, OOError::noEntriesSelectedForCitation))) { + return; +} +``` + +with a reasonably small footstep. + +Dependencies of tests on earlier results complicates this: now we repeat the + +```java +if (testDialog(title, + ...)) { + return; +} +``` + +part several times. + diff --git a/docs/openoffice/order-of-appearance.md b/docs/openoffice/order-of-appearance.md new file mode 100644 index 00000000000..a59846af16c --- /dev/null +++ b/docs/openoffice/order-of-appearance.md @@ -0,0 +1,118 @@ + +## Order of appearance of citation groups (`globalOrder`) + +The order of appearance of citations is decided on +two levels: + +1. their order within each citation group (`localOrder`), and +2. the order of the citation +groups that appear as citation markers in the text (`globalOrder`). + +This page is about the latter: how to decide the order of appearance (numbering sequence) of a set +of citation markers? + +### Conceptually + +In a continuous text it is easy: take the textual order of citation markers. + +In the presence of figures, tables, footnotes/endnotes possibly far from the location they are +referred to in the text or wrapped around with text it becomes less obvious what is the correct +order. + +Examples: + +- References in footnotes: are they *after* the page content, or number them as if they appeared at + the footnote mark? (JabRef does the latter) +- A figure with references in its caption. Text may flow on either or both sides. + Where should we insert these in the sequence? +- In a two-column layout, a text frame or figure mostly, but not fully in the second column: shall + we consider it part of the second column? + + +### Technically + + +In LibreOffice, a document has a main text that supports the +[XText](https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1text_1_1XText.html) +interface. +This allows several types of +[XTextContent](https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1text_1_1XTextContent.html) +to be inserted. + +- Some of these allow text inside with further insertions. + +#### Anchors + +- Many, but not all XTextContent types support getting a "technical" insertion point or text range + through [getAnchor](https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1text_1_1XTextContent.html#ae82a8b42f6b2578549b68b4483a877d3). +- In Libreoffice positioning both a frame and its anchor seems hard: moving the frame tends to also + move the anchor. +- Consequence: producing an order of appearance for the citation groups based solely on `getAnchor` + calls may be impossible. + + - Allowing or requiring the user to insert "logical anchors" for frames and other "floating" parts + might help to alleviate these problems. + +#### Sorting within a `Text` + +The text ranges occupied by the citation markers support the +[XTextRange](https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1text_1_1XTextRange.html) +interface. + +- These provide access to the XText they are contained in. +- The [Text](https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1text_1_1Text.html) service +may support (optional) the [XTextRangeCompare](https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1text_1_1XTextRangeCompare.html) +interface, that allows two XTextRange values to be compared if both belong to this `Text` + +#### Visual ordering + +- The cursor used by the user is available as an + [XTextViewCursor](https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1text_1_1XTextViewCursor.html) +- If we can get it and can set its position in the document to each XTextRange to be sorted, and ask its + [getPosition](https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1text_1_1XTextViewCursor.html#a9b2bafd342ef75b5d504a9313dbb1389) + to provide coordinates "relative to the top left position of the first page of the document.", + then we can sort by these coordinates in top-to-bottom left-to-right order. +- Note: in some cases, for example when the cursor is in a comment (as in + `Libreoffice:[menu:Insert]/[Comment]`), the XTextViewCursor is not available (I know of no way to + get it). +- In some other cases, for example when an image is selected, the XTextViewCursor we normally receive is not 'functional': +we cannot position it for getting coordinates for the citation marks. +The [FunctionalTextViewCursor](https://github.com/antalk2/jabref/blob/improve-reversibility-rebased-03/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java) +class can solve this case by accessing and manipulating the cursor through [XSelectionSupplier](https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1view_1_1XSelectionSupplier.html) + +Consequences of getting these visual coordinates and using them to order the citation markers + +- allows uniform handling of the markers. Works in footnotes, tables, frames (apparently anywhere) +- requires moving the user visible cursor to each position and with [screen + refresh](https://github.com/antalk2/jabref/blob/improve-reversibility-rebased-03/src/main/java/org/jabref/model/openoffice/uno/UnoScreenRefresh.java) + enabled. + `(problem)` This results in some user-visible flashing and scrolling around in the document view. +- The expression "relative to the top left position of the first page of the document" is + understood literally, "as on the screen". + `(problem)` Showing pages side by side or using a two-column layout + will result in markers in the top half of the second column or page to be sorted before those on the bottom + of the first column of the first page. + + +### JabRef + +Jabref uses the following steps for sorting sorting citation markers (providing `globalOrder`): + +1. the textranges of citation marks in footnotes are replaced by the textranges of the footnote + marks. +2. get the positions (coordinates) of these marks +3. sort in top-to-botton left-to-right order + + +`(problem)` In JabRef5.2 the positions of citation marks within the same footnote become +indistinguishable, thus their order after sorting may differ from their order in the footnote text. +This caused problems for + +1. numbering order + `(solved)` by keeping track of the order-in-footnote of citation markers during sorting using + [getIndexInPosition](https://github.com/antalk2/jabref/blob/122d5133fa6c7b44245c5ba5600d398775718664/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java#L21)) +2. `click:Merge`: It examines *consecutive* pairs of citation groups if they can be merged. Wrong +order may result in not discovering some mergeable pairs or attempting to merge in wrong order. +`(solved)` by not using visual order, only XTextRangeCompare-based order within each XText +[here](https://github.com/antalk2/jabref/blob/122d5133fa6c7b44245c5ba5600d398775718664/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java#L325)) + diff --git a/docs/openoffice/overview.md b/docs/openoffice/overview.md new file mode 100644 index 00000000000..df8a5cef5b2 --- /dev/null +++ b/docs/openoffice/overview.md @@ -0,0 +1,302 @@ + +# Overview + +This is a partial overview of the OpenOffice/LibreOffice panel and the +code behind. + +- To access the panel: `JabRef:/[menu:View]/[OpenOffice/LibreOffice]` +- The user documentation is at +[https://docs.jabref.org/cite/openofficeintegration](https://docs.jabref.org/cite/openofficeintegration) + + +I am going to refer to OpenOffice Writer and LibreOffice Writer as +LibreOffice or LO: their UNO APIs are still mostly identical, but I +only tested with LibreOffice and differences do exist. + +## Subject + +- What is stored in a document, how. +- Generating citation markers and bibliography + - (excluding the bibliography entries, which is delegated to the layout module) + + +## The purpose of the panel + +- Allow the user to insert **citations** in a LibreOffice writer document. +- Automatically format these according to some prescribed style as **citation markers**. +- Generate a **bibliography**, also formatted according to the style. + - The bibliography consists of a title (e.g. "References") and a sorted list + of formatted bibliography entries, possibly prefixed with a marker (e.g. "[1]") +- It also allows some related activities: connect to a document, select a style, group ("Merge") the + citations for nicer output, ungroup ("Separate") them to move or delete them individually, + edit ("Manage") their page-info parts, and collect the database entries of cited sources + to a new database. + +## Citation types + +Citations (actually citation groups, see below) have three types +depending on how the citation marker is intended to appear in the +text: + +- **Parenthesized**: "(Smith, 2000)" +- **In-text**: "Smith (2000)" +- **Invisible**: no visible citation mark. + - An invisible citation mark lets the user to use any form for the citation + by taking control (and responsibility) back from the style. + - Like the other two citation types, they have a location in the document. + - In the bibliography these behave as the other two citation types. + - In LibreOffice (`LibreOffice:[Ctrl-F8]` or`LibreOffice:[menu:View]/[Field Shadings]`) + shows reference marks with gray background. Invisible citation marks appear as a thin gray rectangle. + +- These citation types correspond to `\citep{Smith2000}`, + `\citet{Smith2000}` in + [natbib](http://tug.ctan.org/macros/latex/contrib/natbib/natnotes.pdf) + and `\nocite{Smith2000}`. I will use `\citep`, `\citet` and `\citen` in "LaTeX pseudocode" below. + +## PageInfo + +The citations can be augmented with a string detailing which part +of a document is cited, for example "page 11" or "chapter 2". + +Sample citation markers (with LaTeX pseudocode): + +- `\citep[page 11]{Smith2000}` "(Smith, 2000; page 11)" +- `\citet[page 11]{Smith2000}` "Smith (2000; page 11)" +- `\citen[page 11]{Smith2000}` "" + +- This string is referred to as **`pageInfo`** in the code. +- In the GUI the labels "Cite special", "Extra information + (e.g. page number)" are used. + +## Citation groups + +Citations can be grouped. + +A group of parenthesized citations share the parentheses around, like this: + "(Smith, 2000; Jones 2001)". + + - Examples with pseudocode: + - `\citep{Smith2000,Jones2001}` "(Smith, 2000; Jones 2001)" + - `\citet{Smith2000,Jones2001}` "Smith (2000); Jones (2001)" + - `\citen{Smith2000,Jones2001}` "" + +From the user's point of view, citation groups can be created by + +1. Selecting multiple entries in a bibliography database, then + - `[click:Cite]` or + - `[click:Cite in-text]` or + - `[click:Cite special]` or + - `[click:Insert empty citation]` in the panel. + + This method allows any of the citation types to be used. + +2. `[click:Merge citations]` finds all sets of consecutive citations in the text and + replaces each with a group. + - `(change)` The new code only merges consecutive [parenthesized](https://github.com/antalk2/jabref/blob/122d5133fa6c7b44245c5ba5600d398775718664/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java#L183) citations. + - This is inconsistent with the solution used in `[click:Cite]` + - My impression is that + - groups of in-text or invisible citations are probably not useful + - mixed groups are even less. However, with a numbered style + there is no visual difference between parenthesized and in-text + citations, the user may be left wondering why did merge not work. + - One way out could be to merge as a "parenthesized" + group. But then users switching between styles get a + surprise, we have unexpectedly overridden their choice. + - I would prefer a visible log-like warning that does not require + a click to close and lets me see multiple warnings. + Could the main window have such an area at the bottom? + - Starting with JabRef 5.3 there is also `[click:Separate citations]` + that breaks all groups to single citations. + - This allows + - deleting individual citations + - moving individual citations around (between citation groups) + - (copy does not work) + - (Moving a citation within a group has no effect on the final output + due to sorting of citations within groups. See [Sorting within a citation group](#localOrder)) + +In order to manage single citations and groups uniformly, we +consider each citation in the document to belong to a citation +group, even if it means a group containing a single citation. + +Citation groups correspond to citation markers in the document. The latter is empty for invisible +citation groups. When creating the citation markers, the citations in the group +are processed together. + +# Citation styles + +The details of how to format the bibliography and the citation markers are described in a text file. + +- These normally use `.jstyle` extension, and I will refer to them as jstyle files. +- See the [User documentation](https://docs.jabref.org/cite/openofficeintegration#the-style-file) + for details. +- I will refer to keywords in jstyle files as `jstyle:keyword` below. + + +Four major types citation of styles can be described by a jstyle. + +- (1) `jstyle:BibTeXKeyCitations` + + - The citation markers show the citationKey. + - It is not fully implemented + - does not produce markers before the bibliography entries + - does not show pageInfo + - It is not advertised in the [User documentation](https://docs.jabref.org/cite/openofficeintegration#the-style-file). + - Its intended purpose may be + + - (likely) a proper style, with "[Smith2000]" style citation markers + - (possibly) a style for "draft mode" that + - can avoid lookup of citation markers in the database when only the + citation markers are updated + - can produce unique citation markers trivially (only needs local information) + - makes the citation keys visible to the user + - can work without knowing the order of appearance of citation groups + - In case we expect to handle larger documents, a "draft mode" + minimizing work during `[click:Cite]` may be useful. + +- There are two types of numbered (`jstyle:IsNumberEntries`) citation styles: + + - (2) Citations numbered in order of first appearance (`jstyle:IsSortByPosition`) + - (3) Citations numbered according to their order in the sorted bibliography + +- (4) Author-year styles + +# Sorting + +## Sorting te bibliography + +The bibliography is sorted in (author, year, title) order + +- except for `jstyle:IsSortByPosition`, that uses the order of first + appearance of the cited sources. + +## Ordering the citations + +The order of appearance of citations (as considered during numbering and adding letters after the +year to ensure that citation markers uniquely identify sources in the bibliography) is decided on +two levels. + +1. Their order within each citation group (`localOrder`), and +2. the order of the citation groups (citation markers) in the text (`globalOrder`). + +### Sorting within a citation group (`localOrder`) + +The order of citations within a citation group is controlled by +`jstyle:MultiCiteChronological`. + +- true asks for (year, author, title) ordering, +- false for (author, year, title). +- (There is no option for "in the order provided by the user"). + + +For author-year citation styles this ordering is used directly. + +- The (author, year, title) order promotes discovering citations + sharing authors and year and emitting them in a shorter form. For + example as "(Smith 2000a,b)". + +For numbered styles, the citations within a group are sorted again +during generation of the citation marker, now by the numbers +themselves. The result of this sorting is not saved, only affects the citation marker. + + - Series of consecutive number are replaced with ranges: for example "[1-5; 11]" + +### Order of the citation groups (`globalOrder`) + +The location of each citation group in the document is provided by the +user. In a text with no insets, footnotes, figures etc. this directly +provides the order. In the presence of these, it becomes more +complicated, see [Order of appearance of +citation groups](order-of-appearance.md). + +### Order of the citations + +- `globalOrder` and `localOrder` together provide the order of appearance of + citations +- This also provides the order of first appearance of the cited sources. + + First appearance order of sources is used + - in `jstyle:IsSortByPosition` numbered styles + - in author-year styles: first appearance of "Smith200a" + should precede that of "Smith200b". + To achieve this, the sources get the letters + according the order of their first appearance. + - This seems to contradict the statement "The bibliography is + sorted in (author, year, title) order" above. + It does not. As of JabRef 5.3 both are true. + Consequence: in the references + Smith2000b may precede Smith2000a. + ([reported](https://github.com/JabRef/jabref/issues/7805)) + - Some author-year citation styles prescribe a higher threshold on + the number of authors for switching to "FirstAuthor et al." form + (`jstyle:MaxAuthors`) at the first citation of a source + (`jstyle:MaxAuthorsFirst`) + + + +# What is stored in a document (JabRef5.2) + +- Each group of citations has a reference mark. + + (Reference marks are shown in LibreOffice in Navigator, under "References". + To show the Navigator: `LibreOffice:[menu:View]/[Navigator]` or `LibreOffice:[key:F5]`) + + Its purposes: + + 1. The text range of the reference mark tells where to write or update the citation mark. + 2. The name of the reference mark + + - Lets us select only those reference marks that belong to us + - Encodes the citation type + - Contains the list of citation keys that belong to this group + - It may contain an extra number, to make the name unique in the document + - Format: `"JR_cite{number}_{type}_{citationKeys}"`, where + - `{number}` is either empty or an unsigned integer (it can be zero) to make the name unique + - `{type}` is 1, 2, or 3 for parenthesized, in-text and invisible + - `{citationKeys}` contains the comma-separated list of citation keys + - Examples: + - `JR_cite_1_Smith2000` (empty number part, parenthesized, single citation) + - `JR_cite0_2_Smith2000,Jones2001` (number part is 0, in-text, two citations) + - `JR_cite1_3_Smith2000,Jones2001` (number part is 1, invisible, two citations) + +- Each group of citations may have an associated pageInfo. + + - In LibreOffice, these can be found at + `LibreOffice:/[menu:File]/[Properties]/[Custom Properties]` + - The property names are identical to the name of the reference mark + corresponding to the citation group. + - JabRef 5.2 never cleans up these, they are left around. + `(problem)` New citations may "pick up" these unexpectedly. + +- The bibliography, if not found, is created at the end of the document. + - The location and extent of the bibliography is the content of the Section named `"JR_bib"`. + (In LibreOffice Sections are listed in the Navigator panel, under "Sections") + - JabRef 5.2 also creates a bookmark named `"JR_bib_end"`, but does + not use it. During bibliography update it attempts to create it again without + removing the old bookmark. The result is a new bookmark, with a number appended to its name + (by LibreOffice, to ensure unique names of bookmarks). + - [Correction in new code](https://github.com/antalk2/jabref/blob/122d5133fa6c7b44245c5ba5600d398775718664/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java#L147): + remove the old before creating the new. + +# How does it interact with the document? + +- "stateless" + JabRef is only loosely coupled to the document. + Between two GUI actions it does not receive any information from LibreOffice. + It cannot distinguish between the user changing a single character in the document or rewriting everything. + +- Access data + - During a `[click:cite]` or `[click:Update]` we need the reference mark names. + - Get all reference mark names + - Filter (only ours) + - Parse: gives citation type (for the group), citation keys + - Access/store pageInfo: based on reference mark name and property name being equal + - Creating a citation group: (`[click:cite]`) + - Creates a reference mark at the cursor, with a name as described above. +- Update (refreshing citation markers and bibliography): + - citation markers: the content of the reference mark + - bibliography: the content of the Section (in LibreOffice sense) + named `"JR_bib"`. + + + + diff --git a/docs/openoffice/problems.md b/docs/openoffice/problems.md new file mode 100644 index 00000000000..0492c041e4e --- /dev/null +++ b/docs/openoffice/problems.md @@ -0,0 +1,99 @@ +# Problems in JabRef 5.2 + +## pageInfo should belong to citations, not citation groups + +- Creating `[click:Separate]` revealed + a `(problem)`: pageInfo strings are conceptually associated with + citations, but the implementation associates them to citation groups. + The number of available + pageInfo slots changes during`[click:Merge]` and `[click:Separate]` while the number of citations + remains fixed. + - The proposed solution was to change the association. + - Not only reference marks (citation groups) need unique identifiers, but also citations. + Possible encoding for reference mark names: + `JR_cite{type}_{number1}_{citationKey1},{number2}_{citationKey2}` + where `{type}` encodes the citation type (for the group), `{citationKey1}` is made unique by choosing an appropriate number for `{number1}` + This would allow + `JR_cite_{number1}_{citationKey1}` to be used as a property name for storing the pageInfo. + + Changes required to + - reference mark search, name generation and parsing + - name generation and parsing for properties storing pageInfo values + - in-memory representation + - JabRef 5.2 does not collect pageInfo values, accesses only when needed. + So it would be change to code accessing them. + - The proposed representation does collect, to allow separation of getting from the document + and processing + - insertion of pageInfo into citation markers: JabRef 5.2 injects a single pageInfo before the closing parenthesis, + now we need to handle several values + - `[click:Manage citations]` should work on citations, not citation groups. + + +## Backend + +The choice of how do we represent the data and the citation marks in the document has consequences +on usability. + +Reference marks have some features that make it easy to mess up citations in a document + +- They are **not visible** by default, the user is not aware of their boundaries +(`LO:[key:Ctrl-F8]`, `LO:[View]/[Field shadings]` helps) + +- They are **not atomic**: + - the user can edit the content. This will be lost on `[click:Update]` + If an `As character` or `To character` anchor is inserted, the corresponding frame or footnote is deleted. + - by pressing Enter within, the user can break a reference mark into two parts. + The second part is now outside the reference mark: `[click:Update]` will leave it as is, and replace the first part + with the full text for the citation mark. + - If the space separating to citation marks is deleted, the user cannot reliably type between the + marks. + The text typed usually becomes part of one of the marks. No visual clue as to which one. + Note: `[click:Merge]` then `[click:Separate]` adds a single space between. The user can + position the cursor before or after it. In either case the cursor is on a boundary: it is not + clear if it is in or out of a reference mark. + Special case: a reference mark at the start or end of a paragraph: the cursor is usually considered to be within at the coresponding edge. +- (good) They can be moved (Ctrl-X,Ctrl-V) +- They cannot be copied. (Ctrl-C, Ctrl-V) copies the text without the reference mark. +- Reference marks are lost if the document is saved as docx. + +- I know of no way to insert text into an empty text range denoted by a reference mark + - JabRef 5.3 recreates the reference mark (using [insertReferenceMark](https://github.com/JabRef/jabref/blob/475b2989ffa8ec61c3327c62ed8f694149f83220/src/main/java/org/jabref/gui/openoffice/OOBibBase.java#L1072)) + [here](https://github.com/JabRef/jabref/blob/475b2989ffa8ec61c3327c62ed8f694149f83220/src/main/java/org/jabref/gui/openoffice/OOBibBase.java#L706) + - `(change)` I preferred to (try to) avoid this: + [NamedRangeReferenceMark.nrGetFillCursor](https://github.com/antalk2/jabref/blob/122d5133fa6c7b44245c5ba5600d398775718664/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java#L225) + returns a cursor between two invisible + spaces, to provide the caller a location it can safely write some text. [NamedRangeReferenceMark.nrCleanFillCursor](https://github.com/antalk2/jabref/blob/122d5133fa6c7b44245c5ba5600d398775718664/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java#L432) + removes these invisible spaces unless the content would become empty or a single character. By + keeping the content at least two characters, we avoid the ambiguity at the edges: a cursor + positioned between two characters inside is always within the reference mark. (At the edges it + may or may not be inside.) + +- `(change)` `[click:Cite]` at reference mark edges: [safeInsertSpacesBetweenReferenceMarks](https://github.com/antalk2/jabref/blob/122d5133fa6c7b44245c5ba5600d398775718664/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java#L67) ensures the we are not inside, by starting two new paragraphs, inserting two spaces between them, then removing the new paragraph marks. +- `(change)` [guiActionInsertEntry](https://github.com/antalk2/jabref/blob/122d5133fa6c7b44245c5ba5600d398775718664/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java#L624) +checks if the cursor is in a citation mark or the bibliography. + +- `(change)` `[click:Update]` does an [exhaustive check](https://github.com/antalk2/jabref/blob/122d5133fa6c7b44245c5ba5600d398775718664/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java#L927) +for overlaps between protected ranges (citation marks and bibliography). This can become slow if there are many citations. + + +It would be nice if we could have a backend with better properties. We probably need multiple +backends for different purposes. This would be made easier if the backend were separated from the +rest of the code. This would be the purpose of +[logic/openoffice/backend](https://github.com/antalk2/jabref/tree/improve-reversibility-rebased-03/src/main/java/org/jabref/logic/openoffice/backend). + +## Undo + +- JabRef 5.3 does not collect the effects of GUI actions on the document into larger Undo actions. +This makes the Undo functionality of LO impractial. +- `(change)` collect the effects of GUI actions into large chunks: now a GUI action can be undone +with a single click. + - except the effect on pageInfo: that is stored at the document level and is not restored by Undo. + +## Block screen refresh + +- LibreOffice has support in [XModel](https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1frame_1_1XModel.html#a7b7d36374033ee9210ec0ac5c1a90d9f) +to "suspend some notifications to the controllers which are used for display updates." + +- `(change)` Now we are using this facility. + + From 982b27aa05eeae12a3673137c4b4add5f1daf656 Mon Sep 17 00:00:00 2001 From: Antal K Date: Wed, 30 Jun 2021 00:45:41 +0200 Subject: [PATCH 041/103] markdown-lint --- docs/openoffice/code-reorganization.md | 22 +++++----- docs/openoffice/ooresult-alternatives.md | 28 ++++++------ docs/openoffice/ooresult-ooerror.md | 56 ++++++++++++------------ docs/openoffice/order-of-appearance.md | 14 +++--- docs/openoffice/overview.md | 29 +++++------- docs/openoffice/problems.md | 4 +- 6 files changed, 74 insertions(+), 79 deletions(-) diff --git a/docs/openoffice/code-reorganization.md b/docs/openoffice/code-reorganization.md index b91aa53984c..a9d45418690 100644 --- a/docs/openoffice/code-reorganization.md +++ b/docs/openoffice/code-reorganization.md @@ -44,7 +44,7 @@ Why - `rangesort` : ordering objects that have an `XTextRange`, optionally with an extra integer to break ties. - `RangeSort.partitionAndSortRanges` : since `XTextRangeCompare` can only compare `XTextRange` values in the same `XText`, we partition them accordingly and only sort within each partiion. - - `RangeSortable` (interface), `RangeSortEntry` (implements) : + - `RangeSortable` (interface), `RangeSortEntry` (implements) : When we replace `XTextRange` of citation marks in footnotes with the range of the footnote mark, multiple citation marks may be mapped to the same location. To preserve the order between these, `RangeSortable` allows this order to be indicated by returning appropriate indices from `getIndexInPosition` @@ -59,7 +59,7 @@ Why May change as new backends may need different APIs. - `style` : data structures and interfaces used while going from ordered list of citation groups to formatted citation markers and bibliography. Does not communicate with the document. Too long to fit here, starting a new section. - + ## model/style At the core, @@ -112,6 +112,7 @@ This is done in logic, in [`OOProcessAuthorYearMarkers.createUniqueLetters()`](h The entry point for this processing is: [`OOProcess.produceCitationMarkers`](https://github.com/antalk2/jabref/blob/fed0952cbdaf7a76bcb09b3db5ac48f34f5ca388/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java#L69). It fills + - each `CitationGroup.citationMarker` - `CitationGroups.bibliography` - From bibliography `OOFormatBibliography.formatBibliography()` creates an `OOText` @@ -138,7 +139,7 @@ to the rest. Originally it also contains code to format numeric and author-year - `CitationMarkerNumericEntry` - `CitationMarkerEntry` - `CitationMarkerNumericBibEntry` - - `CitationMarkerNormEntry` + - `CitationMarkerNormEntry` describe their expected input entries. - [`OOProcess.produceCitationMarkers`](https://github.com/antalk2/jabref/blob/fed0952cbdaf7a76bcb09b3db5ac48f34f5ca388/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java#L69) is the main entry point for style application. Calls to specific implementations @@ -159,7 +160,7 @@ These are currently in `UpdateBibliography` - `OOFrontend` : has a `Backend` and `CitationGroups` - Its constructor creates a backend, reads data from the document and creates a CitationGroups instance. - provides functionality that requires both access to the document and the CitationGroups instance -- `RangeForOverlapCheck` used in `OOFrontend` +- `RangeForOverlapCheck` used in `OOFrontend` - `UpdateBibliography` : Create, find and update the bibliography in the document using output from `produceCitationMarkers()` - `UpdateCitationMarkers` create `CitationGroup`, update citation markers using output from @@ -178,11 +179,10 @@ GUI-independent part of implementations of GUI actions. - contains some dialog messages that do not correspond to exceptions - `OOBibBase2` : most activity was moved out from here to parts discussed above. - - connecting / selecting a document moved to `OOBibBaseConnect` - - the rest connects higher parts of the GUI to actions in logic - - does argument and precondition checking - - catches all exceptions - - shows error and warning dialogs - - adds `enterUndoContext`, `leaveUndoContext` around action code - + - connecting / selecting a document moved to `OOBibBaseConnect` + - the rest connects higher parts of the GUI to actions in logic + - does argument and precondition checking + - catches all exceptions + - shows error and warning dialogs + - adds `enterUndoContext`, `leaveUndoContext` around action code diff --git a/docs/openoffice/ooresult-alternatives.md b/docs/openoffice/ooresult-alternatives.md index 83f8ca67232..27d5dbb7e11 100644 --- a/docs/openoffice/ooresult-alternatives.md +++ b/docs/openoffice/ooresult-alternatives.md @@ -14,7 +14,8 @@ Situation: One strategy could be to use a single try-catch around the whole body, then showing a message based on the type of exceptions thrown. -**[base case]** +## [base case] + ```java try { A a = f(); @@ -101,11 +102,11 @@ We still need to notify the action handler (the caller) about failure. Since we have shown the dialog, we do not need to provide a message. -### Notify caller with `Optional` result. +### Notify caller with `Optional` result With `Optional` we get something like this: -**[dialog in wrap, return Optional]** +#### [dialog in wrap, return Optional] ```java Optional wrap_f(String title) { @@ -157,11 +158,11 @@ try { } ``` -### Notify caller with `Result` result. +### Notify caller with `Result` result With `Result` we get something like this: -**[dialog in wrap, return OOResult]** +#### [dialog in wrap, return OOResult] ```java OOResult wrap_f() { @@ -221,8 +222,6 @@ try { } ``` - - ### Notify caller by throwing an exception Or we can throw an exception to notify the caller. @@ -230,7 +229,7 @@ Or we can throw an exception to notify the caller. To simplify code in the caller, I assume we are using an exception type not used elsewhere, but shared by all precondition checks. -**[dialog in wrap, PreconditionException]** +#### [dialog in wrap, PreconditionException] ```java A wrap_f(String title) throws PreconditionException { @@ -304,7 +303,7 @@ try { or to reduce passing around the title part: -**[PreconditionException, dialog in catch]** +#### [PreconditionException, dialog in catch] ```java A wrap_f() throws PreconditionException { @@ -343,7 +342,7 @@ try { or -``` +```java try { A a = wrap_f(); B b = wrap_g(a); @@ -447,7 +446,8 @@ The more promising variants were - pro: no repeated `if(){return}` boilerplate - pro: title used only once -**[using OOResult]** +### [using OOResult] + ```java final String title = "Could not insert citation"; @@ -474,7 +474,8 @@ if (testDialog(title, cursor)) { ``` -**[using PreconditionException, dialog in catch]** +### [using PreconditionException, dialog in catch] + ```java final String title = "Could not insert citation"; @@ -491,7 +492,8 @@ try { } ``` -I would suggest using the latter, +I would suggest using the latter, + - probably using `OOError` for `PreconditionException` - In this case `OOError` being in `gui` becomes an asset: we can be sure code in `logic` cannot throw it. diff --git a/docs/openoffice/ooresult-ooerror.md b/docs/openoffice/ooresult-ooerror.md index ec243e0a0dc..867ee55d009 100644 --- a/docs/openoffice/ooresult-ooerror.md +++ b/docs/openoffice/ooresult-ooerror.md @@ -6,7 +6,7 @@ On the question of where should we catch exceptions in relation to GUI code it was suggested (Jonatan Asketorp -https://github.com/koppor/jabref/pull/496#discussion_r629695493, "most +[here](https://github.com/koppor/jabref/pull/496#discussion_r629695493), "most of them (all?) should be handled latest in the ViewModel.") that catching them early could help simplifying the higher levels. @@ -48,7 +48,7 @@ message texts needed in `OOBibBase` were moved from `OpenOfficePanel` to `OOErro - Another set of contructors provide messages for some preconditions. For example `public static OOError noDataBaseIsOpenForCiting()` - + Some questions: - Should we use static data instead of static methods for the precondition-related messages? @@ -57,12 +57,12 @@ Some questions: For static instances this would modify a shared resource unless we create a new copy in `setTitle`. However `setTitle` can be called repeatedly on the same object: as we bubble up, we can be more specific about the context. - + - Should we remove title from `OOError`? - pro: we almost always override its original value - con: may need to duplicate the title in different files (preconditions for an action in OpenOfficePanel and in OOBibBase) - + - Should we include `OOError.showErrorDialog` ? - pro: since it was intended *for* error dialogs, it is nice to provide this. - con: the reference to `DialogService` forces it to `gui`, thus it cannot be used in `logic` or `model` @@ -83,7 +83,7 @@ During precondition checking 3. some test depend on these resources While concentrating on these and on "do not throw exceptions here" -... using a https://en.wikipedia.org/wiki/Result_type as a return +... using a [Result type](https://en.wikipedia.org/wiki/Result_type) as a return value from precondition checking code seemed a good fit: - Instead of throwing an exception, we can return some data describing the problem. @@ -102,7 +102,7 @@ cases of checked exception types) In `OOBibBase` I used `OOError` as the unified error type: it can store error messages and wrap exceptions. It contains everything we need -for an error dialog. On the other hand it does not support programmatic +for an error dialog. On the other hand it does not support programmatic dissection. ### Implementation @@ -110,14 +110,14 @@ dissection. Unlike `Optional` and `List`, `Result` (in the sense used here) did not get into java standard libraries. There are some implementations of this idea for java on the net: - * https://github.com/bgerstle/result-java/ - * https://github.com/MrKloan/result-type - * https://gist.github.com/david-bakin/35d55daeeaee1eb71cea - * https://www.baeldung.com/vavr-try +- [bgerstle/result-java](https://github.com/bgerstle/result-java/) +- [MrKloan/result-type](https://github.com/MrKloan/result-type) +- [david-bakin](https://gist.github.com/david-bakin/35d55daeeaee1eb71cea) +- [vavr-try](https://www.baeldung.com/vavr-try) Generics allow an implementation built around -``` +```java class OOResult { private final Optional result; private final Optional error; @@ -143,7 +143,7 @@ with an assumption that at any time exactly one of `result` and `error` is prese `OOResult.ok(null)` would look strange: in this case we need `ok()` without arguments. -To solve this problem, I introduced +To solve this problem, I introduced ```java class OOVoidResult { @@ -157,40 +157,40 @@ with methods on the error side similar to those in `OOError`, and ### The relation between `Optional` and `OOVoidResult` -* Both `Optional` and `OOVoidResult` can store 0 or 1 values, +- Both `Optional` and `OOVoidResult` can store 0 or 1 values, in this respect they are equivalent - * Actually, `OOVoidResult` is just a wrapper around an `Optional` + - Actually, `OOVoidResult` is just a wrapper around an `Optional` -* In terms of communication to human readers when used, their +- In terms of communication to human readers when used, their connotation in respect to success and failure is the opposite: - * `Optional.empty()` normally suggests failure, `OOVoidResult.ok()` mean success. - * `Optional.of(something)` probably means success, `OOVoidResult.error(something)` indicates failure. - * `OOVoidResult` is "the other half" (the failure branch) of `OOResult` - - * its content is accessed through `getError`, `mapError`, `ifError`, not `get`, `map`, `ifPresent` + - `Optional.empty()` normally suggests failure, `OOVoidResult.ok()` mean success. + - `Optional.of(something)` probably means success, `OOVoidResult.error(something)` indicates failure. + - `OOVoidResult` is "the other half" (the failure branch) of `OOResult` + + - its content is accessed through `getError`, `mapError`, `ifError`, not `get`, `map`, `ifPresent` `OOVoidResult` allows -* a clear distinction between success and failure when +- a clear distinction between success and failure when calls to "get" something that might not be available (`Optional`) and calls to precondition checking where we can only get reasons for failure (`OOVoidResult`) appear together. Using `Optional` for both is possible, but is more error-prone. -* it also allows using uniform verbs (`isError`, `getError`, +- it also allows using uniform verbs (`isError`, `getError`, `ifError`, return `OO{Void}Result.error`) for "we have a problem" when - * checking preconditions (`OOVoidResult`) is mixed with - * "I need an X" orelse "we have a problem" (`OOResult`) + - checking preconditions (`OOVoidResult`) is mixed with + - "I need an X" orelse "we have a problem" (`OOResult`) -* at a functions head: +- at a functions head: - * `OOVoidResult function()` says: no result, but may get an error message - * `Optional function()` says: a `String` result or nothing. + - `OOVoidResult function()` says: no result, but may get an error message + - `Optional function()` says: a `String` result or nothing. **Summary**: technically could use `Optional` for both situation, but it would be less precise, leaving more room for confusion and bugs. `OOVoidResult` forces use of `getError` instead of `get`, @@ -228,5 +228,5 @@ if (testDialog(title, } ``` -part several times. +part several times. diff --git a/docs/openoffice/order-of-appearance.md b/docs/openoffice/order-of-appearance.md index a59846af16c..e43009b9f93 100644 --- a/docs/openoffice/order-of-appearance.md +++ b/docs/openoffice/order-of-appearance.md @@ -1,5 +1,5 @@ -## Order of appearance of citation groups (`globalOrder`) +# Order of appearance of citation groups (`globalOrder`) The order of appearance of citations is decided on two levels: @@ -11,7 +11,7 @@ groups that appear as citation markers in the text (`globalOrder`). This page is about the latter: how to decide the order of appearance (numbering sequence) of a set of citation markers? -### Conceptually +## Conceptually In a continuous text it is easy: take the textual order of citation markers. @@ -29,7 +29,7 @@ Examples: we consider it part of the second column? -### Technically +## Technically In LibreOffice, a document has a main text that supports the @@ -41,7 +41,7 @@ to be inserted. - Some of these allow text inside with further insertions. -#### Anchors +### Anchors - Many, but not all XTextContent types support getting a "technical" insertion point or text range through [getAnchor](https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1text_1_1XTextContent.html#ae82a8b42f6b2578549b68b4483a877d3). @@ -53,7 +53,7 @@ to be inserted. - Allowing or requiring the user to insert "logical anchors" for frames and other "floating" parts might help to alleviate these problems. -#### Sorting within a `Text` +### Sorting within a `Text` The text ranges occupied by the citation markers support the [XTextRange](https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1text_1_1XTextRange.html) @@ -64,7 +64,7 @@ interface. may support (optional) the [XTextRangeCompare](https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1text_1_1XTextRangeCompare.html) interface, that allows two XTextRange values to be compared if both belong to this `Text` -#### Visual ordering +### Visual ordering - The cursor used by the user is available as an [XTextViewCursor](https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1text_1_1XTextViewCursor.html) @@ -94,7 +94,7 @@ Consequences of getting these visual coordinates and using them to order the cit of the first column of the first page. -### JabRef +## JabRef Jabref uses the following steps for sorting sorting citation markers (providing `globalOrder`): diff --git a/docs/openoffice/overview.md b/docs/openoffice/overview.md index df8a5cef5b2..f3a6ed251f6 100644 --- a/docs/openoffice/overview.md +++ b/docs/openoffice/overview.md @@ -75,10 +75,10 @@ Citations can be grouped. A group of parenthesized citations share the parentheses around, like this: "(Smith, 2000; Jones 2001)". - - Examples with pseudocode: - - `\citep{Smith2000,Jones2001}` "(Smith, 2000; Jones 2001)" - - `\citet{Smith2000,Jones2001}` "Smith (2000); Jones (2001)" - - `\citen{Smith2000,Jones2001}` "" +- Examples with pseudocode: + - `\citep{Smith2000,Jones2001}` "(Smith, 2000; Jones 2001)" + - `\citet{Smith2000,Jones2001}` "Smith (2000); Jones (2001)" + - `\citen{Smith2000,Jones2001}` "" From the user's point of view, citation groups can be created by @@ -198,7 +198,7 @@ For numbered styles, the citations within a group are sorted again during generation of the citation marker, now by the numbers themselves. The result of this sorting is not saved, only affects the citation marker. - - Series of consecutive number are replaced with ranges: for example "[1-5; 11]" +- Series of consecutive number are replaced with ranges: for example "[1-5; 11]" ### Order of the citation groups (`globalOrder`) @@ -220,19 +220,18 @@ citation groups](order-of-appearance.md). should precede that of "Smith200b". To achieve this, the sources get the letters according the order of their first appearance. - - This seems to contradict the statement "The bibliography is - sorted in (author, year, title) order" above. - It does not. As of JabRef 5.3 both are true. - Consequence: in the references - Smith2000b may precede Smith2000a. - ([reported](https://github.com/JabRef/jabref/issues/7805)) + - This seems to contradict the statement "The bibliography is + sorted in (author, year, title) order" above. + It does not. As of JabRef 5.3 both are true. + Consequence: in the references + Smith2000b may precede Smith2000a. + ([reported](https://github.com/JabRef/jabref/issues/7805)) - Some author-year citation styles prescribe a higher threshold on the number of authors for switching to "FirstAuthor et al." form (`jstyle:MaxAuthors`) at the first citation of a source (`jstyle:MaxAuthorsFirst`) - # What is stored in a document (JabRef5.2) - Each group of citations has a reference mark. @@ -279,7 +278,7 @@ citation groups](order-of-appearance.md). # How does it interact with the document? -- "stateless" +- "stateless" JabRef is only loosely coupled to the document. Between two GUI actions it does not receive any information from LibreOffice. It cannot distinguish between the user changing a single character in the document or rewriting everything. @@ -296,7 +295,3 @@ citation groups](order-of-appearance.md). - citation markers: the content of the reference mark - bibliography: the content of the Section (in LibreOffice sense) named `"JR_bib"`. - - - - diff --git a/docs/openoffice/problems.md b/docs/openoffice/problems.md index 0492c041e4e..c23b39a7d25 100644 --- a/docs/openoffice/problems.md +++ b/docs/openoffice/problems.md @@ -40,7 +40,7 @@ Reference marks have some features that make it easy to mess up citations in a d (`LO:[key:Ctrl-F8]`, `LO:[View]/[Field shadings]` helps) - They are **not atomic**: - - the user can edit the content. This will be lost on `[click:Update]` + - the user can edit the content. This will be lost on `[click:Update]` If an `As character` or `To character` anchor is inserted, the corresponding frame or footnote is deleted. - by pressing Enter within, the user can break a reference mark into two parts. The second part is now outside the reference mark: `[click:Update]` will leave it as is, and replace the first part @@ -95,5 +95,3 @@ with a single click. to "suspend some notifications to the controllers which are used for display updates." - `(change)` Now we are using this facility. - - From ad194e51ffc4edd6f45199088c228266ce2be567 Mon Sep 17 00:00:00 2001 From: Antal K Date: Tue, 22 Jun 2021 15:42:36 +0200 Subject: [PATCH 042/103] use StringUtil.isNullOrEmpty --- .../java/org/jabref/model/openoffice/ootext/OOFormat.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java index be5ee399e55..4bfba9e5baf 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java @@ -1,5 +1,7 @@ package org.jabref.model.openoffice.ootext; +import org.jabref.model.strings.StringUtil; + /** * Helper functions to produce some of the markup as understood by OOTextIntoOO.write * @@ -54,7 +56,7 @@ public static OOText setCharStyle(OOText ootext, String charStyle) { * Mark {@code ootext} as part of a paragraph with style {@code paraStyle} */ public static OOText paragraph(OOText ootext, String paraStyle) { - if (paraStyle == null || "".equals(paraStyle)) { + if (StringUtil.isNullOrEmpty(paraStyle)) { return paragraph(ootext); } String startTag = String.format("

", paraStyle); From ff8517be96a22885ad1c4a6382909389fe5e0496 Mon Sep 17 00:00:00 2001 From: Antal K Date: Tue, 22 Jun 2021 15:42:54 +0200 Subject: [PATCH 043/103] no natural sort for ComparableMark --- .../openoffice/rangesort/RangeSortVisual.java | 48 +++++-------------- 1 file changed, 13 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java index 969f9fed44e..e971e7ea67c 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Objects; import org.jabref.model.openoffice.uno.NoDocumentException; import org.jabref.model.openoffice.uno.UnoScreenRefresh; @@ -73,7 +72,7 @@ public static List> visualSort(List> input input.getIndexInPosition(), input)); } - Collections.sort(set); + Collections.sort(set, RangeSortVisual::compareTopToBottomLeftToRight); if (set.size() != inputSize) { throw new IllegalStateException("visualSort: set.size() != inputSize"); @@ -115,6 +114,17 @@ private static Point findPositionOfTextRange(XTextRange range, XTextViewCursor c return cursor.getPosition(); } + private static int compareTopToBottomLeftToRight(ComparableMark a, ComparableMark b) { + + if (a.position.Y != b.position.Y) { + return a.position.Y - b.position.Y; + } + if (a.position.X != b.position.X) { + return a.position.X - b.position.X; + } + return a.indexInPosition - b.indexInPosition; + } + /** * A reference mark name paired with its visual position. * @@ -123,7 +133,7 @@ private static Point findPositionOfTextRange(XTextRange range, XTextViewCursor c * * Used for sorting reference marks by their visual positions. */ - private static class ComparableMark implements Comparable> { + private static class ComparableMark { private final Point position; private final int indexInPosition; @@ -135,42 +145,10 @@ public ComparableMark(Point position, int indexInPosition, T content) { this.content = content; } - @Override - public int compareTo(ComparableMark other) { - - if (position.Y != other.position.Y) { - return position.Y - other.position.Y; - } - if (position.X != other.position.X) { - return position.X - other.position.X; - } - return indexInPosition - other.indexInPosition; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (o instanceof ComparableMark) { - ComparableMark other = (ComparableMark) o; - return ((this.position.X == other.position.X) - && (this.position.Y == other.position.Y) - && (this.indexInPosition == other.indexInPosition) - && Objects.equals(this.content, other.content)); - } - return false; - } - public T getContent() { return content; } - @Override - public int hashCode() { - return Objects.hash(position, indexInPosition, content); - } } } From 7ec1cc23ebe3ea3281daf73ab396331e2a2e0fa1 Mon Sep 17 00:00:00 2001 From: Antal K Date: Wed, 7 Jul 2021 20:27:07 +0200 Subject: [PATCH 044/103] in response to review https://github.com/JabRef/jabref/pull/7788#pullrequestreview-698494039 - more use of StringUtil.isNullOrEmpty - private final XTextRangeCompare cmp; - List partition = partitions.computeIfAbsent(partitionKey, _key -> new ArrayList<>()); - visualSort does not throw WrappedTargetException, NoDocumentException - set renamed to comparableMarks --- .../model/openoffice/ootext/OOFormat.java | 4 +-- .../model/openoffice/ootext/OOText.java | 5 ++- .../model/openoffice/ootext/OOTextIntoOO.java | 9 ++--- .../model/openoffice/rangesort/RangeSort.java | 36 +++++++++++-------- .../openoffice/rangesort/RangeSortVisual.java | 25 ++++--------- 5 files changed, 36 insertions(+), 43 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java index 4bfba9e5baf..f502922f818 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java @@ -73,8 +73,8 @@ public static OOText paragraph(OOText ootext) { /** * Format an OO cross-reference showing the target's page number as label to a reference mark. */ - public static OOText formatReferenceToPageNumberOfReferenceMark(String referencMarkName) { - String string = String.format("", referencMarkName); + public static OOText formatReferenceToPageNumberOfReferenceMark(String referenceMarkName) { + String string = String.format("", referenceMarkName); return OOText.fromString(string); } } diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOText.java b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java index ad0b9fb448d..f5142e8dc2e 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOText.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java @@ -17,7 +17,7 @@ private OOText(String data) { this.data = data; } - /* null input is passed through */ + /** @return null for null input, otherwise the argument wrapped into a new OOText */ public static OOText fromString(String string) { if (string == null) { return null; @@ -25,7 +25,7 @@ public static OOText fromString(String string) { return new OOText(string); } - /* null input is passed through */ + /** @return null for null input, otherwise the string inside the argument */ public static String toString(OOText ootext) { if (ootext == null) { return null; @@ -38,7 +38,6 @@ public String toString() { return data; } - /* Object.equals */ @Override public boolean equals(Object object) { diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java index 0758d515446..caa78f07d2c 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java @@ -17,6 +17,7 @@ import org.jabref.model.openoffice.uno.UnoCast; import org.jabref.model.openoffice.uno.UnoCrossRef; import org.jabref.model.openoffice.util.OOPair; +import org.jabref.model.strings.StringUtil; import com.sun.star.awt.FontSlant; import com.sun.star.awt.FontStrikeout; @@ -181,7 +182,7 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) String endTagName = m.group(1); String startTagName = m.group(2); String attributeListPart = m.group(3); - boolean isStartTag = (endTagName == null) || "".equals(endTagName); + boolean isStartTag = StringUtil.isNullOrEmpty(endTagName); String tagName = isStartTag ? startTagName : endTagName; Objects.requireNonNull(tagName); @@ -231,7 +232,7 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) switch (key) { case "oo:ParaStyleName": //

- if (value != null && !value.equals("")) { + if (!StringUtil.isNullOrEmpty(value)) { if (setParagraphStyle(cursor, value)) { // Presumably tested already: LOGGER.debug(String.format("oo:ParaStyleName=\"%s\" failed", value)); @@ -689,7 +690,7 @@ private static List> setCharStrikeout(short value) { // CharStyleName private static List> setCharStyleName(String value) { List> settings = new ArrayList<>(); - if (value != null && value != "") { + if (!StringUtil.isNullOrEmpty(value)) { settings.add(new OOPair<>(CHAR_STYLE_NAME, value)); } else { LOGGER.warn("setCharStyleName: received null or empty value"); @@ -708,7 +709,7 @@ private static List> setCharLocale(Locale value) { * Locale from string encoding: language, language-country or language-country-variant */ private static List> setCharLocale(String value) { - if (value == null || "".equals(value)) { + if (StringUtil.isNullOrEmpty(value)) { throw new java.lang.IllegalArgumentException("setCharLocale \"\" or null"); } String[] parts = value.split("-"); diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java index 1b4fc327598..d5024d6d8e2 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java @@ -12,21 +12,29 @@ import com.sun.star.text.XText; import com.sun.star.text.XTextRangeCompare; +/** + * RangeSort provides sorting based on XTextRangeCompare, which only provides comparison + * between XTextRange values within the same XText. + */ public class RangeSort { - /* - * Sort within a partition + /** + * Compare two RangeHolders (using RangeHolder.getRange()) within an XText. + * + * Note: since we only look at the ranges, this comparison is generally not consistent with + * `equals` on the RangeHolders. Probably should not be used for key comparison in + * TreeMap<RangeHolder> or Set<RangeHolder> + * */ - public static class HolderComparatorWithinPartition implements Comparator { - XTextRangeCompare cmp; + private final XTextRangeCompare cmp; HolderComparatorWithinPartition(XText text) { cmp = UnoCast.cast(XTextRangeCompare.class, text).get(); } - /* + /** * Assumes a and b belong to the same XText as cmp. */ @Override @@ -35,7 +43,7 @@ public int compare(RangeHolder a, RangeHolder b) { } } - /* + /** * Sort a list of RangeHolder values known to share the same getText(). * * Note: RangeHolder.getRange() is called many times. @@ -48,10 +56,9 @@ public static void sortWithinPartition(List rangeHold rangeHolders.sort(new HolderComparatorWithinPartition(text)); } - /* - * Partitioning + /** + * Represent a partitioning of RangeHolders by XText */ - public static class RangePartitions { private final Map> partitions; @@ -61,11 +68,7 @@ public RangePartitions() { public void add(V holder) { XText partitionKey = holder.getRange().getText(); - List partition = partitions.get(partitionKey); - if (partition == null) { - partition = new ArrayList<>(); - partitions.put(partitionKey, partition); - } + List partition = partitions.computeIfAbsent(partitionKey, _key -> new ArrayList<>()); partition.add(holder); } @@ -74,6 +77,9 @@ public List> getPartitions() { } } + /** + * Partition RangeHolders by the corresponding XText. + */ public static RangePartitions partitionRanges(List holders) { RangePartitions result = new RangePartitions<>(); for (V holder : holders) { @@ -82,7 +88,7 @@ public static RangePartitions partitionRanges(List return result; } - /* + /** * Note: RangeHolder.getRange() is called many times. */ public static RangePartitions partitionAndSortRanges(List holders) { diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java index e971e7ea67c..1f39427cf43 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java @@ -4,11 +4,9 @@ import java.util.Collections; import java.util.List; -import org.jabref.model.openoffice.uno.NoDocumentException; import org.jabref.model.openoffice.uno.UnoScreenRefresh; import com.sun.star.awt.Point; -import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextDocument; import com.sun.star.text.XTextRange; import com.sun.star.text.XTextViewCursor; @@ -38,10 +36,7 @@ public class RangeSortVisual { */ public static List> visualSort(List> inputs, XTextDocument doc, - FunctionalTextViewCursor fcursor) - throws - WrappedTargetException, - NoDocumentException { + FunctionalTextViewCursor fcursor) { final int inputSize = inputs.size(); @@ -60,27 +55,19 @@ public static List> visualSort(List> input } fcursor.restore(doc); - if (positions.size() != inputSize) { - throw new IllegalStateException("visualSort: positions.size() != inputSize"); - } - // order by position - ArrayList>> set = new ArrayList<>(inputSize); + ArrayList>> comparableMarks = new ArrayList<>(inputSize); for (int i = 0; i < inputSize; i++) { RangeSortable input = inputs.get(i); - set.add(new ComparableMark<>(positions.get(i), + comparableMarks.add(new ComparableMark<>(positions.get(i), input.getIndexInPosition(), input)); } - Collections.sort(set, RangeSortVisual::compareTopToBottomLeftToRight); - - if (set.size() != inputSize) { - throw new IllegalStateException("visualSort: set.size() != inputSize"); - } + Collections.sort(comparableMarks, RangeSortVisual::compareTopToBottomLeftToRight); // collect ordered result - List> result = new ArrayList<>(set.size()); - for (ComparableMark> mark : set) { + List> result = new ArrayList<>(comparableMarks.size()); + for (ComparableMark> mark : comparableMarks) { result.add(mark.getContent()); } From bf94bf52ef4321f0add9c29949a5c7ebe114a996 Mon Sep 17 00:00:00 2001 From: Antal K Date: Fri, 9 Jul 2021 23:19:28 +0200 Subject: [PATCH 045/103] use {@code }, PMD suggestions --- .../model/openoffice/ootext/OOFormat.java | 4 + .../model/openoffice/ootext/OOText.java | 4 +- .../model/openoffice/ootext/OOTextIntoOO.java | 82 +++++++++---------- .../rangesort/RangeOverlapBetween.java | 2 +- .../rangesort/RangeOverlapWithin.java | 6 +- .../model/openoffice/rangesort/RangeSort.java | 13 ++- .../openoffice/rangesort/RangeSortEntry.java | 8 +- .../openoffice/rangesort/RangeSortVisual.java | 15 ++-- .../openoffice/rangesort/RangeSortable.java | 6 +- 9 files changed, 75 insertions(+), 65 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java index f502922f818..6b4a96de644 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java @@ -11,6 +11,10 @@ */ public class OOFormat { + private OOFormat() { + /* */ + } + /** * Mark {@code ootext} as using a character locale known to OO. * diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOText.java b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java index f5142e8dc2e..5b5fa4caba9 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOText.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java @@ -49,9 +49,9 @@ public boolean equals(Object object) { return false; } - OOText c = (OOText) object; + OOText other = (OOText) object; - return data.equals(c.data); + return data.equals(other.data); } @Override diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java index caa78f07d2c..6e61faed147 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java @@ -112,29 +112,29 @@ private OOTextIntoOO() { * * - new tags: * - * - <span lang="zxx"> + * - {@code } * - earlier was applied from code * - * - <span oo:CharStyleName="CharStylename"> + * - {@code } * - earlier was applied from code, for "CitationCharacterFormat" * - * - <p> start new paragraph + * - {@code

} start new paragraph * - earlier was applied from code * - * - <p oo:ParaStyleName="ParStyleName"> : start new paragraph and apply ParStyleName + * - {@code

} : start new paragraph and apply ParStyleName * - earlier was applied from code * - * - <tt> + * - {@code } * - earlier: known, but ignored - * - now: equivalent to <span oo:CharStyleName="Example"> - * - <oo:referenceToPageNumberOfReferenceMark> (self-closing) + * - now: equivalent to {@code } + * - {@code } (self-closing) * * - closing tags try to properly restore state (in particular, the "not directly set" state) * instead of dictating an "off" state. This makes a difference when the value inherited from * another level (for example the paragraph) is not the "off" state. * * An example: a style with - * ReferenceParagraphFormat="JR_bibentry" + * {@code ReferenceParagraphFormat="JR_bibentry"} * Assume JR_bibentry in LibreOffice is a paragraph style that prescribes "bold" font. * LAYOUT only prescribes bold around year. * Which parts of the bibliography entries should come out as bold? @@ -147,7 +147,6 @@ private OOTextIntoOO() { */ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) throws - PropertyVetoException, WrappedTargetException, CreationException { @@ -168,20 +167,19 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) // We need to extract formatting. Use a simple regexp search iteration: int piv = 0; - Matcher m = HTML_TAG.matcher(lText); - while (m.find()) { + Matcher tagMatcher = HTML_TAG.matcher(lText); + while (tagMatcher.find()) { - String currentSubstring = lText.substring(piv, m.start()); + String currentSubstring = lText.substring(piv, tagMatcher.start()); if (!currentSubstring.isEmpty()) { cursor.setString(currentSubstring); } formatStack.apply(cursor); cursor.collapseToEnd(); - String fullTag = m.group(); - String endTagName = m.group(1); - String startTagName = m.group(2); - String attributeListPart = m.group(3); + String endTagName = tagMatcher.group(1); + String startTagName = tagMatcher.group(2); + String attributeListPart = tagMatcher.group(3); boolean isStartTag = StringUtil.isNullOrEmpty(endTagName); String tagName = isStartTag ? startTagName : endTagName; Objects.requireNonNull(tagName); @@ -232,13 +230,13 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) switch (key) { case "oo:ParaStyleName": //

- if (!StringUtil.isNullOrEmpty(value)) { + if (StringUtil.isNullOrEmpty(value)) { + LOGGER.debug(String.format("oo:ParaStyleName inherited")); + } else { if (setParagraphStyle(cursor, value)) { // Presumably tested already: LOGGER.debug(String.format("oo:ParaStyleName=\"%s\" failed", value)); } - } else { - LOGGER.debug(String.format("oo:ParaStyleName inherited")); } break; default: @@ -283,7 +281,7 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) break; case "style": // HTML-style small-caps - if (value.equals("font-variant: small-caps")) { + if ("font-variant: small-caps".equals(value)) { settings.addAll(setCharCaseMap(CaseMap.SMALLCAPS)); break; } @@ -317,9 +315,12 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) currentSubstring)); } break; + default: + LOGGER.warn(String.format("ignoring unknown tag '<%s>'", tagName)); + break; } - piv = m.end(); + piv = tagMatcher.end(); } if (piv < lText.length()) { @@ -396,7 +397,7 @@ public static void removeDirectFormatting(XTextCursor cursor) { continue; } } catch (UnknownPropertyException ex) { - throw new java.lang.IllegalStateException("Unexpected UnknownPropertyException"); + throw new IllegalStateException("Unexpected UnknownPropertyException", ex); } if (knownToFail.contains(p.Name)) { continue; @@ -511,11 +512,11 @@ static class MyPropertyStack { * Get the initial state of the properties and add the first layer. */ XMultiPropertyStates mpss = UnoCast.cast(XMultiPropertyStates.class, cursor).get(); - PropertyState[] propertyStates = null; + PropertyState[] propertyStates; try { propertyStates = mpss.getPropertyStates(goodNames); } catch (UnknownPropertyException ex) { - throw new java.lang.IllegalStateException("Caught unexpected UnknownPropertyException"); + throw new IllegalStateException("Caught unexpected UnknownPropertyException", ex); } XMultiPropertySet mps = UnoCast.cast(XMultiPropertySet.class, cursor).get(); @@ -546,13 +547,13 @@ void pushLayer(List> settings) { ArrayList> newLayer = new ArrayList<>(oldLayer); for (OOPair pair : settings) { String name = pair.a; - Integer i = goodNameToIndex.get(name); - if (i == null) { + Integer index = goodNameToIndex.get(name); + if (index == null) { LOGGER.warn(String.format("pushLayer: '%s' is not in goodNameToIndex", name)); continue; } Object newValue = pair.b; - newLayer.set(i, Optional.ofNullable(newValue)); + newLayer.set(index, Optional.ofNullable(newValue)); } layers.push(newLayer); } @@ -592,8 +593,8 @@ void apply(XTextCursor cursor) { } } // namesArray must be alphabetically sorted. - String[] namesArray = names.toArray(new String[names.size()]); - String[] delNamesArray = delNames.toArray(new String[delNames.size()]); + String[] namesArray = names.toArray(new String[0]); + String[] delNamesArray = delNames.toArray(new String[0]); mpss.setPropertiesToDefault(delNamesArray); mps.setPropertyValues(namesArray, values.toArray()); } catch (UnknownPropertyException ex) { @@ -608,10 +609,9 @@ void apply(XTextCursor cursor) { // Relative CharEscapement needs to know current values. Optional getPropertyValue(String name) { if (goodNameToIndex.containsKey(name)) { - int i = goodNameToIndex.get(name); + int index = goodNameToIndex.get(name); ArrayList> topLayer = layers.peek(); - Optional value = topLayer.get(i); - return value; + return topLayer.get(index); } return Optional.empty(); } @@ -620,15 +620,15 @@ Optional getPropertyValue(String name) { /** * Parse HTML-like attributes to a list of (name,value) pairs. */ - private static List> parseAttributes(String s) { + private static List> parseAttributes(String attributes) { List> res = new ArrayList<>(); - if (s == null) { + if (attributes == null) { return res; } - Matcher m = ATTRIBUTE_PATTERN.matcher(s); - while (m.find()) { - String key = m.group(1); - String value = m.group(2); + Matcher attributeMatcher = ATTRIBUTE_PATTERN.matcher(attributes); + while (attributeMatcher.find()) { + String key = attributeMatcher.group(1); + String value = attributeMatcher.group(2); res.add(new OOPair(key, value)); } return res; @@ -690,10 +690,10 @@ private static List> setCharStrikeout(short value) { // CharStyleName private static List> setCharStyleName(String value) { List> settings = new ArrayList<>(); - if (!StringUtil.isNullOrEmpty(value)) { - settings.add(new OOPair<>(CHAR_STYLE_NAME, value)); - } else { + if (StringUtil.isNullOrEmpty(value)) { LOGGER.warn("setCharStyleName: received null or empty value"); + } else { + settings.add(new OOPair<>(CHAR_STYLE_NAME, value)); } return settings; } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java index 9a3ef1c9968..16b7735fb7a 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java @@ -31,7 +31,7 @@ List> findFirst(XTextDocument doc, List> result = new ArrayList<>(); - if (fewHolders.size() == 0) { + if (fewHolders.isEmpty()) { return result; } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java index e4df2d8278c..a8534b630ae 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java @@ -39,9 +39,7 @@ List> findOverlappingRanges(XTextDocument doc, RangeSort.RangePartitions partitions = RangeSort.partitionAndSortRanges(rangeHolders); - List> overlaps = findOverlappingRanges(partitions, reportAtMost, includeTouching); - - return overlaps; + return findOverlappingRanges(partitions, reportAtMost, includeTouching); } /** @@ -64,7 +62,7 @@ List> findOverlappingRanges(RangeSort.RangePartitions input, List> result = new ArrayList<>(); for (List partition : input.getPartitions()) { - if (partition.size() == 0) { + if (partition.isEmpty()) { continue; } XTextRangeCompare cmp = UnoCast.cast(XTextRangeCompare.class, diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java index d5024d6d8e2..99ace5154e1 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java @@ -18,20 +18,25 @@ */ public class RangeSort { + private RangeSort() { + /**/ + } + /** * Compare two RangeHolders (using RangeHolder.getRange()) within an XText. * * Note: since we only look at the ranges, this comparison is generally not consistent with * `equals` on the RangeHolders. Probably should not be used for key comparison in - * TreeMap<RangeHolder> or Set<RangeHolder> + * {@code TreeMap} or {@code Set} * */ - public static class HolderComparatorWithinPartition implements Comparator { + private static class HolderComparatorWithinPartition implements Comparator { private final XTextRangeCompare cmp; HolderComparatorWithinPartition(XText text) { - cmp = UnoCast.cast(XTextRangeCompare.class, text).get(); + cmp = (UnoCast.cast(XTextRangeCompare.class, text) + .orElseThrow(java.lang.IllegalArgumentException::new)); } /** @@ -68,7 +73,7 @@ public RangePartitions() { public void add(V holder) { XText partitionKey = holder.getRange().getText(); - List partition = partitions.computeIfAbsent(partitionKey, _key -> new ArrayList<>()); + List partition = partitions.computeIfAbsent(partitionKey, unused -> new ArrayList<>()); partition.add(holder); } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java index 4ed651e5396..0ed686ee901 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java @@ -32,11 +32,11 @@ public T getContent() { return content; } - public void setRange(XTextRange r) { - range = r; + public void setRange(XTextRange range) { + this.range = range; } - public void setIndexInPosition(int i) { - indexInPosition = i; + public void setIndexInPosition(int indexInPosition) { + this.indexInPosition = indexInPosition; } } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java index 1f39427cf43..e412f4ade6c 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java @@ -1,7 +1,6 @@ package org.jabref.model.openoffice.rangesort; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import org.jabref.model.openoffice.uno.UnoScreenRefresh; @@ -27,6 +26,10 @@ public class RangeSortVisual { private static final Logger LOGGER = LoggerFactory.getLogger(RangeSortVisual.class); + private RangeSortVisual() { + /**/ + } + /** * Sort the input {@code inputs} visually. * @@ -38,8 +41,6 @@ public static List> visualSort(List> input XTextDocument doc, FunctionalTextViewCursor fcursor) { - final int inputSize = inputs.size(); - if (UnoScreenRefresh.hasControllersLocked(doc)) { final String msg = "visualSort: with ControllersLocked, viewCursor.gotoRange is probably useless"; LOGGER.warn(msg); @@ -48,6 +49,8 @@ public static List> visualSort(List> input XTextViewCursor viewCursor = fcursor.getViewCursor(); + final int inputSize = inputs.size(); + // find coordinates List positions = new ArrayList<>(inputSize); for (RangeSortable v : inputs) { @@ -63,7 +66,7 @@ public static List> visualSort(List> input input.getIndexInPosition(), input)); } - Collections.sort(comparableMarks, RangeSortVisual::compareTopToBottomLeftToRight); + comparableMarks.sort(RangeSortVisual::compareTopToBottomLeftToRight); // collect ordered result List> result = new ArrayList<>(comparableMarks.size()); @@ -101,7 +104,7 @@ private static Point findPositionOfTextRange(XTextRange range, XTextViewCursor c return cursor.getPosition(); } - private static int compareTopToBottomLeftToRight(ComparableMark a, ComparableMark b) { + private static int compareTopToBottomLeftToRight(ComparableMark a, ComparableMark b) { if (a.position.Y != b.position.Y) { return a.position.Y - b.position.Y; @@ -111,7 +114,7 @@ private static int compareTopToBottomLeftToRight(ComparableMark a, ComparableMar } return a.indexInPosition - b.indexInPosition; } - + /** * A reference mark name paired with its visual position. * diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java index c3eab225889..59a4c3fa9af 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java @@ -11,12 +11,12 @@ public interface RangeSortable extends RangeHolder { * * For citation marks in footnotes this may be the range of the footnote mark. */ - public XTextRange getRange(); + XTextRange getRange(); /** * For citation marks in footnotes this may provide order within the footnote. */ - public int getIndexInPosition(); + int getIndexInPosition(); - public T getContent(); + T getContent(); } From b82959018f0a84d340cd648bb9581be01e3c40b7 Mon Sep 17 00:00:00 2001 From: Antal K Date: Tue, 22 Jun 2021 15:42:36 +0200 Subject: [PATCH 046/103] use StringUtil.isNullOrEmpty --- .../java/org/jabref/model/openoffice/ootext/OOFormat.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java index be5ee399e55..4bfba9e5baf 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java @@ -1,5 +1,7 @@ package org.jabref.model.openoffice.ootext; +import org.jabref.model.strings.StringUtil; + /** * Helper functions to produce some of the markup as understood by OOTextIntoOO.write * @@ -54,7 +56,7 @@ public static OOText setCharStyle(OOText ootext, String charStyle) { * Mark {@code ootext} as part of a paragraph with style {@code paraStyle} */ public static OOText paragraph(OOText ootext, String paraStyle) { - if (paraStyle == null || "".equals(paraStyle)) { + if (StringUtil.isNullOrEmpty(paraStyle)) { return paragraph(ootext); } String startTag = String.format("

", paraStyle); From 28a019a10621332e326564e4735c5dbb9f6e6680 Mon Sep 17 00:00:00 2001 From: Antal K Date: Tue, 22 Jun 2021 15:42:54 +0200 Subject: [PATCH 047/103] no natural sort for ComparableMark --- .../openoffice/rangesort/RangeSortVisual.java | 48 +++++-------------- 1 file changed, 13 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java index 969f9fed44e..e971e7ea67c 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Objects; import org.jabref.model.openoffice.uno.NoDocumentException; import org.jabref.model.openoffice.uno.UnoScreenRefresh; @@ -73,7 +72,7 @@ public static List> visualSort(List> input input.getIndexInPosition(), input)); } - Collections.sort(set); + Collections.sort(set, RangeSortVisual::compareTopToBottomLeftToRight); if (set.size() != inputSize) { throw new IllegalStateException("visualSort: set.size() != inputSize"); @@ -115,6 +114,17 @@ private static Point findPositionOfTextRange(XTextRange range, XTextViewCursor c return cursor.getPosition(); } + private static int compareTopToBottomLeftToRight(ComparableMark a, ComparableMark b) { + + if (a.position.Y != b.position.Y) { + return a.position.Y - b.position.Y; + } + if (a.position.X != b.position.X) { + return a.position.X - b.position.X; + } + return a.indexInPosition - b.indexInPosition; + } + /** * A reference mark name paired with its visual position. * @@ -123,7 +133,7 @@ private static Point findPositionOfTextRange(XTextRange range, XTextViewCursor c * * Used for sorting reference marks by their visual positions. */ - private static class ComparableMark implements Comparable> { + private static class ComparableMark { private final Point position; private final int indexInPosition; @@ -135,42 +145,10 @@ public ComparableMark(Point position, int indexInPosition, T content) { this.content = content; } - @Override - public int compareTo(ComparableMark other) { - - if (position.Y != other.position.Y) { - return position.Y - other.position.Y; - } - if (position.X != other.position.X) { - return position.X - other.position.X; - } - return indexInPosition - other.indexInPosition; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (o instanceof ComparableMark) { - ComparableMark other = (ComparableMark) o; - return ((this.position.X == other.position.X) - && (this.position.Y == other.position.Y) - && (this.indexInPosition == other.indexInPosition) - && Objects.equals(this.content, other.content)); - } - return false; - } - public T getContent() { return content; } - @Override - public int hashCode() { - return Objects.hash(position, indexInPosition, content); - } } } From 8c7ad3faa5e23faa6b8d5914d30f6d9ecff2fd0d Mon Sep 17 00:00:00 2001 From: Antal K Date: Wed, 7 Jul 2021 20:27:07 +0200 Subject: [PATCH 048/103] in response to review https://github.com/JabRef/jabref/pull/7788#pullrequestreview-698494039 - more use of StringUtil.isNullOrEmpty - private final XTextRangeCompare cmp; - List partition = partitions.computeIfAbsent(partitionKey, _key -> new ArrayList<>()); - visualSort does not throw WrappedTargetException, NoDocumentException - set renamed to comparableMarks --- .../model/openoffice/ootext/OOFormat.java | 4 +-- .../model/openoffice/ootext/OOText.java | 5 ++- .../model/openoffice/ootext/OOTextIntoOO.java | 9 ++--- .../model/openoffice/rangesort/RangeSort.java | 36 +++++++++++-------- .../openoffice/rangesort/RangeSortVisual.java | 25 ++++--------- 5 files changed, 36 insertions(+), 43 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java index 4bfba9e5baf..f502922f818 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java @@ -73,8 +73,8 @@ public static OOText paragraph(OOText ootext) { /** * Format an OO cross-reference showing the target's page number as label to a reference mark. */ - public static OOText formatReferenceToPageNumberOfReferenceMark(String referencMarkName) { - String string = String.format("", referencMarkName); + public static OOText formatReferenceToPageNumberOfReferenceMark(String referenceMarkName) { + String string = String.format("", referenceMarkName); return OOText.fromString(string); } } diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOText.java b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java index ad0b9fb448d..f5142e8dc2e 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOText.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java @@ -17,7 +17,7 @@ private OOText(String data) { this.data = data; } - /* null input is passed through */ + /** @return null for null input, otherwise the argument wrapped into a new OOText */ public static OOText fromString(String string) { if (string == null) { return null; @@ -25,7 +25,7 @@ public static OOText fromString(String string) { return new OOText(string); } - /* null input is passed through */ + /** @return null for null input, otherwise the string inside the argument */ public static String toString(OOText ootext) { if (ootext == null) { return null; @@ -38,7 +38,6 @@ public String toString() { return data; } - /* Object.equals */ @Override public boolean equals(Object object) { diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java index 0758d515446..caa78f07d2c 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java @@ -17,6 +17,7 @@ import org.jabref.model.openoffice.uno.UnoCast; import org.jabref.model.openoffice.uno.UnoCrossRef; import org.jabref.model.openoffice.util.OOPair; +import org.jabref.model.strings.StringUtil; import com.sun.star.awt.FontSlant; import com.sun.star.awt.FontStrikeout; @@ -181,7 +182,7 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) String endTagName = m.group(1); String startTagName = m.group(2); String attributeListPart = m.group(3); - boolean isStartTag = (endTagName == null) || "".equals(endTagName); + boolean isStartTag = StringUtil.isNullOrEmpty(endTagName); String tagName = isStartTag ? startTagName : endTagName; Objects.requireNonNull(tagName); @@ -231,7 +232,7 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) switch (key) { case "oo:ParaStyleName": //

- if (value != null && !value.equals("")) { + if (!StringUtil.isNullOrEmpty(value)) { if (setParagraphStyle(cursor, value)) { // Presumably tested already: LOGGER.debug(String.format("oo:ParaStyleName=\"%s\" failed", value)); @@ -689,7 +690,7 @@ private static List> setCharStrikeout(short value) { // CharStyleName private static List> setCharStyleName(String value) { List> settings = new ArrayList<>(); - if (value != null && value != "") { + if (!StringUtil.isNullOrEmpty(value)) { settings.add(new OOPair<>(CHAR_STYLE_NAME, value)); } else { LOGGER.warn("setCharStyleName: received null or empty value"); @@ -708,7 +709,7 @@ private static List> setCharLocale(Locale value) { * Locale from string encoding: language, language-country or language-country-variant */ private static List> setCharLocale(String value) { - if (value == null || "".equals(value)) { + if (StringUtil.isNullOrEmpty(value)) { throw new java.lang.IllegalArgumentException("setCharLocale \"\" or null"); } String[] parts = value.split("-"); diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java index 1b4fc327598..d5024d6d8e2 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java @@ -12,21 +12,29 @@ import com.sun.star.text.XText; import com.sun.star.text.XTextRangeCompare; +/** + * RangeSort provides sorting based on XTextRangeCompare, which only provides comparison + * between XTextRange values within the same XText. + */ public class RangeSort { - /* - * Sort within a partition + /** + * Compare two RangeHolders (using RangeHolder.getRange()) within an XText. + * + * Note: since we only look at the ranges, this comparison is generally not consistent with + * `equals` on the RangeHolders. Probably should not be used for key comparison in + * TreeMap<RangeHolder> or Set<RangeHolder> + * */ - public static class HolderComparatorWithinPartition implements Comparator { - XTextRangeCompare cmp; + private final XTextRangeCompare cmp; HolderComparatorWithinPartition(XText text) { cmp = UnoCast.cast(XTextRangeCompare.class, text).get(); } - /* + /** * Assumes a and b belong to the same XText as cmp. */ @Override @@ -35,7 +43,7 @@ public int compare(RangeHolder a, RangeHolder b) { } } - /* + /** * Sort a list of RangeHolder values known to share the same getText(). * * Note: RangeHolder.getRange() is called many times. @@ -48,10 +56,9 @@ public static void sortWithinPartition(List rangeHold rangeHolders.sort(new HolderComparatorWithinPartition(text)); } - /* - * Partitioning + /** + * Represent a partitioning of RangeHolders by XText */ - public static class RangePartitions { private final Map> partitions; @@ -61,11 +68,7 @@ public RangePartitions() { public void add(V holder) { XText partitionKey = holder.getRange().getText(); - List partition = partitions.get(partitionKey); - if (partition == null) { - partition = new ArrayList<>(); - partitions.put(partitionKey, partition); - } + List partition = partitions.computeIfAbsent(partitionKey, _key -> new ArrayList<>()); partition.add(holder); } @@ -74,6 +77,9 @@ public List> getPartitions() { } } + /** + * Partition RangeHolders by the corresponding XText. + */ public static RangePartitions partitionRanges(List holders) { RangePartitions result = new RangePartitions<>(); for (V holder : holders) { @@ -82,7 +88,7 @@ public static RangePartitions partitionRanges(List return result; } - /* + /** * Note: RangeHolder.getRange() is called many times. */ public static RangePartitions partitionAndSortRanges(List holders) { diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java index e971e7ea67c..1f39427cf43 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java @@ -4,11 +4,9 @@ import java.util.Collections; import java.util.List; -import org.jabref.model.openoffice.uno.NoDocumentException; import org.jabref.model.openoffice.uno.UnoScreenRefresh; import com.sun.star.awt.Point; -import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextDocument; import com.sun.star.text.XTextRange; import com.sun.star.text.XTextViewCursor; @@ -38,10 +36,7 @@ public class RangeSortVisual { */ public static List> visualSort(List> inputs, XTextDocument doc, - FunctionalTextViewCursor fcursor) - throws - WrappedTargetException, - NoDocumentException { + FunctionalTextViewCursor fcursor) { final int inputSize = inputs.size(); @@ -60,27 +55,19 @@ public static List> visualSort(List> input } fcursor.restore(doc); - if (positions.size() != inputSize) { - throw new IllegalStateException("visualSort: positions.size() != inputSize"); - } - // order by position - ArrayList>> set = new ArrayList<>(inputSize); + ArrayList>> comparableMarks = new ArrayList<>(inputSize); for (int i = 0; i < inputSize; i++) { RangeSortable input = inputs.get(i); - set.add(new ComparableMark<>(positions.get(i), + comparableMarks.add(new ComparableMark<>(positions.get(i), input.getIndexInPosition(), input)); } - Collections.sort(set, RangeSortVisual::compareTopToBottomLeftToRight); - - if (set.size() != inputSize) { - throw new IllegalStateException("visualSort: set.size() != inputSize"); - } + Collections.sort(comparableMarks, RangeSortVisual::compareTopToBottomLeftToRight); // collect ordered result - List> result = new ArrayList<>(set.size()); - for (ComparableMark> mark : set) { + List> result = new ArrayList<>(comparableMarks.size()); + for (ComparableMark> mark : comparableMarks) { result.add(mark.getContent()); } From 66d48a230d53977127e0a7490fab3afc1bab56ad Mon Sep 17 00:00:00 2001 From: Antal K Date: Fri, 9 Jul 2021 23:19:28 +0200 Subject: [PATCH 049/103] use {@code }, PMD suggestions --- .../model/openoffice/ootext/OOFormat.java | 4 + .../model/openoffice/ootext/OOText.java | 4 +- .../model/openoffice/ootext/OOTextIntoOO.java | 82 +++++++++---------- .../rangesort/RangeOverlapBetween.java | 2 +- .../rangesort/RangeOverlapWithin.java | 6 +- .../model/openoffice/rangesort/RangeSort.java | 13 ++- .../openoffice/rangesort/RangeSortEntry.java | 8 +- .../openoffice/rangesort/RangeSortVisual.java | 15 ++-- .../openoffice/rangesort/RangeSortable.java | 6 +- 9 files changed, 75 insertions(+), 65 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java index f502922f818..6b4a96de644 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java @@ -11,6 +11,10 @@ */ public class OOFormat { + private OOFormat() { + /* */ + } + /** * Mark {@code ootext} as using a character locale known to OO. * diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOText.java b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java index f5142e8dc2e..5b5fa4caba9 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOText.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java @@ -49,9 +49,9 @@ public boolean equals(Object object) { return false; } - OOText c = (OOText) object; + OOText other = (OOText) object; - return data.equals(c.data); + return data.equals(other.data); } @Override diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java index caa78f07d2c..6e61faed147 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java @@ -112,29 +112,29 @@ private OOTextIntoOO() { * * - new tags: * - * - <span lang="zxx"> + * - {@code } * - earlier was applied from code * - * - <span oo:CharStyleName="CharStylename"> + * - {@code } * - earlier was applied from code, for "CitationCharacterFormat" * - * - <p> start new paragraph + * - {@code

} start new paragraph * - earlier was applied from code * - * - <p oo:ParaStyleName="ParStyleName"> : start new paragraph and apply ParStyleName + * - {@code

} : start new paragraph and apply ParStyleName * - earlier was applied from code * - * - <tt> + * - {@code } * - earlier: known, but ignored - * - now: equivalent to <span oo:CharStyleName="Example"> - * - <oo:referenceToPageNumberOfReferenceMark> (self-closing) + * - now: equivalent to {@code } + * - {@code } (self-closing) * * - closing tags try to properly restore state (in particular, the "not directly set" state) * instead of dictating an "off" state. This makes a difference when the value inherited from * another level (for example the paragraph) is not the "off" state. * * An example: a style with - * ReferenceParagraphFormat="JR_bibentry" + * {@code ReferenceParagraphFormat="JR_bibentry"} * Assume JR_bibentry in LibreOffice is a paragraph style that prescribes "bold" font. * LAYOUT only prescribes bold around year. * Which parts of the bibliography entries should come out as bold? @@ -147,7 +147,6 @@ private OOTextIntoOO() { */ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) throws - PropertyVetoException, WrappedTargetException, CreationException { @@ -168,20 +167,19 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) // We need to extract formatting. Use a simple regexp search iteration: int piv = 0; - Matcher m = HTML_TAG.matcher(lText); - while (m.find()) { + Matcher tagMatcher = HTML_TAG.matcher(lText); + while (tagMatcher.find()) { - String currentSubstring = lText.substring(piv, m.start()); + String currentSubstring = lText.substring(piv, tagMatcher.start()); if (!currentSubstring.isEmpty()) { cursor.setString(currentSubstring); } formatStack.apply(cursor); cursor.collapseToEnd(); - String fullTag = m.group(); - String endTagName = m.group(1); - String startTagName = m.group(2); - String attributeListPart = m.group(3); + String endTagName = tagMatcher.group(1); + String startTagName = tagMatcher.group(2); + String attributeListPart = tagMatcher.group(3); boolean isStartTag = StringUtil.isNullOrEmpty(endTagName); String tagName = isStartTag ? startTagName : endTagName; Objects.requireNonNull(tagName); @@ -232,13 +230,13 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) switch (key) { case "oo:ParaStyleName": //

- if (!StringUtil.isNullOrEmpty(value)) { + if (StringUtil.isNullOrEmpty(value)) { + LOGGER.debug(String.format("oo:ParaStyleName inherited")); + } else { if (setParagraphStyle(cursor, value)) { // Presumably tested already: LOGGER.debug(String.format("oo:ParaStyleName=\"%s\" failed", value)); } - } else { - LOGGER.debug(String.format("oo:ParaStyleName inherited")); } break; default: @@ -283,7 +281,7 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) break; case "style": // HTML-style small-caps - if (value.equals("font-variant: small-caps")) { + if ("font-variant: small-caps".equals(value)) { settings.addAll(setCharCaseMap(CaseMap.SMALLCAPS)); break; } @@ -317,9 +315,12 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) currentSubstring)); } break; + default: + LOGGER.warn(String.format("ignoring unknown tag '<%s>'", tagName)); + break; } - piv = m.end(); + piv = tagMatcher.end(); } if (piv < lText.length()) { @@ -396,7 +397,7 @@ public static void removeDirectFormatting(XTextCursor cursor) { continue; } } catch (UnknownPropertyException ex) { - throw new java.lang.IllegalStateException("Unexpected UnknownPropertyException"); + throw new IllegalStateException("Unexpected UnknownPropertyException", ex); } if (knownToFail.contains(p.Name)) { continue; @@ -511,11 +512,11 @@ static class MyPropertyStack { * Get the initial state of the properties and add the first layer. */ XMultiPropertyStates mpss = UnoCast.cast(XMultiPropertyStates.class, cursor).get(); - PropertyState[] propertyStates = null; + PropertyState[] propertyStates; try { propertyStates = mpss.getPropertyStates(goodNames); } catch (UnknownPropertyException ex) { - throw new java.lang.IllegalStateException("Caught unexpected UnknownPropertyException"); + throw new IllegalStateException("Caught unexpected UnknownPropertyException", ex); } XMultiPropertySet mps = UnoCast.cast(XMultiPropertySet.class, cursor).get(); @@ -546,13 +547,13 @@ void pushLayer(List> settings) { ArrayList> newLayer = new ArrayList<>(oldLayer); for (OOPair pair : settings) { String name = pair.a; - Integer i = goodNameToIndex.get(name); - if (i == null) { + Integer index = goodNameToIndex.get(name); + if (index == null) { LOGGER.warn(String.format("pushLayer: '%s' is not in goodNameToIndex", name)); continue; } Object newValue = pair.b; - newLayer.set(i, Optional.ofNullable(newValue)); + newLayer.set(index, Optional.ofNullable(newValue)); } layers.push(newLayer); } @@ -592,8 +593,8 @@ void apply(XTextCursor cursor) { } } // namesArray must be alphabetically sorted. - String[] namesArray = names.toArray(new String[names.size()]); - String[] delNamesArray = delNames.toArray(new String[delNames.size()]); + String[] namesArray = names.toArray(new String[0]); + String[] delNamesArray = delNames.toArray(new String[0]); mpss.setPropertiesToDefault(delNamesArray); mps.setPropertyValues(namesArray, values.toArray()); } catch (UnknownPropertyException ex) { @@ -608,10 +609,9 @@ void apply(XTextCursor cursor) { // Relative CharEscapement needs to know current values. Optional getPropertyValue(String name) { if (goodNameToIndex.containsKey(name)) { - int i = goodNameToIndex.get(name); + int index = goodNameToIndex.get(name); ArrayList> topLayer = layers.peek(); - Optional value = topLayer.get(i); - return value; + return topLayer.get(index); } return Optional.empty(); } @@ -620,15 +620,15 @@ Optional getPropertyValue(String name) { /** * Parse HTML-like attributes to a list of (name,value) pairs. */ - private static List> parseAttributes(String s) { + private static List> parseAttributes(String attributes) { List> res = new ArrayList<>(); - if (s == null) { + if (attributes == null) { return res; } - Matcher m = ATTRIBUTE_PATTERN.matcher(s); - while (m.find()) { - String key = m.group(1); - String value = m.group(2); + Matcher attributeMatcher = ATTRIBUTE_PATTERN.matcher(attributes); + while (attributeMatcher.find()) { + String key = attributeMatcher.group(1); + String value = attributeMatcher.group(2); res.add(new OOPair(key, value)); } return res; @@ -690,10 +690,10 @@ private static List> setCharStrikeout(short value) { // CharStyleName private static List> setCharStyleName(String value) { List> settings = new ArrayList<>(); - if (!StringUtil.isNullOrEmpty(value)) { - settings.add(new OOPair<>(CHAR_STYLE_NAME, value)); - } else { + if (StringUtil.isNullOrEmpty(value)) { LOGGER.warn("setCharStyleName: received null or empty value"); + } else { + settings.add(new OOPair<>(CHAR_STYLE_NAME, value)); } return settings; } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java index 9a3ef1c9968..16b7735fb7a 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java @@ -31,7 +31,7 @@ List> findFirst(XTextDocument doc, List> result = new ArrayList<>(); - if (fewHolders.size() == 0) { + if (fewHolders.isEmpty()) { return result; } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java index e4df2d8278c..a8534b630ae 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java @@ -39,9 +39,7 @@ List> findOverlappingRanges(XTextDocument doc, RangeSort.RangePartitions partitions = RangeSort.partitionAndSortRanges(rangeHolders); - List> overlaps = findOverlappingRanges(partitions, reportAtMost, includeTouching); - - return overlaps; + return findOverlappingRanges(partitions, reportAtMost, includeTouching); } /** @@ -64,7 +62,7 @@ List> findOverlappingRanges(RangeSort.RangePartitions input, List> result = new ArrayList<>(); for (List partition : input.getPartitions()) { - if (partition.size() == 0) { + if (partition.isEmpty()) { continue; } XTextRangeCompare cmp = UnoCast.cast(XTextRangeCompare.class, diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java index d5024d6d8e2..99ace5154e1 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java @@ -18,20 +18,25 @@ */ public class RangeSort { + private RangeSort() { + /**/ + } + /** * Compare two RangeHolders (using RangeHolder.getRange()) within an XText. * * Note: since we only look at the ranges, this comparison is generally not consistent with * `equals` on the RangeHolders. Probably should not be used for key comparison in - * TreeMap<RangeHolder> or Set<RangeHolder> + * {@code TreeMap} or {@code Set} * */ - public static class HolderComparatorWithinPartition implements Comparator { + private static class HolderComparatorWithinPartition implements Comparator { private final XTextRangeCompare cmp; HolderComparatorWithinPartition(XText text) { - cmp = UnoCast.cast(XTextRangeCompare.class, text).get(); + cmp = (UnoCast.cast(XTextRangeCompare.class, text) + .orElseThrow(java.lang.IllegalArgumentException::new)); } /** @@ -68,7 +73,7 @@ public RangePartitions() { public void add(V holder) { XText partitionKey = holder.getRange().getText(); - List partition = partitions.computeIfAbsent(partitionKey, _key -> new ArrayList<>()); + List partition = partitions.computeIfAbsent(partitionKey, unused -> new ArrayList<>()); partition.add(holder); } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java index 4ed651e5396..0ed686ee901 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java @@ -32,11 +32,11 @@ public T getContent() { return content; } - public void setRange(XTextRange r) { - range = r; + public void setRange(XTextRange range) { + this.range = range; } - public void setIndexInPosition(int i) { - indexInPosition = i; + public void setIndexInPosition(int indexInPosition) { + this.indexInPosition = indexInPosition; } } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java index 1f39427cf43..e412f4ade6c 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java @@ -1,7 +1,6 @@ package org.jabref.model.openoffice.rangesort; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import org.jabref.model.openoffice.uno.UnoScreenRefresh; @@ -27,6 +26,10 @@ public class RangeSortVisual { private static final Logger LOGGER = LoggerFactory.getLogger(RangeSortVisual.class); + private RangeSortVisual() { + /**/ + } + /** * Sort the input {@code inputs} visually. * @@ -38,8 +41,6 @@ public static List> visualSort(List> input XTextDocument doc, FunctionalTextViewCursor fcursor) { - final int inputSize = inputs.size(); - if (UnoScreenRefresh.hasControllersLocked(doc)) { final String msg = "visualSort: with ControllersLocked, viewCursor.gotoRange is probably useless"; LOGGER.warn(msg); @@ -48,6 +49,8 @@ public static List> visualSort(List> input XTextViewCursor viewCursor = fcursor.getViewCursor(); + final int inputSize = inputs.size(); + // find coordinates List positions = new ArrayList<>(inputSize); for (RangeSortable v : inputs) { @@ -63,7 +66,7 @@ public static List> visualSort(List> input input.getIndexInPosition(), input)); } - Collections.sort(comparableMarks, RangeSortVisual::compareTopToBottomLeftToRight); + comparableMarks.sort(RangeSortVisual::compareTopToBottomLeftToRight); // collect ordered result List> result = new ArrayList<>(comparableMarks.size()); @@ -101,7 +104,7 @@ private static Point findPositionOfTextRange(XTextRange range, XTextViewCursor c return cursor.getPosition(); } - private static int compareTopToBottomLeftToRight(ComparableMark a, ComparableMark b) { + private static int compareTopToBottomLeftToRight(ComparableMark a, ComparableMark b) { if (a.position.Y != b.position.Y) { return a.position.Y - b.position.Y; @@ -111,7 +114,7 @@ private static int compareTopToBottomLeftToRight(ComparableMark a, ComparableMar } return a.indexInPosition - b.indexInPosition; } - + /** * A reference mark name paired with its visual position. * diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java index c3eab225889..59a4c3fa9af 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java @@ -11,12 +11,12 @@ public interface RangeSortable extends RangeHolder { * * For citation marks in footnotes this may be the range of the footnote mark. */ - public XTextRange getRange(); + XTextRange getRange(); /** * For citation marks in footnotes this may provide order within the footnote. */ - public int getIndexInPosition(); + int getIndexInPosition(); - public T getContent(); + T getContent(); } From 6d7b8a14a9d9ad4cbc9257a6b26ed5a4b6cc2c08 Mon Sep 17 00:00:00 2001 From: Antal K Date: Tue, 13 Jul 2021 11:48:42 +0200 Subject: [PATCH 050/103] update logic/style from improve-reversibility-rebased-03 --- .../style/OOBibStyleGetCitationMarker.java | 74 ++++++++++--------- .../style/OOBibStyleGetNumCitationMarker.java | 6 +- .../logic/openoffice/style/OOProcess.java | 30 +++----- .../style/OOProcessAuthorYearMarkers.java | 4 + .../style/OOProcessCitationKeyMarkers.java | 5 ++ .../style/OOProcessNumericMarkers.java | 4 + 6 files changed, 66 insertions(+), 57 deletions(-) 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 e501cd4aaaf..4235841e426 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java @@ -22,6 +22,10 @@ class OOBibStyleGetCitationMarker { + private OOBibStyleGetCitationMarker() { + /**/ + } + /** * Look up the nth author and return the "proper" last name for * citation markers. @@ -29,23 +33,23 @@ class OOBibStyleGetCitationMarker { * Note: "proper" in the sense that it includes the "von" part * of the name (followed by a space) if there is one. * - * @param al The author list. + * @param authorList The author list. * @param number The number of the author to return. * @return The author name, or an empty String if inapplicable. */ - private static String getAuthorLastName(AuthorList al, int number) { + private static String getAuthorLastName(AuthorList authorList, int number) { StringBuilder sb = new StringBuilder(); - if (al.getNumberOfAuthors() > number) { - Author a = al.getAuthor(number); + if (authorList.getNumberOfAuthors() > number) { + Author author = authorList.getAuthor(number); // "von " if von exists - Optional von = a.getVon(); + Optional von = author.getVon(); if (von.isPresent() && !von.get().isEmpty()) { sb.append(von.get()); sb.append(' '); } // last name if it exists - sb.append(a.getLast().orElse("")); + sb.append(author.getLast().orElse("")); } return sb.toString(); @@ -306,23 +310,23 @@ private enum AuthorYearMarkerPurpose { } /** - * How many authors would be emitted for ce, considering - * style and ce.getIsFirstAppearanceOfSource() + * How many authors would be emitted for entry, considering + * style and entry.getIsFirstAppearanceOfSource() * - * If ce is unresolved, return 0. + * If entry is unresolved, return 0. */ - private static int calculateNAuthorsToEmit(OOBibStyle style, CitationMarkerEntry ce) { - - int maxAuthors = (ce.getIsFirstAppearanceOfSource() - ? style.getMaxAuthorsFirst() - : style.getMaxAuthors()); + private static int calculateNAuthorsToEmit(OOBibStyle style, CitationMarkerEntry entry) { - if (ce.getLookupResult().isEmpty()) { + if (entry.getLookupResult().isEmpty()) { // unresolved return 0; } - AuthorList authorList = getAuthorList(style, ce.getLookupResult().get()); + int maxAuthors = (entry.getIsFirstAppearanceOfSource() + ? style.getMaxAuthorsFirst() + : style.getMaxAuthors()); + + AuthorList authorList = getAuthorList(style, entry.getLookupResult().get()); int nAuthors = authorList.getNumberOfAuthors(); if (maxAuthors == -1) { @@ -342,21 +346,21 @@ private static int calculateNAuthorsToEmit(OOBibStyle style, CitationMarkerEntry * ignores isFirstAppearanceOfSource (always * style.getMaxAuthors, not getMaxAuthorsFirst) * - * @param ces The list of CitationMarkerEntry values to process. + * @param entries The list of CitationMarkerEntry values to process. * * Here we do not check for duplicate entries: those * are handled by {@code getCitationMarker} by * omitting them from the list. * * Unresolved citations recognized by - * ce.getBibEntry() and/or - * ce.getDatabase() returning empty, and + * entry.getBibEntry() and/or + * entry.getDatabase() returning empty, and * emitted as "Unresolved${citationKey}". * * Neither uniqueLetter nor pageInfo are emitted * for unresolved citations. * - * @param startsNewGroup Should have the same length as {@code ces}, and + * @param startsNewGroup Should have the same length as {@code entries}, and * contain true for entries starting a new group, * false for those that only add a uniqueLetter to * the grouped presentation. @@ -370,7 +374,7 @@ private static int calculateNAuthorsToEmit(OOBibStyle style, CitationMarkerEntry */ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, AuthorYearMarkerPurpose purpose, - List ces, + List entries, boolean[] startsNewGroup, Optional maxAuthorsOverride) { @@ -409,14 +413,14 @@ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, sb.append(startBrace); // shared parenthesis } - for (int j = 0; j < ces.size(); j++) { - CitationMarkerEntry ce = ces.get(j); + for (int j = 0; j < entries.size(); j++) { + CitationMarkerEntry entry = entries.get(j); boolean startingNewGroup = startsNewGroup[j]; - boolean endingAGroup = (j + 1 == ces.size()) || startsNewGroup[j + 1]; + boolean endingAGroup = (j + 1 == entries.size()) || startsNewGroup[j + 1]; if (!startingNewGroup) { // Just add our uniqueLetter - String uniqueLetter = ce.getUniqueLetter().orElse(null); + String uniqueLetter = entry.getUniqueLetter().orElse(null); if (uniqueLetter != null) { sb.append(uniquefierSeparator); sb.append(uniqueLetter); @@ -436,26 +440,26 @@ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, StringBuilder pageInfoPart = new StringBuilder(""); if (purpose != AuthorYearMarkerPurpose.NORMALIZED) { Optional pageInfo = - PageInfo.normalizePageInfo(ce.getPageInfo()); + PageInfo.normalizePageInfo(entry.getPageInfo()); if (pageInfo.isPresent()) { pageInfoPart.append(pageInfoSeparator); pageInfoPart.append(OOText.toString(pageInfo.get())); } } - final boolean isUnresolved = ce.getLookupResult().isEmpty(); + final boolean isUnresolved = entry.getLookupResult().isEmpty(); if (isUnresolved) { - sb.append(String.format("Unresolved(%s)", ce.getCitationKey())); + sb.append(String.format("Unresolved(%s)", entry.getCitationKey())); if (purpose != AuthorYearMarkerPurpose.NORMALIZED) { sb.append(pageInfoPart); } } else { - CitationLookupResult db = ce.getLookupResult().get(); + CitationLookupResult db = entry.getLookupResult().get(); int maxAuthors = (purpose == AuthorYearMarkerPurpose.NORMALIZED ? style.getMaxAuthors() - : calculateNAuthorsToEmit(style, ce)); + : calculateNAuthorsToEmit(style, entry)); if (maxAuthorsOverride.isPresent()) { maxAuthors = maxAuthorsOverride.get(); @@ -476,7 +480,7 @@ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, } if (purpose != AuthorYearMarkerPurpose.NORMALIZED) { - String uniqueLetter = ce.getUniqueLetter().orElse(null); + String uniqueLetter = entry.getUniqueLetter().orElse(null); if (uniqueLetter != null) { sb.append(uniqueLetter); } @@ -547,10 +551,10 @@ static OOText getNormalizedCitationMarker(OOBibStyle style, CitationMarkerNormEntry cne, Optional maxAuthorsOverride) { boolean[] startsNewGroup = {true}; - CitationMarkerEntry ce = new CitationMarkerNormEntryWrap(cne); + CitationMarkerEntry entry = new CitationMarkerNormEntryWrap(cne); return getAuthorYearParenthesisMarker2(style, AuthorYearMarkerPurpose.NORMALIZED, - Collections.singletonList(ce), + Collections.singletonList(entry), startsNewGroup, maxAuthorsOverride); } @@ -630,8 +634,8 @@ static OOText getNormalizedCitationMarker(OOBibStyle style, int[] nAuthorsToEmit = new int[nEntries]; int[] nAuthorsToEmitRevised = new int[nEntries]; for (int i = 0; i < nEntries; i++) { - CitationMarkerEntry ce = citationMarkerEntries.get(i); - int n = calculateNAuthorsToEmit(style, ce); + CitationMarkerEntry entry = citationMarkerEntries.get(i); + int n = calculateNAuthorsToEmit(style, entry); nAuthorsToEmit[i] = n; nAuthorsToEmitRevised[i] = n; } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java index 8d8422fbc51..5dce4e8caa1 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java @@ -17,6 +17,10 @@ class OOBibStyleGetNumCitationMarker { */ public final static int UNRESOLVED_ENTRY_NUMBER = 0; + private OOBibStyleGetNumCitationMarker() { + /**/ + } + /** * Defines sort order for CitationMarkerNumericEntry. */ @@ -223,7 +227,7 @@ public static OOText getNumCitationMarker2(OOBibStyle style, throw new IllegalArgumentException("getNumCitationMarker2: found negative number"); } - if (currentBlock.size() == 0) { + if (currentBlock.isEmpty()) { currentBlock.add(current); } else { CitationMarkerNumericEntry prev = currentBlock.get(currentBlock.size() - 1); diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java index 05475fcdfac..f8f7de6c7b7 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java @@ -1,6 +1,5 @@ package org.jabref.logic.openoffice.style; -import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -11,37 +10,26 @@ import org.jabref.model.entry.field.StandardField; import org.jabref.model.openoffice.style.CitationGroups; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class OOProcess { static final Comparator AUTHOR_YEAR_TITLE_COMPARATOR = makeAuthorYearTitleComparator(); static final Comparator YEAR_AUTHOR_TITLE_COMPARATOR = makeYearAuthorTitleComparator(); - private static final Logger LOGGER = LoggerFactory.getLogger(OOProcess.class); + private OOProcess() { + /**/ + } private static Comparator makeAuthorYearTitleComparator() { - FieldComparator a = new FieldComparator(StandardField.AUTHOR); - FieldComparator y = new FieldComparator(StandardField.YEAR); - FieldComparator t = new FieldComparator(StandardField.TITLE); - - List> ayt = new ArrayList<>(3); - ayt.add(a); - ayt.add(y); - ayt.add(t); + List> ayt = List.of(new FieldComparator(StandardField.AUTHOR), + new FieldComparator(StandardField.YEAR), + new FieldComparator(StandardField.TITLE)); return new FieldComparatorStack<>(ayt); } private static Comparator makeYearAuthorTitleComparator() { - FieldComparator y = new FieldComparator(StandardField.YEAR); - FieldComparator a = new FieldComparator(StandardField.AUTHOR); - FieldComparator t = new FieldComparator(StandardField.TITLE); - - List> yat = new ArrayList<>(3); - yat.add(y); - yat.add(a); - yat.add(t); + List> yat = List.of(new FieldComparator(StandardField.YEAR), + new FieldComparator(StandardField.AUTHOR), + new FieldComparator(StandardField.TITLE)); return new FieldComparatorStack<>(yat); } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java index a55d59107a8..cbd03cd79c6 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java @@ -21,6 +21,10 @@ class OOProcessAuthorYearMarkers { + private OOProcessAuthorYearMarkers() { + /**/ + } + /** * Fills {@code sortedCitedKeys//normCitMarker} */ diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java index c63a4b3d0e4..9789d6c6caa 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java @@ -9,6 +9,11 @@ import org.jabref.model.openoffice.util.OOListUtil; class OOProcessCitationKeyMarkers { + + private OOProcessCitationKeyMarkers() { + /**/ + } + /** * Produce citation markers for the case when the citation * markers are the citation keys themselves, separated by commas. diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java index 4023ed0e028..589ebfb7a48 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java @@ -11,6 +11,10 @@ class OOProcessNumericMarkers { + private OOProcessNumericMarkers() { + /**/ + } + /** * Produce citation markers for the case of numbered citations * with bibliography sorted by first appearance in the text. From cb0ca45029391cf97bac17b1ffe44b7e23d552df Mon Sep 17 00:00:00 2001 From: Antal K Date: Tue, 13 Jul 2021 11:35:16 +0200 Subject: [PATCH 051/103] update model/style from improve-reversibility-rebased-03 --- .../model/openoffice/style/Citation.java | 30 +++++----- .../model/openoffice/style/CitationGroup.java | 4 +- .../openoffice/style/CitationGroups.java | 59 +++++++++---------- .../style/CitationLookupResult.java | 8 +-- .../model/openoffice/style/CitedKey.java | 8 +-- .../openoffice/style/ComparableCitation.java | 2 +- .../openoffice/style/ComparableCitedKey.java | 4 +- .../openoffice/style/CompareCitedKey.java | 6 +- .../model/openoffice/style/OODataModel.java | 4 +- .../model/openoffice/style/PageInfo.java | 11 ++-- 10 files changed, 67 insertions(+), 69 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/style/Citation.java b/src/main/java/org/jabref/model/openoffice/style/Citation.java index 3f949237e07..9b71a1051b2 100644 --- a/src/main/java/org/jabref/model/openoffice/style/Citation.java +++ b/src/main/java/org/jabref/model/openoffice/style/Citation.java @@ -93,8 +93,8 @@ public Optional getNumber() { return number; } - public void setNumber(Optional n) { - number = n; + public void setNumber(Optional number) { + this.number = number; } public int getNumberOrThrow() { @@ -109,12 +109,12 @@ public void setUniqueLetter(Optional uniqueLetter) { this.uniqueLetter = uniqueLetter; } - public void setPageInfo(Optional v) { - Optional vv = PageInfo.normalizePageInfo(v); - if (!vv.equals(v)) { + public void setPageInfo(Optional pageInfo) { + Optional normalizedPageInfo = PageInfo.normalizePageInfo(pageInfo); + if (!normalizedPageInfo.equals(pageInfo)) { throw new IllegalArgumentException("setPageInfo argument is not normalized"); } - this.pageInfo = vv; + this.pageInfo = normalizedPageInfo; } public void setIsFirstAppearanceOfSource(boolean value) { @@ -124,19 +124,19 @@ public void setIsFirstAppearanceOfSource(boolean value) { /* * Setters for CitationGroups.distribute() */ - public static void setLookupResult(OOPair> x) { - Citation cit = x.a; - cit.db = x.b; + public static void setLookupResult(OOPair> pair) { + Citation cit = pair.a; + cit.db = pair.b; } - public static void setNumber(OOPair> x) { - Citation cit = x.a; - cit.number = x.b; + public static void setNumber(OOPair> pair) { + Citation cit = pair.a; + cit.number = pair.b; } - public static void setUniqueLetter(OOPair> x) { - Citation cit = x.a; - cit.uniqueLetter = x.b; + public static void setUniqueLetter(OOPair> pair) { + Citation cit = pair.a; + cit.uniqueLetter = pair.b; } } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java index 2986a6f4501..3b9021eb73f 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java @@ -121,8 +121,8 @@ public List getCitationsInLocalOrder() { * indexInGlobalOrder */ - public void setIndexInGlobalOrder(Optional i) { - this.indexInGlobalOrder = i; + public void setIndexInGlobalOrder(Optional indexInGlobalOrder) { + this.indexInGlobalOrder = indexInGlobalOrder; } public Optional getIndexInGlobalOrder() { diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java index bd0cca64e13..0bfe4a832d0 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java @@ -79,29 +79,28 @@ public void lookupCitations(List databases) { /* * It is not clear which of the two solutions below is better. */ - if (true) { - // collect-lookup-distribute - // - // CitationDatabaseLookupResult for the same citation key is the same object. Until we - // insert a new citation from the GUI. - CitedKeys cks = getCitedKeysUnordered(); - cks.lookupInDatabases(databases); - cks.distributeLookupResults(this); - } else { - // lookup each citation directly - // - // CitationDatabaseLookupResult for the same citation key may be a different object: - // CitedKey.addPath has to use equals, so CitationDatabaseLookupResult has to override - // Object.equals, which depends on BibEntry.equals and BibDatabase.equals doing the - // right thing. Seems to work. But what we gained from avoiding collect-and-distribute - // may be lost in more complicated consistency checking in addPath. - // - for (CitationGroup cg : getCitationGroupsUnordered()) { - for (Citation cit : cg.citationsInStorageOrder) { - cit.lookupInDatabases(databases); - } - } - } + + // (1) collect-lookup-distribute + // + // CitationDatabaseLookupResult for the same citation key is the same object. Until we + // insert a new citation from the GUI. + CitedKeys cks = getCitedKeysUnordered(); + cks.lookupInDatabases(databases); + cks.distributeLookupResults(this); + + // (2) lookup each citation directly + // + // CitationDatabaseLookupResult for the same citation key may be a different object: + // CitedKey.addPath has to use equals, so CitationDatabaseLookupResult has to override + // Object.equals, which depends on BibEntry.equals and BibDatabase.equals doing the + // right thing. Seems to work. But what we gained from avoiding collect-and-distribute + // may be lost in more complicated consistency checking in addPath. + // + /// for (CitationGroup cg : getCitationGroupsUnordered()) { + /// for (Citation cit : cg.citationsInStorageOrder) { + /// cit.lookupInDatabases(databases); + /// } + /// } } public List getCitationGroupsUnordered() { @@ -162,11 +161,11 @@ public CitedKeys getCitedKeysUnordered() { int storageIndexInGroup = 0; for (Citation cit : cg.citationsInStorageOrder) { String key = cit.citationKey; - CitationPath p = new CitationPath(cg.cgid, storageIndexInGroup); + CitationPath path = new CitationPath(cg.cgid, storageIndexInGroup); if (res.containsKey(key)) { - res.get(key).addPath(p, cit); + res.get(key).addPath(path, cit); } else { - res.put(key, new CitedKey(key, p, cit)); + res.put(key, new CitedKey(key, path, cit)); } storageIndexInGroup++; } @@ -178,19 +177,19 @@ public CitedKeys getCitedKeysUnordered() { * CitedKeys created iterating citations in (globalOrder,localOrder) */ public CitedKeys getCitedKeysSortedInOrderOfAppearance() { - LinkedHashMap res = new LinkedHashMap<>(); if (!hasGlobalOrder()) { throw new IllegalStateException("getSortedCitedKeys: no globalOrder"); } + LinkedHashMap res = new LinkedHashMap<>(); for (CitationGroup cg : getCitationGroupsInGlobalOrder()) { for (int i : cg.getLocalOrder()) { Citation cit = cg.citationsInStorageOrder.get(i); String citationKey = cit.citationKey; - CitationPath p = new CitationPath(cg.cgid, i); + CitationPath path = new CitationPath(cg.cgid, i); if (res.containsKey(citationKey)) { - res.get(citationKey).addPath(p, cit); + res.get(citationKey).addPath(path, cit); } else { - res.put(citationKey, new CitedKey(citationKey, p, cit)); + res.put(citationKey, new CitedKey(citationKey, path, cit)); } } } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java b/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java index b17ec100ee2..86674583d1c 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java @@ -26,14 +26,14 @@ public CitationLookupResult(BibEntry entry, BibDatabase database) { * Since within each GUI call we use a fixed list of databases, it is OK. */ @Override - public boolean equals(Object o) { - if (o == this) { + public boolean equals(Object otherObject) { + if (otherObject == this) { return true; } - if (!(o instanceof CitationLookupResult)) { + if (!(otherObject instanceof CitationLookupResult)) { return false; } - CitationLookupResult that = (CitationLookupResult) o; + CitationLookupResult that = (CitationLookupResult) otherObject; return this.entry.equals(that.entry) && this.database.equals(that.database); } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java index f577867c539..785d828ce7e 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java @@ -27,11 +27,11 @@ public class CitedKey implements private Optional uniqueLetter; // For AuthorYear citation styles. private Optional normCitMarker; // For AuthorYear citation styles. - CitedKey(String citationKey, CitationPath p, Citation cit) { + CitedKey(String citationKey, CitationPath path, Citation cit) { this.citationKey = citationKey; this.where = new ArrayList<>(); // remember order - this.where.add(p); + this.where.add(path); // synchronized with Citation this.db = cit.getLookupResult(); @@ -100,8 +100,8 @@ public void setNormalizedCitationMarker(Optional normCitMarker) { /** * Appends to end of {@code where} */ - void addPath(CitationPath p, Citation cit) { - this.where.add(p); + void addPath(CitationPath path, Citation cit) { + this.where.add(path); // Check consistency if (!cit.getLookupResult().equals(this.db)) { diff --git a/src/main/java/org/jabref/model/openoffice/style/ComparableCitation.java b/src/main/java/org/jabref/model/openoffice/style/ComparableCitation.java index a6ac799b017..81120c09b2a 100644 --- a/src/main/java/org/jabref/model/openoffice/style/ComparableCitation.java +++ b/src/main/java/org/jabref/model/openoffice/style/ComparableCitation.java @@ -9,5 +9,5 @@ * Otherwise we sort citations as cited keys. */ public interface ComparableCitation extends ComparableCitedKey { - public Optional getPageInfo(); + Optional getPageInfo(); } diff --git a/src/main/java/org/jabref/model/openoffice/style/ComparableCitedKey.java b/src/main/java/org/jabref/model/openoffice/style/ComparableCitedKey.java index 0d4c8e2efce..23b3ffaba78 100644 --- a/src/main/java/org/jabref/model/openoffice/style/ComparableCitedKey.java +++ b/src/main/java/org/jabref/model/openoffice/style/ComparableCitedKey.java @@ -9,8 +9,8 @@ */ public interface ComparableCitedKey { - public String getCitationKey(); + String getCitationKey(); - public Optional getBibEntry(); + Optional getBibEntry(); } diff --git a/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java b/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java index a5484560316..7f6d3adfab0 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java +++ b/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java @@ -24,18 +24,16 @@ public int compare(ComparableCitedKey a, ComparableCitedKey b) { Optional bBibEntry = b.getBibEntry(); final int mul = unresolvedComesFirst ? (+1) : (-1); - int res = 0; if (aBibEntry.isEmpty() && bBibEntry.isEmpty()) { // Both are unresolved: compare them by citation key. - res = a.getCitationKey().compareTo(b.getCitationKey()); + return a.getCitationKey().compareTo(b.getCitationKey()); } else if (aBibEntry.isEmpty()) { return -mul; } else if (bBibEntry.isEmpty()) { return mul; } else { // Proper comparison of entries - res = entryComparator.compare(aBibEntry.get(), bBibEntry.get()); + return entryComparator.compare(aBibEntry.get(), bBibEntry.get()); } - return res; } } diff --git a/src/main/java/org/jabref/model/openoffice/style/OODataModel.java b/src/main/java/org/jabref/model/openoffice/style/OODataModel.java index 20b2365ebf2..835715dfca5 100644 --- a/src/main/java/org/jabref/model/openoffice/style/OODataModel.java +++ b/src/main/java/org/jabref/model/openoffice/style/OODataModel.java @@ -26,8 +26,8 @@ public static List> fakePageInfos(String pageInfo, int nCitatio } if (pageInfo != null) { final int last = nCitations - 1; - Optional pi = Optional.ofNullable(OOText.fromString(pageInfo)); - pageInfos.set(last, PageInfo.normalizePageInfo(pi)); + Optional optionalPageInfo = Optional.ofNullable(OOText.fromString(pageInfo)); + pageInfos.set(last, PageInfo.normalizePageInfo(optionalPageInfo)); } return pageInfos; } diff --git a/src/main/java/org/jabref/model/openoffice/style/PageInfo.java b/src/main/java/org/jabref/model/openoffice/style/PageInfo.java index ace7eedae02..ec3a8436dcf 100644 --- a/src/main/java/org/jabref/model/openoffice/style/PageInfo.java +++ b/src/main/java/org/jabref/model/openoffice/style/PageInfo.java @@ -13,15 +13,16 @@ private PageInfo() { /* * pageInfo normalization */ - public static Optional normalizePageInfo(Optional o) { - if (o == null || o.isEmpty() || "".equals(OOText.toString(o.get()))) { + public static Optional normalizePageInfo(Optional optionalText) { + if (optionalText == null || optionalText.isEmpty() || "".equals(OOText.toString(optionalText.get()))) { return Optional.empty(); } - String s = OOText.toString(o.get()); - if (s.trim().equals("")) { + String str = OOText.toString(optionalText.get()); + String trimmed = str.trim(); + if (trimmed.equals("")) { return Optional.empty(); } - return Optional.of(OOText.fromString(s.trim())); + return Optional.of(OOText.fromString(trimmed)); } /** From a60211b653fcdd002d2dc916c679f548f7afc8d8 Mon Sep 17 00:00:00 2001 From: Antal K Date: Tue, 13 Jul 2021 11:48:42 +0200 Subject: [PATCH 052/103] update logic/style from improve-reversibility-rebased-03 --- .../style/OOBibStyleGetCitationMarker.java | 74 ++++++++++--------- .../style/OOBibStyleGetNumCitationMarker.java | 6 +- .../logic/openoffice/style/OOProcess.java | 30 +++----- .../style/OOProcessAuthorYearMarkers.java | 4 + .../style/OOProcessCitationKeyMarkers.java | 5 ++ .../style/OOProcessNumericMarkers.java | 4 + 6 files changed, 66 insertions(+), 57 deletions(-) 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 e501cd4aaaf..4235841e426 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java @@ -22,6 +22,10 @@ class OOBibStyleGetCitationMarker { + private OOBibStyleGetCitationMarker() { + /**/ + } + /** * Look up the nth author and return the "proper" last name for * citation markers. @@ -29,23 +33,23 @@ class OOBibStyleGetCitationMarker { * Note: "proper" in the sense that it includes the "von" part * of the name (followed by a space) if there is one. * - * @param al The author list. + * @param authorList The author list. * @param number The number of the author to return. * @return The author name, or an empty String if inapplicable. */ - private static String getAuthorLastName(AuthorList al, int number) { + private static String getAuthorLastName(AuthorList authorList, int number) { StringBuilder sb = new StringBuilder(); - if (al.getNumberOfAuthors() > number) { - Author a = al.getAuthor(number); + if (authorList.getNumberOfAuthors() > number) { + Author author = authorList.getAuthor(number); // "von " if von exists - Optional von = a.getVon(); + Optional von = author.getVon(); if (von.isPresent() && !von.get().isEmpty()) { sb.append(von.get()); sb.append(' '); } // last name if it exists - sb.append(a.getLast().orElse("")); + sb.append(author.getLast().orElse("")); } return sb.toString(); @@ -306,23 +310,23 @@ private enum AuthorYearMarkerPurpose { } /** - * How many authors would be emitted for ce, considering - * style and ce.getIsFirstAppearanceOfSource() + * How many authors would be emitted for entry, considering + * style and entry.getIsFirstAppearanceOfSource() * - * If ce is unresolved, return 0. + * If entry is unresolved, return 0. */ - private static int calculateNAuthorsToEmit(OOBibStyle style, CitationMarkerEntry ce) { - - int maxAuthors = (ce.getIsFirstAppearanceOfSource() - ? style.getMaxAuthorsFirst() - : style.getMaxAuthors()); + private static int calculateNAuthorsToEmit(OOBibStyle style, CitationMarkerEntry entry) { - if (ce.getLookupResult().isEmpty()) { + if (entry.getLookupResult().isEmpty()) { // unresolved return 0; } - AuthorList authorList = getAuthorList(style, ce.getLookupResult().get()); + int maxAuthors = (entry.getIsFirstAppearanceOfSource() + ? style.getMaxAuthorsFirst() + : style.getMaxAuthors()); + + AuthorList authorList = getAuthorList(style, entry.getLookupResult().get()); int nAuthors = authorList.getNumberOfAuthors(); if (maxAuthors == -1) { @@ -342,21 +346,21 @@ private static int calculateNAuthorsToEmit(OOBibStyle style, CitationMarkerEntry * ignores isFirstAppearanceOfSource (always * style.getMaxAuthors, not getMaxAuthorsFirst) * - * @param ces The list of CitationMarkerEntry values to process. + * @param entries The list of CitationMarkerEntry values to process. * * Here we do not check for duplicate entries: those * are handled by {@code getCitationMarker} by * omitting them from the list. * * Unresolved citations recognized by - * ce.getBibEntry() and/or - * ce.getDatabase() returning empty, and + * entry.getBibEntry() and/or + * entry.getDatabase() returning empty, and * emitted as "Unresolved${citationKey}". * * Neither uniqueLetter nor pageInfo are emitted * for unresolved citations. * - * @param startsNewGroup Should have the same length as {@code ces}, and + * @param startsNewGroup Should have the same length as {@code entries}, and * contain true for entries starting a new group, * false for those that only add a uniqueLetter to * the grouped presentation. @@ -370,7 +374,7 @@ private static int calculateNAuthorsToEmit(OOBibStyle style, CitationMarkerEntry */ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, AuthorYearMarkerPurpose purpose, - List ces, + List entries, boolean[] startsNewGroup, Optional maxAuthorsOverride) { @@ -409,14 +413,14 @@ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, sb.append(startBrace); // shared parenthesis } - for (int j = 0; j < ces.size(); j++) { - CitationMarkerEntry ce = ces.get(j); + for (int j = 0; j < entries.size(); j++) { + CitationMarkerEntry entry = entries.get(j); boolean startingNewGroup = startsNewGroup[j]; - boolean endingAGroup = (j + 1 == ces.size()) || startsNewGroup[j + 1]; + boolean endingAGroup = (j + 1 == entries.size()) || startsNewGroup[j + 1]; if (!startingNewGroup) { // Just add our uniqueLetter - String uniqueLetter = ce.getUniqueLetter().orElse(null); + String uniqueLetter = entry.getUniqueLetter().orElse(null); if (uniqueLetter != null) { sb.append(uniquefierSeparator); sb.append(uniqueLetter); @@ -436,26 +440,26 @@ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, StringBuilder pageInfoPart = new StringBuilder(""); if (purpose != AuthorYearMarkerPurpose.NORMALIZED) { Optional pageInfo = - PageInfo.normalizePageInfo(ce.getPageInfo()); + PageInfo.normalizePageInfo(entry.getPageInfo()); if (pageInfo.isPresent()) { pageInfoPart.append(pageInfoSeparator); pageInfoPart.append(OOText.toString(pageInfo.get())); } } - final boolean isUnresolved = ce.getLookupResult().isEmpty(); + final boolean isUnresolved = entry.getLookupResult().isEmpty(); if (isUnresolved) { - sb.append(String.format("Unresolved(%s)", ce.getCitationKey())); + sb.append(String.format("Unresolved(%s)", entry.getCitationKey())); if (purpose != AuthorYearMarkerPurpose.NORMALIZED) { sb.append(pageInfoPart); } } else { - CitationLookupResult db = ce.getLookupResult().get(); + CitationLookupResult db = entry.getLookupResult().get(); int maxAuthors = (purpose == AuthorYearMarkerPurpose.NORMALIZED ? style.getMaxAuthors() - : calculateNAuthorsToEmit(style, ce)); + : calculateNAuthorsToEmit(style, entry)); if (maxAuthorsOverride.isPresent()) { maxAuthors = maxAuthorsOverride.get(); @@ -476,7 +480,7 @@ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, } if (purpose != AuthorYearMarkerPurpose.NORMALIZED) { - String uniqueLetter = ce.getUniqueLetter().orElse(null); + String uniqueLetter = entry.getUniqueLetter().orElse(null); if (uniqueLetter != null) { sb.append(uniqueLetter); } @@ -547,10 +551,10 @@ static OOText getNormalizedCitationMarker(OOBibStyle style, CitationMarkerNormEntry cne, Optional maxAuthorsOverride) { boolean[] startsNewGroup = {true}; - CitationMarkerEntry ce = new CitationMarkerNormEntryWrap(cne); + CitationMarkerEntry entry = new CitationMarkerNormEntryWrap(cne); return getAuthorYearParenthesisMarker2(style, AuthorYearMarkerPurpose.NORMALIZED, - Collections.singletonList(ce), + Collections.singletonList(entry), startsNewGroup, maxAuthorsOverride); } @@ -630,8 +634,8 @@ static OOText getNormalizedCitationMarker(OOBibStyle style, int[] nAuthorsToEmit = new int[nEntries]; int[] nAuthorsToEmitRevised = new int[nEntries]; for (int i = 0; i < nEntries; i++) { - CitationMarkerEntry ce = citationMarkerEntries.get(i); - int n = calculateNAuthorsToEmit(style, ce); + CitationMarkerEntry entry = citationMarkerEntries.get(i); + int n = calculateNAuthorsToEmit(style, entry); nAuthorsToEmit[i] = n; nAuthorsToEmitRevised[i] = n; } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java index 8d8422fbc51..5dce4e8caa1 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java @@ -17,6 +17,10 @@ class OOBibStyleGetNumCitationMarker { */ public final static int UNRESOLVED_ENTRY_NUMBER = 0; + private OOBibStyleGetNumCitationMarker() { + /**/ + } + /** * Defines sort order for CitationMarkerNumericEntry. */ @@ -223,7 +227,7 @@ public static OOText getNumCitationMarker2(OOBibStyle style, throw new IllegalArgumentException("getNumCitationMarker2: found negative number"); } - if (currentBlock.size() == 0) { + if (currentBlock.isEmpty()) { currentBlock.add(current); } else { CitationMarkerNumericEntry prev = currentBlock.get(currentBlock.size() - 1); diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java index 05475fcdfac..f8f7de6c7b7 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java @@ -1,6 +1,5 @@ package org.jabref.logic.openoffice.style; -import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -11,37 +10,26 @@ import org.jabref.model.entry.field.StandardField; import org.jabref.model.openoffice.style.CitationGroups; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class OOProcess { static final Comparator AUTHOR_YEAR_TITLE_COMPARATOR = makeAuthorYearTitleComparator(); static final Comparator YEAR_AUTHOR_TITLE_COMPARATOR = makeYearAuthorTitleComparator(); - private static final Logger LOGGER = LoggerFactory.getLogger(OOProcess.class); + private OOProcess() { + /**/ + } private static Comparator makeAuthorYearTitleComparator() { - FieldComparator a = new FieldComparator(StandardField.AUTHOR); - FieldComparator y = new FieldComparator(StandardField.YEAR); - FieldComparator t = new FieldComparator(StandardField.TITLE); - - List> ayt = new ArrayList<>(3); - ayt.add(a); - ayt.add(y); - ayt.add(t); + List> ayt = List.of(new FieldComparator(StandardField.AUTHOR), + new FieldComparator(StandardField.YEAR), + new FieldComparator(StandardField.TITLE)); return new FieldComparatorStack<>(ayt); } private static Comparator makeYearAuthorTitleComparator() { - FieldComparator y = new FieldComparator(StandardField.YEAR); - FieldComparator a = new FieldComparator(StandardField.AUTHOR); - FieldComparator t = new FieldComparator(StandardField.TITLE); - - List> yat = new ArrayList<>(3); - yat.add(y); - yat.add(a); - yat.add(t); + List> yat = List.of(new FieldComparator(StandardField.YEAR), + new FieldComparator(StandardField.AUTHOR), + new FieldComparator(StandardField.TITLE)); return new FieldComparatorStack<>(yat); } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java index a55d59107a8..cbd03cd79c6 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java @@ -21,6 +21,10 @@ class OOProcessAuthorYearMarkers { + private OOProcessAuthorYearMarkers() { + /**/ + } + /** * Fills {@code sortedCitedKeys//normCitMarker} */ diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java index c63a4b3d0e4..9789d6c6caa 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java @@ -9,6 +9,11 @@ import org.jabref.model.openoffice.util.OOListUtil; class OOProcessCitationKeyMarkers { + + private OOProcessCitationKeyMarkers() { + /**/ + } + /** * Produce citation markers for the case when the citation * markers are the citation keys themselves, separated by commas. diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java index 4023ed0e028..589ebfb7a48 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java @@ -11,6 +11,10 @@ class OOProcessNumericMarkers { + private OOProcessNumericMarkers() { + /**/ + } + /** * Produce citation markers for the case of numbered citations * with bibliography sorted by first appearance in the text. From da0ae0a07d255ff377de0e69675367b1a80fffce Mon Sep 17 00:00:00 2001 From: Antal K Date: Tue, 13 Jul 2021 11:35:16 +0200 Subject: [PATCH 053/103] update model/style from improve-reversibility-rebased-03 --- .../model/openoffice/style/Citation.java | 30 +++++----- .../model/openoffice/style/CitationGroup.java | 4 +- .../openoffice/style/CitationGroups.java | 59 +++++++++---------- .../style/CitationLookupResult.java | 8 +-- .../model/openoffice/style/CitedKey.java | 8 +-- .../openoffice/style/ComparableCitation.java | 2 +- .../openoffice/style/ComparableCitedKey.java | 4 +- .../openoffice/style/CompareCitedKey.java | 6 +- .../model/openoffice/style/OODataModel.java | 4 +- .../model/openoffice/style/PageInfo.java | 11 ++-- 10 files changed, 67 insertions(+), 69 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/style/Citation.java b/src/main/java/org/jabref/model/openoffice/style/Citation.java index 3f949237e07..9b71a1051b2 100644 --- a/src/main/java/org/jabref/model/openoffice/style/Citation.java +++ b/src/main/java/org/jabref/model/openoffice/style/Citation.java @@ -93,8 +93,8 @@ public Optional getNumber() { return number; } - public void setNumber(Optional n) { - number = n; + public void setNumber(Optional number) { + this.number = number; } public int getNumberOrThrow() { @@ -109,12 +109,12 @@ public void setUniqueLetter(Optional uniqueLetter) { this.uniqueLetter = uniqueLetter; } - public void setPageInfo(Optional v) { - Optional vv = PageInfo.normalizePageInfo(v); - if (!vv.equals(v)) { + public void setPageInfo(Optional pageInfo) { + Optional normalizedPageInfo = PageInfo.normalizePageInfo(pageInfo); + if (!normalizedPageInfo.equals(pageInfo)) { throw new IllegalArgumentException("setPageInfo argument is not normalized"); } - this.pageInfo = vv; + this.pageInfo = normalizedPageInfo; } public void setIsFirstAppearanceOfSource(boolean value) { @@ -124,19 +124,19 @@ public void setIsFirstAppearanceOfSource(boolean value) { /* * Setters for CitationGroups.distribute() */ - public static void setLookupResult(OOPair> x) { - Citation cit = x.a; - cit.db = x.b; + public static void setLookupResult(OOPair> pair) { + Citation cit = pair.a; + cit.db = pair.b; } - public static void setNumber(OOPair> x) { - Citation cit = x.a; - cit.number = x.b; + public static void setNumber(OOPair> pair) { + Citation cit = pair.a; + cit.number = pair.b; } - public static void setUniqueLetter(OOPair> x) { - Citation cit = x.a; - cit.uniqueLetter = x.b; + public static void setUniqueLetter(OOPair> pair) { + Citation cit = pair.a; + cit.uniqueLetter = pair.b; } } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java index 2986a6f4501..3b9021eb73f 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java @@ -121,8 +121,8 @@ public List getCitationsInLocalOrder() { * indexInGlobalOrder */ - public void setIndexInGlobalOrder(Optional i) { - this.indexInGlobalOrder = i; + public void setIndexInGlobalOrder(Optional indexInGlobalOrder) { + this.indexInGlobalOrder = indexInGlobalOrder; } public Optional getIndexInGlobalOrder() { diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java index bd0cca64e13..0bfe4a832d0 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java @@ -79,29 +79,28 @@ public void lookupCitations(List databases) { /* * It is not clear which of the two solutions below is better. */ - if (true) { - // collect-lookup-distribute - // - // CitationDatabaseLookupResult for the same citation key is the same object. Until we - // insert a new citation from the GUI. - CitedKeys cks = getCitedKeysUnordered(); - cks.lookupInDatabases(databases); - cks.distributeLookupResults(this); - } else { - // lookup each citation directly - // - // CitationDatabaseLookupResult for the same citation key may be a different object: - // CitedKey.addPath has to use equals, so CitationDatabaseLookupResult has to override - // Object.equals, which depends on BibEntry.equals and BibDatabase.equals doing the - // right thing. Seems to work. But what we gained from avoiding collect-and-distribute - // may be lost in more complicated consistency checking in addPath. - // - for (CitationGroup cg : getCitationGroupsUnordered()) { - for (Citation cit : cg.citationsInStorageOrder) { - cit.lookupInDatabases(databases); - } - } - } + + // (1) collect-lookup-distribute + // + // CitationDatabaseLookupResult for the same citation key is the same object. Until we + // insert a new citation from the GUI. + CitedKeys cks = getCitedKeysUnordered(); + cks.lookupInDatabases(databases); + cks.distributeLookupResults(this); + + // (2) lookup each citation directly + // + // CitationDatabaseLookupResult for the same citation key may be a different object: + // CitedKey.addPath has to use equals, so CitationDatabaseLookupResult has to override + // Object.equals, which depends on BibEntry.equals and BibDatabase.equals doing the + // right thing. Seems to work. But what we gained from avoiding collect-and-distribute + // may be lost in more complicated consistency checking in addPath. + // + /// for (CitationGroup cg : getCitationGroupsUnordered()) { + /// for (Citation cit : cg.citationsInStorageOrder) { + /// cit.lookupInDatabases(databases); + /// } + /// } } public List getCitationGroupsUnordered() { @@ -162,11 +161,11 @@ public CitedKeys getCitedKeysUnordered() { int storageIndexInGroup = 0; for (Citation cit : cg.citationsInStorageOrder) { String key = cit.citationKey; - CitationPath p = new CitationPath(cg.cgid, storageIndexInGroup); + CitationPath path = new CitationPath(cg.cgid, storageIndexInGroup); if (res.containsKey(key)) { - res.get(key).addPath(p, cit); + res.get(key).addPath(path, cit); } else { - res.put(key, new CitedKey(key, p, cit)); + res.put(key, new CitedKey(key, path, cit)); } storageIndexInGroup++; } @@ -178,19 +177,19 @@ public CitedKeys getCitedKeysUnordered() { * CitedKeys created iterating citations in (globalOrder,localOrder) */ public CitedKeys getCitedKeysSortedInOrderOfAppearance() { - LinkedHashMap res = new LinkedHashMap<>(); if (!hasGlobalOrder()) { throw new IllegalStateException("getSortedCitedKeys: no globalOrder"); } + LinkedHashMap res = new LinkedHashMap<>(); for (CitationGroup cg : getCitationGroupsInGlobalOrder()) { for (int i : cg.getLocalOrder()) { Citation cit = cg.citationsInStorageOrder.get(i); String citationKey = cit.citationKey; - CitationPath p = new CitationPath(cg.cgid, i); + CitationPath path = new CitationPath(cg.cgid, i); if (res.containsKey(citationKey)) { - res.get(citationKey).addPath(p, cit); + res.get(citationKey).addPath(path, cit); } else { - res.put(citationKey, new CitedKey(citationKey, p, cit)); + res.put(citationKey, new CitedKey(citationKey, path, cit)); } } } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java b/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java index b17ec100ee2..86674583d1c 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java @@ -26,14 +26,14 @@ public CitationLookupResult(BibEntry entry, BibDatabase database) { * Since within each GUI call we use a fixed list of databases, it is OK. */ @Override - public boolean equals(Object o) { - if (o == this) { + public boolean equals(Object otherObject) { + if (otherObject == this) { return true; } - if (!(o instanceof CitationLookupResult)) { + if (!(otherObject instanceof CitationLookupResult)) { return false; } - CitationLookupResult that = (CitationLookupResult) o; + CitationLookupResult that = (CitationLookupResult) otherObject; return this.entry.equals(that.entry) && this.database.equals(that.database); } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java index f577867c539..785d828ce7e 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java @@ -27,11 +27,11 @@ public class CitedKey implements private Optional uniqueLetter; // For AuthorYear citation styles. private Optional normCitMarker; // For AuthorYear citation styles. - CitedKey(String citationKey, CitationPath p, Citation cit) { + CitedKey(String citationKey, CitationPath path, Citation cit) { this.citationKey = citationKey; this.where = new ArrayList<>(); // remember order - this.where.add(p); + this.where.add(path); // synchronized with Citation this.db = cit.getLookupResult(); @@ -100,8 +100,8 @@ public void setNormalizedCitationMarker(Optional normCitMarker) { /** * Appends to end of {@code where} */ - void addPath(CitationPath p, Citation cit) { - this.where.add(p); + void addPath(CitationPath path, Citation cit) { + this.where.add(path); // Check consistency if (!cit.getLookupResult().equals(this.db)) { diff --git a/src/main/java/org/jabref/model/openoffice/style/ComparableCitation.java b/src/main/java/org/jabref/model/openoffice/style/ComparableCitation.java index a6ac799b017..81120c09b2a 100644 --- a/src/main/java/org/jabref/model/openoffice/style/ComparableCitation.java +++ b/src/main/java/org/jabref/model/openoffice/style/ComparableCitation.java @@ -9,5 +9,5 @@ * Otherwise we sort citations as cited keys. */ public interface ComparableCitation extends ComparableCitedKey { - public Optional getPageInfo(); + Optional getPageInfo(); } diff --git a/src/main/java/org/jabref/model/openoffice/style/ComparableCitedKey.java b/src/main/java/org/jabref/model/openoffice/style/ComparableCitedKey.java index 0d4c8e2efce..23b3ffaba78 100644 --- a/src/main/java/org/jabref/model/openoffice/style/ComparableCitedKey.java +++ b/src/main/java/org/jabref/model/openoffice/style/ComparableCitedKey.java @@ -9,8 +9,8 @@ */ public interface ComparableCitedKey { - public String getCitationKey(); + String getCitationKey(); - public Optional getBibEntry(); + Optional getBibEntry(); } diff --git a/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java b/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java index a5484560316..7f6d3adfab0 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java +++ b/src/main/java/org/jabref/model/openoffice/style/CompareCitedKey.java @@ -24,18 +24,16 @@ public int compare(ComparableCitedKey a, ComparableCitedKey b) { Optional bBibEntry = b.getBibEntry(); final int mul = unresolvedComesFirst ? (+1) : (-1); - int res = 0; if (aBibEntry.isEmpty() && bBibEntry.isEmpty()) { // Both are unresolved: compare them by citation key. - res = a.getCitationKey().compareTo(b.getCitationKey()); + return a.getCitationKey().compareTo(b.getCitationKey()); } else if (aBibEntry.isEmpty()) { return -mul; } else if (bBibEntry.isEmpty()) { return mul; } else { // Proper comparison of entries - res = entryComparator.compare(aBibEntry.get(), bBibEntry.get()); + return entryComparator.compare(aBibEntry.get(), bBibEntry.get()); } - return res; } } diff --git a/src/main/java/org/jabref/model/openoffice/style/OODataModel.java b/src/main/java/org/jabref/model/openoffice/style/OODataModel.java index 20b2365ebf2..835715dfca5 100644 --- a/src/main/java/org/jabref/model/openoffice/style/OODataModel.java +++ b/src/main/java/org/jabref/model/openoffice/style/OODataModel.java @@ -26,8 +26,8 @@ public static List> fakePageInfos(String pageInfo, int nCitatio } if (pageInfo != null) { final int last = nCitations - 1; - Optional pi = Optional.ofNullable(OOText.fromString(pageInfo)); - pageInfos.set(last, PageInfo.normalizePageInfo(pi)); + Optional optionalPageInfo = Optional.ofNullable(OOText.fromString(pageInfo)); + pageInfos.set(last, PageInfo.normalizePageInfo(optionalPageInfo)); } return pageInfos; } diff --git a/src/main/java/org/jabref/model/openoffice/style/PageInfo.java b/src/main/java/org/jabref/model/openoffice/style/PageInfo.java index ace7eedae02..ec3a8436dcf 100644 --- a/src/main/java/org/jabref/model/openoffice/style/PageInfo.java +++ b/src/main/java/org/jabref/model/openoffice/style/PageInfo.java @@ -13,15 +13,16 @@ private PageInfo() { /* * pageInfo normalization */ - public static Optional normalizePageInfo(Optional o) { - if (o == null || o.isEmpty() || "".equals(OOText.toString(o.get()))) { + public static Optional normalizePageInfo(Optional optionalText) { + if (optionalText == null || optionalText.isEmpty() || "".equals(OOText.toString(optionalText.get()))) { return Optional.empty(); } - String s = OOText.toString(o.get()); - if (s.trim().equals("")) { + String str = OOText.toString(optionalText.get()); + String trimmed = str.trim(); + if (trimmed.equals("")) { return Optional.empty(); } - return Optional.of(OOText.fromString(s.trim())); + return Optional.of(OOText.fromString(trimmed)); } /** From f224dc0e487f0ecd5bf4e9152224309532a2ade0 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 08:57:21 +0200 Subject: [PATCH 054/103] replaced single-character names in OOBibStyle.java (in changed part) --- .../logic/openoffice/style/OOBibStyle.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index feccb727f53..c612f179540 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -1019,36 +1019,36 @@ protected Map getCitProperties() { return citProperties; } - protected void addJournal(String s) { - journals.add(s); + protected void addJournal(String journalName) { + journals.add(journalName); } - protected void setLocalCopy(String s) { - localCopy = s; + protected void setLocalCopy(String contentsOfJstyleFile) { + localCopy = contentsOfJstyleFile; } - protected void setName(String s) { - name = s; + protected void setName(String nameOfTheStyle) { + name = nameOfTheStyle; } protected boolean getIsDefaultLayoutPresent() { return isDefaultLayoutPresent; } - protected void setIsDefaultLayoutPresent(boolean b) { - isDefaultLayoutPresent = b; + protected void setIsDefaultLayoutPresent(boolean isPresent) { + isDefaultLayoutPresent = isPresent; } - protected void setValid(boolean b) { - valid = b; + protected void setValid(boolean isValid) { + valid = isValid; } protected LayoutFormatterPreferences getPrefs() { return prefs; } - protected void setDefaultBibLayout(Layout l) { - defaultBibLayout = l; + protected void setDefaultBibLayout(Layout layout) { + defaultBibLayout = layout; } /** @@ -1270,9 +1270,9 @@ protected String getAuthorLastSeparator() { /* As getAuthorLastSeparator, for in-text citation. */ protected String getAuthorLastSeparatorInTextWithFallBack() { - String a = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR_IN_TEXT); - String b = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR); - return Objects.requireNonNullElse(a, b); + String value1 = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR_IN_TEXT); + String value2 = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR); + return Objects.requireNonNullElse(value1, value2); } protected String getPageInfoSeparator() { From ac51403cd7ce54d8cb22006b88037730ce1de702 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 09:14:43 +0200 Subject: [PATCH 055/103] some longer names in OOBibStyleGetCitationMarker.java --- .../style/OOBibStyleGetCitationMarker.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) 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 4235841e426..deb1a306913 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java @@ -503,6 +503,9 @@ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, return OOText.fromString(sb.toString()); } + /** + * Add / override methods for the purpose of creating a normalized citation marker. + */ private static class CitationMarkerNormEntryWrap implements CitationMarkerEntry { CitationMarkerNormEntry inner; @@ -538,7 +541,7 @@ public boolean getIsFirstAppearanceOfSource() { } /** - * @param cne A citation to process. + * @param normEntry A citation to process. * * @return A normalized citation marker for deciding which * citations need uniqueLetters. @@ -548,10 +551,10 @@ public boolean getIsFirstAppearanceOfSource() { * Note: now includes some markup. */ static OOText getNormalizedCitationMarker(OOBibStyle style, - CitationMarkerNormEntry cne, + CitationMarkerNormEntry normEntry, Optional maxAuthorsOverride) { boolean[] startsNewGroup = {true}; - CitationMarkerEntry entry = new CitationMarkerNormEntryWrap(cne); + CitationMarkerEntry entry = new CitationMarkerNormEntryWrap(normEntry); return getAuthorYearParenthesisMarker2(style, AuthorYearMarkerPurpose.NORMALIZED, Collections.singletonList(entry), @@ -566,10 +569,10 @@ static OOText getNormalizedCitationMarker(OOBibStyle style, List normalizedMarkers = new ArrayList<>(citationMarkerEntries.size()); for (CitationMarkerEntry citationMarkerEntry : citationMarkerEntries) { - OOText nm = getNormalizedCitationMarker(style, - citationMarkerEntry, - maxAuthorsOverride); - normalizedMarkers.add(nm); + OOText normalized = getNormalizedCitationMarker(style, + citationMarkerEntry, + maxAuthorsOverride); + normalizedMarkers.add(normalized); } return normalizedMarkers; } From e0151eb6586bc65cbf0aecf469accde311f6af18 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 14:34:54 +0200 Subject: [PATCH 056/103] drop normalizePageInfos, use 'preferred' and 'fallback' in getAuthorLastSeparatorInTextWithFallBack --- .../logic/openoffice/style/OOBibStyle.java | 36 ++----------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index c612f179540..e21804a2c86 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -42,8 +42,6 @@ import org.jabref.model.openoffice.style.CitationMarkerNumericBibEntry; import org.jabref.model.openoffice.style.CitationMarkerNumericEntry; import org.jabref.model.openoffice.style.NonUniqueCitationMarker; -import org.jabref.model.openoffice.style.PageInfo; -import org.jabref.model.openoffice.util.OOListUtil; import org.jabref.model.strings.StringUtil; import org.slf4j.Logger; @@ -1080,34 +1078,6 @@ public OOText getNumCitationMarkerForBibliography(CitationMarkerNumericBibEntry return OOBibStyleGetNumCitationMarker.getNumCitationMarkerForBibliography(this, entry); } - /** - * Make sure that (1) we have exactly one entry for each - * citation, (2) each entry is either Optional.empty or its content is not empty when trimmed. - * - * As a special case: pageInfos may be null. In this case - * the result is a list filled with Optional.empty() values. - */ - static List> - normalizePageInfos(List> pageInfos, int nCitations) { - - // translate null to all-empty - if (pageInfos == null) { - List> res = new ArrayList<>(nCitations); - for (int i = 0; i < nCitations; i++) { - res.add(Optional.empty()); - } - return res; - } - - // not null, check size - if (pageInfos.size() != nCitations) { - throw new IllegalArgumentException("normalizePageInfos: pageInfos.size() != nCitations"); - } - - // not null, normalize elementwise - return OOListUtil.map(pageInfos, PageInfo::normalizePageInfo); - } - public OOText getNormalizedCitationMarker(CitationMarkerNormEntry ce) { return OOBibStyleGetCitationMarker.getNormalizedCitationMarker(this, ce, Optional.empty()); } @@ -1270,9 +1240,9 @@ protected String getAuthorLastSeparator() { /* As getAuthorLastSeparator, for in-text citation. */ protected String getAuthorLastSeparatorInTextWithFallBack() { - String value1 = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR_IN_TEXT); - String value2 = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR); - return Objects.requireNonNullElse(value1, value2); + String preferred = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR_IN_TEXT); + String fallback = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR); + return Objects.requireNonNullElse(preferred, fallback); } protected String getPageInfoSeparator() { From d7bf2fb119d74b62f51a6ec173bff262f9462183 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 14:53:20 +0200 Subject: [PATCH 057/103] checkstyle --- src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index e21804a2c86..082d94a7fdf 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -1241,7 +1241,7 @@ protected String getAuthorLastSeparator() { /* As getAuthorLastSeparator, for in-text citation. */ protected String getAuthorLastSeparatorInTextWithFallBack() { String preferred = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR_IN_TEXT); - String fallback = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR); + String fallback = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR); return Objects.requireNonNullElse(preferred, fallback); } From dd6d1c69b47b8d494d602d7b3a0ea465164f0131 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 14:53:34 +0200 Subject: [PATCH 058/103] use putIfAbsent --- .../style/OOProcessAuthorYearMarkers.java | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java index cbd03cd79c6..896e747913f 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java @@ -63,17 +63,10 @@ private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroup String normCitMarker = OOText.toString(citedKey.getNormalizedCitationMarker().get()); String citationKey = citedKey.citationKey; - if (!normCitMarkerToClachingKeys.containsKey(normCitMarker)) { - // Found new normCitMarker - List clashingKeys = new ArrayList<>(1); - normCitMarkerToClachingKeys.put(normCitMarker, clashingKeys); + List clashingKeys = normCitMarkerToClachingKeys.putIfAbsent(normCitMarker, new ArrayList<>(1)); + if (!clashingKeys.contains(citationKey)) { + // First appearance of citationKey, add to list. clashingKeys.add(citationKey); - } else { - List clashingKeys = normCitMarkerToClachingKeys.get(normCitMarker); - if (!clashingKeys.contains(citationKey)) { - // First appearance of citationKey, add to list. - clashingKeys.add(citationKey); - } } } From 7cb166c28f12bec22469c254882422bcd4ca58e9 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 14:56:59 +0200 Subject: [PATCH 059/103] use "{}" with LOGGER --- .../java/org/jabref/logic/openoffice/style/StyleLoader.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java b/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java index 727db88cbc4..3dbdf766056 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java +++ b/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java @@ -92,9 +92,9 @@ private void loadExternalStyles() { } } catch (FileNotFoundException e) { // The file couldn't be found... should we tell anyone? - LOGGER.info("Cannot find external style file " + filename); + LOGGER.info("Cannot find external style file {}", filename); } catch (IOException e) { - LOGGER.info("Problem reading external style file " + filename, e); + LOGGER.info("Problem reading external style file {}", filename, e); } } } From e832a1014c230dd81899f190db61e3e24ebb2bda Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 16:52:37 +0200 Subject: [PATCH 060/103] use Objects.hash and Objects.equals in CitationLookupResult --- .../openoffice/style/CitationLookupResult.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java b/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java index 86674583d1c..bfe6dc1debe 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java @@ -24,6 +24,11 @@ public CitationLookupResult(BibEntry entry, BibDatabase database) { * is equivalent to {@code this.database == that.database}. * * Since within each GUI call we use a fixed list of databases, it is OK. + * + * CitationLookupResult.equals is used in CitedKey.addPath to check the added Citation + * refers to the same source as the others. As long as we look up each citation key + * only once (in CitationGroups.lookupCitations), the default implementation for equals + * would be sufficient (and could also omit hashCode below). */ @Override public boolean equals(Object otherObject) { @@ -34,15 +39,11 @@ public boolean equals(Object otherObject) { return false; } CitationLookupResult that = (CitationLookupResult) otherObject; - return this.entry.equals(that.entry) && this.database.equals(that.database); + return Objects.equals(this.entry, that.entry) && Objects.equals(this.database, that.database); } @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + entry.hashCode(); - result = prime * result + database.hashCode(); - return result; + return Objects.hash(entry, database); } } From 4ba4e66bb7dbaee7b6bca303b1b6c87d4c731242 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 17:05:17 +0200 Subject: [PATCH 061/103] simplified CitedKey.getBibEntry --- src/main/java/org/jabref/model/openoffice/style/CitedKey.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java index 785d828ce7e..5331204bd75 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java @@ -52,9 +52,7 @@ public String getCitationKey() { @Override public Optional getBibEntry() { - return (db.isPresent() - ? Optional.of(db.get().entry) - : Optional.empty()); + return db.map(e -> e.entry); } /* From 46f72317907af392108a83c1806b78b771de3ee7 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 08:57:21 +0200 Subject: [PATCH 062/103] replaced single-character names in OOBibStyle.java (in changed part) --- .../logic/openoffice/style/OOBibStyle.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index 1cc0ae78f4a..e27e3a8521a 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -635,36 +635,36 @@ protected Map getCitProperties() { return citProperties; } - protected void addJournal(String s) { - journals.add(s); + protected void addJournal(String journalName) { + journals.add(journalName); } - protected void setLocalCopy(String s) { - localCopy = s; + protected void setLocalCopy(String contentsOfJstyleFile) { + localCopy = contentsOfJstyleFile; } - protected void setName(String s) { - name = s; + protected void setName(String nameOfTheStyle) { + name = nameOfTheStyle; } protected boolean getIsDefaultLayoutPresent() { return isDefaultLayoutPresent; } - protected void setIsDefaultLayoutPresent(boolean b) { - isDefaultLayoutPresent = b; + protected void setIsDefaultLayoutPresent(boolean isPresent) { + isDefaultLayoutPresent = isPresent; } - protected void setValid(boolean b) { - valid = b; + protected void setValid(boolean isValid) { + valid = isValid; } protected LayoutFormatterPreferences getPrefs() { return prefs; } - protected void setDefaultBibLayout(Layout l) { - defaultBibLayout = l; + protected void setDefaultBibLayout(Layout layout) { + defaultBibLayout = layout; } /** @@ -886,9 +886,9 @@ protected String getAuthorLastSeparator() { /* As getAuthorLastSeparator, for in-text citation. */ protected String getAuthorLastSeparatorInTextWithFallBack() { - String a = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR_IN_TEXT); - String b = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR); - return Objects.requireNonNullElse(a, b); + String value1 = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR_IN_TEXT); + String value2 = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR); + return Objects.requireNonNullElse(value1, value2); } protected String getPageInfoSeparator() { From 55686e36b81dd8213e5c032fca05b4e40e513b62 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 09:14:43 +0200 Subject: [PATCH 063/103] some longer names in OOBibStyleGetCitationMarker.java --- .../style/OOBibStyleGetCitationMarker.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) 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 4235841e426..deb1a306913 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java @@ -503,6 +503,9 @@ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, return OOText.fromString(sb.toString()); } + /** + * Add / override methods for the purpose of creating a normalized citation marker. + */ private static class CitationMarkerNormEntryWrap implements CitationMarkerEntry { CitationMarkerNormEntry inner; @@ -538,7 +541,7 @@ public boolean getIsFirstAppearanceOfSource() { } /** - * @param cne A citation to process. + * @param normEntry A citation to process. * * @return A normalized citation marker for deciding which * citations need uniqueLetters. @@ -548,10 +551,10 @@ public boolean getIsFirstAppearanceOfSource() { * Note: now includes some markup. */ static OOText getNormalizedCitationMarker(OOBibStyle style, - CitationMarkerNormEntry cne, + CitationMarkerNormEntry normEntry, Optional maxAuthorsOverride) { boolean[] startsNewGroup = {true}; - CitationMarkerEntry entry = new CitationMarkerNormEntryWrap(cne); + CitationMarkerEntry entry = new CitationMarkerNormEntryWrap(normEntry); return getAuthorYearParenthesisMarker2(style, AuthorYearMarkerPurpose.NORMALIZED, Collections.singletonList(entry), @@ -566,10 +569,10 @@ static OOText getNormalizedCitationMarker(OOBibStyle style, List normalizedMarkers = new ArrayList<>(citationMarkerEntries.size()); for (CitationMarkerEntry citationMarkerEntry : citationMarkerEntries) { - OOText nm = getNormalizedCitationMarker(style, - citationMarkerEntry, - maxAuthorsOverride); - normalizedMarkers.add(nm); + OOText normalized = getNormalizedCitationMarker(style, + citationMarkerEntry, + maxAuthorsOverride); + normalizedMarkers.add(normalized); } return normalizedMarkers; } From c1491e926bc635eed4cb21e4c587ca66a9a5856e Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 17:29:52 +0200 Subject: [PATCH 064/103] OOBibStyle --- .../logic/openoffice/style/OOBibStyle.java | 37 ++----------------- 1 file changed, 4 insertions(+), 33 deletions(-) diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index e27e3a8521a..1ac3045f24e 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -37,8 +37,7 @@ import org.jabref.model.openoffice.style.CitationMarkerNumericBibEntry; import org.jabref.model.openoffice.style.CitationMarkerNumericEntry; import org.jabref.model.openoffice.style.NonUniqueCitationMarker; -import org.jabref.model.openoffice.style.PageInfo; -import org.jabref.model.openoffice.util.OOListUtil; +import org.jabref.model.strings.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -696,34 +695,6 @@ public OOText getNumCitationMarkerForBibliography(CitationMarkerNumericBibEntry return OOBibStyleGetNumCitationMarker.getNumCitationMarkerForBibliography(this, entry); } - /** - * Make sure that (1) we have exactly one entry for each - * citation, (2) each entry is either Optional.empty or its content is not empty when trimmed. - * - * As a special case: pageInfos may be null. In this case - * the result is a list filled with Optional.empty() values. - */ - static List> - normalizePageInfos(List> pageInfos, int nCitations) { - - // translate null to all-empty - if (pageInfos == null) { - List> res = new ArrayList<>(nCitations); - for (int i = 0; i < nCitations; i++) { - res.add(Optional.empty()); - } - return res; - } - - // not null, check size - if (pageInfos.size() != nCitations) { - throw new IllegalArgumentException("normalizePageInfos: pageInfos.size() != nCitations"); - } - - // not null, normalize elementwise - return OOListUtil.map(pageInfos, PageInfo::normalizePageInfo); - } - public OOText getNormalizedCitationMarker(CitationMarkerNormEntry ce) { return OOBibStyleGetCitationMarker.getNormalizedCitationMarker(this, ce, Optional.empty()); } @@ -886,9 +857,9 @@ protected String getAuthorLastSeparator() { /* As getAuthorLastSeparator, for in-text citation. */ protected String getAuthorLastSeparatorInTextWithFallBack() { - String value1 = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR_IN_TEXT); - String value2 = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR); - return Objects.requireNonNullElse(value1, value2); + String preferred = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR_IN_TEXT); + String fallback = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR); + return Objects.requireNonNullElse(preferred, fallback); } protected String getPageInfoSeparator() { From e0783df9e062e25ad68a06fd40d82ea91d432a29 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 14:53:20 +0200 Subject: [PATCH 065/103] checkstyle --- src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index 1ac3045f24e..e65ed4c6b97 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -858,7 +858,7 @@ protected String getAuthorLastSeparator() { /* As getAuthorLastSeparator, for in-text citation. */ protected String getAuthorLastSeparatorInTextWithFallBack() { String preferred = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR_IN_TEXT); - String fallback = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR); + String fallback = getStringCitProperty(OOBibStyle.AUTHOR_LAST_SEPARATOR); return Objects.requireNonNullElse(preferred, fallback); } From 09748e3ff968319dd1117ba805b83ea24ccdfdad Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 14:53:34 +0200 Subject: [PATCH 066/103] use putIfAbsent --- .../style/OOProcessAuthorYearMarkers.java | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java index cbd03cd79c6..896e747913f 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java @@ -63,17 +63,10 @@ private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroup String normCitMarker = OOText.toString(citedKey.getNormalizedCitationMarker().get()); String citationKey = citedKey.citationKey; - if (!normCitMarkerToClachingKeys.containsKey(normCitMarker)) { - // Found new normCitMarker - List clashingKeys = new ArrayList<>(1); - normCitMarkerToClachingKeys.put(normCitMarker, clashingKeys); + List clashingKeys = normCitMarkerToClachingKeys.putIfAbsent(normCitMarker, new ArrayList<>(1)); + if (!clashingKeys.contains(citationKey)) { + // First appearance of citationKey, add to list. clashingKeys.add(citationKey); - } else { - List clashingKeys = normCitMarkerToClachingKeys.get(normCitMarker); - if (!clashingKeys.contains(citationKey)) { - // First appearance of citationKey, add to list. - clashingKeys.add(citationKey); - } } } From e0fb50d5125d02ea0e77368d18d96bf7f7cff929 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 14:56:59 +0200 Subject: [PATCH 067/103] use "{}" with LOGGER --- .../java/org/jabref/logic/openoffice/style/StyleLoader.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java b/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java index 727db88cbc4..3dbdf766056 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java +++ b/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java @@ -92,9 +92,9 @@ private void loadExternalStyles() { } } catch (FileNotFoundException e) { // The file couldn't be found... should we tell anyone? - LOGGER.info("Cannot find external style file " + filename); + LOGGER.info("Cannot find external style file {}", filename); } catch (IOException e) { - LOGGER.info("Problem reading external style file " + filename, e); + LOGGER.info("Problem reading external style file {}", filename, e); } } } From 1268e60f52b21e6cf868354f4de6201ca847ae89 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 16:52:37 +0200 Subject: [PATCH 068/103] use Objects.hash and Objects.equals in CitationLookupResult --- .../openoffice/style/CitationLookupResult.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java b/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java index 86674583d1c..bfe6dc1debe 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java @@ -24,6 +24,11 @@ public CitationLookupResult(BibEntry entry, BibDatabase database) { * is equivalent to {@code this.database == that.database}. * * Since within each GUI call we use a fixed list of databases, it is OK. + * + * CitationLookupResult.equals is used in CitedKey.addPath to check the added Citation + * refers to the same source as the others. As long as we look up each citation key + * only once (in CitationGroups.lookupCitations), the default implementation for equals + * would be sufficient (and could also omit hashCode below). */ @Override public boolean equals(Object otherObject) { @@ -34,15 +39,11 @@ public boolean equals(Object otherObject) { return false; } CitationLookupResult that = (CitationLookupResult) otherObject; - return this.entry.equals(that.entry) && this.database.equals(that.database); + return Objects.equals(this.entry, that.entry) && Objects.equals(this.database, that.database); } @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + entry.hashCode(); - result = prime * result + database.hashCode(); - return result; + return Objects.hash(entry, database); } } From 6107f4b9e1c3058b478c58e59b2e680cf1ec2749 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 17:05:17 +0200 Subject: [PATCH 069/103] simplified CitedKey.getBibEntry --- src/main/java/org/jabref/model/openoffice/style/CitedKey.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java index 785d828ce7e..5331204bd75 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java @@ -52,9 +52,7 @@ public String getCitationKey() { @Override public Optional getBibEntry() { - return (db.isPresent() - ? Optional.of(db.get().entry) - : Optional.empty()); + return db.map(e -> e.entry); } /* From a87d6b855cc5e34c4d3fb3d8a14c0ec335bbcd4d Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 17:46:30 +0200 Subject: [PATCH 070/103] drop import StringUtil --- src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index e65ed4c6b97..341d3839f72 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -37,7 +37,6 @@ import org.jabref.model.openoffice.style.CitationMarkerNumericBibEntry; import org.jabref.model.openoffice.style.CitationMarkerNumericEntry; import org.jabref.model.openoffice.style.NonUniqueCitationMarker; -import org.jabref.model.strings.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; From 6b5055a59604db71e706cd21795b5dcb6888e0fd Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 18:10:06 +0200 Subject: [PATCH 071/103] drop import ArrayList --- src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index 341d3839f72..b155dd44dc7 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -9,7 +9,6 @@ import java.io.StringReader; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; From 8a29981a4aaaa840b46af23e689d01c2cf932daa Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 18:11:28 +0200 Subject: [PATCH 072/103] more use of "{}" in LOGGER --- .../jabref/logic/openoffice/style/StyleLoader.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java b/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java index 3dbdf766056..3098e06233c 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java +++ b/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java @@ -61,19 +61,19 @@ public boolean addStyleIfValid(String filename) { try { OOBibStyle newStyle = new OOBibStyle(new File(filename), layoutFormatterPreferences, encoding); if (externalStyles.contains(newStyle)) { - LOGGER.info("External style file " + filename + " already existing."); + LOGGER.info("External style file {} already existing.", filename); } else if (newStyle.isValid()) { externalStyles.add(newStyle); storeExternalStyles(); return true; } else { - LOGGER.error(String.format("Style with filename %s is invalid", filename)); + LOGGER.error("Style with filename {} is invalid", filename); } } catch (FileNotFoundException e) { // The file couldn't be found... should we tell anyone? - LOGGER.info("Cannot find external style file " + filename, e); + LOGGER.info("Cannot find external style file {}", filename, e); } catch (IOException e) { - LOGGER.info("Problem reading external style file " + filename, e); + LOGGER.info("Problem reading external style file {}", filename, e); } return false; } @@ -88,7 +88,7 @@ private void loadExternalStyles() { if (style.isValid()) { // Problem! externalStyles.add(style); } else { - LOGGER.error(String.format("Style with filename %s is invalid", filename)); + LOGGER.error("Style with filename {} is invalid", filename); } } catch (FileNotFoundException e) { // The file couldn't be found... should we tell anyone? @@ -105,7 +105,7 @@ private void loadInternalStyles() { try { internalStyles.add(new OOBibStyle(filename, layoutFormatterPreferences)); } catch (IOException e) { - LOGGER.info("Problem reading internal style file " + filename, e); + LOGGER.info("Problem reading internal style file {}", filename, e); } } } From 2725b64400169fcd836a283b59f5d9b2141f7c68 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 18:11:50 +0200 Subject: [PATCH 073/103] more use of "{}" in LOGGER --- .../logic/openoffice/backend/NamedRangeReferenceMark.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 63d5f917fc5..29a90601056 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java @@ -198,8 +198,7 @@ public Optional nrGetRawCursor(XTextDocument doc) Optional markAsTextContent = UnoReferenceMark.getAsTextContent(doc, name); if (markAsTextContent.isEmpty()) { - String msg = String.format("nrGetRawCursor: markAsTextContent(%s).isEmpty()", name); - LOGGER.warn(msg); + LOGGER.warn("nrGetRawCursor: markAsTextContent({}).isEmpty()", name); } full = UnoCursor.getTextCursorOfTextContentAnchor(markAsTextContent.get()); @@ -338,7 +337,7 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) alpha.goRight(leftLength, true); LOGGER.debug("nrGetFillCursor: alpha(7) covers '{}', should be '{}'", alpha.getString(), left); omega.goLeft(rightLength, true); - LOGGER.debug("nrGetFillCursor: omega(8) covers '%s', should be '%s'%n", omega.getString(), right); + LOGGER.debug("nrGetFillCursor: omega(8) covers '{}', should be '{}'", omega.getString(), right); } } From c7cb442c733d28bd6b9e25fa2a5fb79c188e9981 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 18:11:56 +0200 Subject: [PATCH 074/103] more use of "{}" in LOGGER --- .../logic/openoffice/frontend/UpdateCitationMarkers.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java index b3f90d380a7..a3363938797 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java @@ -63,9 +63,8 @@ public static void applyNewCitationMarkers(XTextDocument doc, OOFrontend fr, OOB Optional marker = cg.getCitationMarker(); if (!marker.isPresent()) { - String msg = String.format("applyNewCitationMarkers: no marker for %s", - cg.cgid.citationGroupIdAsString()); - LOGGER.warn(msg); + LOGGER.warn("applyNewCitationMarkers: no marker for {}", + cg.cgid.citationGroupIdAsString()); continue; } From d86eadfccf9446702a0496136510cf4afcccf0c2 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 18:11:28 +0200 Subject: [PATCH 075/103] more use of "{}" in LOGGER --- .../jabref/logic/openoffice/style/StyleLoader.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java b/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java index 3dbdf766056..3098e06233c 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java +++ b/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java @@ -61,19 +61,19 @@ public boolean addStyleIfValid(String filename) { try { OOBibStyle newStyle = new OOBibStyle(new File(filename), layoutFormatterPreferences, encoding); if (externalStyles.contains(newStyle)) { - LOGGER.info("External style file " + filename + " already existing."); + LOGGER.info("External style file {} already existing.", filename); } else if (newStyle.isValid()) { externalStyles.add(newStyle); storeExternalStyles(); return true; } else { - LOGGER.error(String.format("Style with filename %s is invalid", filename)); + LOGGER.error("Style with filename {} is invalid", filename); } } catch (FileNotFoundException e) { // The file couldn't be found... should we tell anyone? - LOGGER.info("Cannot find external style file " + filename, e); + LOGGER.info("Cannot find external style file {}", filename, e); } catch (IOException e) { - LOGGER.info("Problem reading external style file " + filename, e); + LOGGER.info("Problem reading external style file {}", filename, e); } return false; } @@ -88,7 +88,7 @@ private void loadExternalStyles() { if (style.isValid()) { // Problem! externalStyles.add(style); } else { - LOGGER.error(String.format("Style with filename %s is invalid", filename)); + LOGGER.error("Style with filename {} is invalid", filename); } } catch (FileNotFoundException e) { // The file couldn't be found... should we tell anyone? @@ -105,7 +105,7 @@ private void loadInternalStyles() { try { internalStyles.add(new OOBibStyle(filename, layoutFormatterPreferences)); } catch (IOException e) { - LOGGER.info("Problem reading internal style file " + filename, e); + LOGGER.info("Problem reading internal style file {}", filename, e); } } } From fa2b24af532f2b36121b5a6b9750b438f5d61e53 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 18:11:50 +0200 Subject: [PATCH 076/103] more use of "{}" in LOGGER --- .../logic/openoffice/backend/NamedRangeReferenceMark.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 63d5f917fc5..29a90601056 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java @@ -198,8 +198,7 @@ public Optional nrGetRawCursor(XTextDocument doc) Optional markAsTextContent = UnoReferenceMark.getAsTextContent(doc, name); if (markAsTextContent.isEmpty()) { - String msg = String.format("nrGetRawCursor: markAsTextContent(%s).isEmpty()", name); - LOGGER.warn(msg); + LOGGER.warn("nrGetRawCursor: markAsTextContent({}).isEmpty()", name); } full = UnoCursor.getTextCursorOfTextContentAnchor(markAsTextContent.get()); @@ -338,7 +337,7 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) alpha.goRight(leftLength, true); LOGGER.debug("nrGetFillCursor: alpha(7) covers '{}', should be '{}'", alpha.getString(), left); omega.goLeft(rightLength, true); - LOGGER.debug("nrGetFillCursor: omega(8) covers '%s', should be '%s'%n", omega.getString(), right); + LOGGER.debug("nrGetFillCursor: omega(8) covers '{}', should be '{}'", omega.getString(), right); } } From a83a3aff732373e9ae3f240e5dca5f482a134c0d Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 18 Jul 2021 18:11:56 +0200 Subject: [PATCH 077/103] more use of "{}" in LOGGER --- .../logic/openoffice/frontend/UpdateCitationMarkers.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java index b3f90d380a7..a3363938797 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java @@ -63,9 +63,8 @@ public static void applyNewCitationMarkers(XTextDocument doc, OOFrontend fr, OOB Optional marker = cg.getCitationMarker(); if (!marker.isPresent()) { - String msg = String.format("applyNewCitationMarkers: no marker for %s", - cg.cgid.citationGroupIdAsString()); - LOGGER.warn(msg); + LOGGER.warn("applyNewCitationMarkers: no marker for {}", + cg.cgid.citationGroupIdAsString()); continue; } From 2224e6832a08792adea053c4fbf2fc629e670b7b Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 25 Jul 2021 00:17:31 +0200 Subject: [PATCH 078/103] Citation.lookup: use streams --- .../model/openoffice/style/Citation.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/style/Citation.java b/src/main/java/org/jabref/model/openoffice/style/Citation.java index 9b71a1051b2..9b286029310 100644 --- a/src/main/java/org/jabref/model/openoffice/style/Citation.java +++ b/src/main/java/org/jabref/model/openoffice/style/Citation.java @@ -62,14 +62,18 @@ public Optional getBibEntry() { : Optional.empty()); } + public static Optional lookup(BibDatabase database, String key) { + return (database + .getEntryByCitationKey(key) + .map(bibEntry -> new CitationLookupResult(bibEntry, database))); + } + public static Optional lookup(List databases, String key) { - for (BibDatabase database : databases) { - Optional entry = database.getEntryByCitationKey(key); - if (entry.isPresent()) { - return Optional.of(new CitationLookupResult(entry.get(), database)); - } - } - return Optional.empty(); + return (databases.stream() + .map(database -> Citation.lookup(database, key)) + .filter(Optional::isPresent) + .findFirst() + .orElse(Optional.empty())); } public void lookupInDatabases(List databases) { From 220dcc44bb34588293c98560eceae45d2464aa27 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 25 Jul 2021 00:17:31 +0200 Subject: [PATCH 079/103] Citation.lookup: use streams --- .../model/openoffice/style/Citation.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/style/Citation.java b/src/main/java/org/jabref/model/openoffice/style/Citation.java index 9b71a1051b2..9b286029310 100644 --- a/src/main/java/org/jabref/model/openoffice/style/Citation.java +++ b/src/main/java/org/jabref/model/openoffice/style/Citation.java @@ -62,14 +62,18 @@ public Optional getBibEntry() { : Optional.empty()); } + public static Optional lookup(BibDatabase database, String key) { + return (database + .getEntryByCitationKey(key) + .map(bibEntry -> new CitationLookupResult(bibEntry, database))); + } + public static Optional lookup(List databases, String key) { - for (BibDatabase database : databases) { - Optional entry = database.getEntryByCitationKey(key); - if (entry.isPresent()) { - return Optional.of(new CitationLookupResult(entry.get(), database)); - } - } - return Optional.empty(); + return (databases.stream() + .map(database -> Citation.lookup(database, key)) + .filter(Optional::isPresent) + .findFirst() + .orElse(Optional.empty())); } public void lookupInDatabases(List databases) { From eff50adce70a9cebdaee964e310ea6d728de9d45 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 25 Jul 2021 01:00:26 +0200 Subject: [PATCH 080/103] Citation.lookup: Optional::get before findFirst --- src/main/java/org/jabref/model/openoffice/style/Citation.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/style/Citation.java b/src/main/java/org/jabref/model/openoffice/style/Citation.java index 9b286029310..7bae4fd2548 100644 --- a/src/main/java/org/jabref/model/openoffice/style/Citation.java +++ b/src/main/java/org/jabref/model/openoffice/style/Citation.java @@ -72,8 +72,8 @@ public static Optional lookup(List databases, return (databases.stream() .map(database -> Citation.lookup(database, key)) .filter(Optional::isPresent) - .findFirst() - .orElse(Optional.empty())); + .map(Optional::get) + .findFirst()); } public void lookupInDatabases(List databases) { From 69c4d6bf00e51ca19776a46bd8d578a19bf4cd70 Mon Sep 17 00:00:00 2001 From: Antal K Date: Sun, 25 Jul 2021 01:00:26 +0200 Subject: [PATCH 081/103] Citation.lookup: Optional::get before findFirst --- src/main/java/org/jabref/model/openoffice/style/Citation.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/model/openoffice/style/Citation.java b/src/main/java/org/jabref/model/openoffice/style/Citation.java index 9b286029310..7bae4fd2548 100644 --- a/src/main/java/org/jabref/model/openoffice/style/Citation.java +++ b/src/main/java/org/jabref/model/openoffice/style/Citation.java @@ -72,8 +72,8 @@ public static Optional lookup(List databases, return (databases.stream() .map(database -> Citation.lookup(database, key)) .filter(Optional::isPresent) - .findFirst() - .orElse(Optional.empty())); + .map(Optional::get) + .findFirst()); } public void lookupInDatabases(List databases) { From c093d9d305f58d007d34022d41c34470ddf6f6f2 Mon Sep 17 00:00:00 2001 From: Antal K Date: Mon, 2 Aug 2021 13:31:59 +0200 Subject: [PATCH 082/103] removed catch RuntimeException around UnoCursor.getViewCursor Apparently cannot throw here. NoDocumentException is caught elsewhere, before we get here. com.sun.star.uno.RuntimeException is caught below, for cursor.getStart(); --- src/main/java/org/jabref/gui/openoffice/OOBibBase2.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java index f196bae6bc4..29829b9e038 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java @@ -199,15 +199,8 @@ final boolean testDialog(String title, OOVoidResult... results) { */ OOResult getUserCursorForTextInsertion(XTextDocument doc, String title) { - XTextCursor cursor; // Get the cursor positioned by the user. - try { - cursor = UnoCursor.getViewCursor(doc).orElse(null); - } catch (RuntimeException ex) { - return OOResult.error(new OOError(title, - Localization.lang("Could not get the cursor."), - ex)); - } + XTextCursor cursor = UnoCursor.getViewCursor(doc).orElse(null); // Check for crippled XTextViewCursor Objects.requireNonNull(cursor); From d579c804744788ecb87881cf9ce348774ee647d5 Mon Sep 17 00:00:00 2001 From: Antal K Date: Mon, 2 Aug 2021 13:31:59 +0200 Subject: [PATCH 083/103] removed catch RuntimeException around UnoCursor.getViewCursor Apparently cannot throw here. NoDocumentException is caught elsewhere, before we get here. com.sun.star.uno.RuntimeException is caught below, for cursor.getStart(); --- src/main/java/org/jabref/gui/openoffice/OOBibBase2.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java index f196bae6bc4..29829b9e038 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java @@ -199,15 +199,8 @@ final boolean testDialog(String title, OOVoidResult... results) { */ OOResult getUserCursorForTextInsertion(XTextDocument doc, String title) { - XTextCursor cursor; // Get the cursor positioned by the user. - try { - cursor = UnoCursor.getViewCursor(doc).orElse(null); - } catch (RuntimeException ex) { - return OOResult.error(new OOError(title, - Localization.lang("Could not get the cursor."), - ex)); - } + XTextCursor cursor = UnoCursor.getViewCursor(doc).orElse(null); // Check for crippled XTextViewCursor Objects.requireNonNull(cursor); From 1d9163d8f501cee96f7b5553a962caed22107663 Mon Sep 17 00:00:00 2001 From: Antal K Date: Mon, 2 Aug 2021 14:16:37 +0200 Subject: [PATCH 084/103] drop unused message --- src/main/resources/l10n/JabRef_en.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index ba0c601df21..431a2fc0a71 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -1565,7 +1565,6 @@ Custom=Custom Export\ cited=Export cited Unable\ to\ generate\ new\ library=Unable to generate new library -Could\ not\ get\ the\ cursor.=Could not get the cursor. The\ cursor\ is\ in\ protected\ area.=The cursor is in protected area. JabRefException=JabRefException No\ bibliography\ database\ is\ open\ for\ citation.=No bibliography database is open for citation. From 71bb5439e6a46c7f03dfbe3e804583d71e789297 Mon Sep 17 00:00:00 2001 From: Antal K Date: Mon, 2 Aug 2021 14:16:37 +0200 Subject: [PATCH 085/103] drop unused message --- src/main/resources/l10n/JabRef_en.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 0f970dc3cd4..0887759307a 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -1563,7 +1563,6 @@ Custom=Custom Export\ cited=Export cited Unable\ to\ generate\ new\ library=Unable to generate new library -Could\ not\ get\ the\ cursor.=Could not get the cursor. The\ cursor\ is\ in\ protected\ area.=The cursor is in protected area. JabRefException=JabRefException No\ bibliography\ database\ is\ open\ for\ citation.=No bibliography database is open for citation. From 94cb6116729a4138c8f1db2d022c5a497aa4de9c Mon Sep 17 00:00:00 2001 From: Antal K Date: Mon, 2 Aug 2021 16:25:40 +0200 Subject: [PATCH 086/103] putIfAbsent returns null for new entry --- .../logic/openoffice/style/OOProcessAuthorYearMarkers.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java index 896e747913f..306c0111a22 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java @@ -64,6 +64,9 @@ private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroup String citationKey = citedKey.citationKey; List clashingKeys = normCitMarkerToClachingKeys.putIfAbsent(normCitMarker, new ArrayList<>(1)); + if (clashingKeys == null) { + clashingKeys = normCitMarkerToClachingKeys.get(normCitMarker); + } if (!clashingKeys.contains(citationKey)) { // First appearance of citationKey, add to list. clashingKeys.add(citationKey); From 26ae70a1f0cb495875f42c5ddf829dc742500478 Mon Sep 17 00:00:00 2001 From: Antal K Date: Mon, 2 Aug 2021 16:25:40 +0200 Subject: [PATCH 087/103] putIfAbsent returns null for new entry --- .../logic/openoffice/style/OOProcessAuthorYearMarkers.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java index 896e747913f..306c0111a22 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java @@ -64,6 +64,9 @@ private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroup String citationKey = citedKey.citationKey; List clashingKeys = normCitMarkerToClachingKeys.putIfAbsent(normCitMarker, new ArrayList<>(1)); + if (clashingKeys == null) { + clashingKeys = normCitMarkerToClachingKeys.get(normCitMarker); + } if (!clashingKeys.contains(citationKey)) { // First appearance of citationKey, add to list. clashingKeys.add(citationKey); From ae22fec4cf4ce999a7b6a778f205ebb6c1a55dda Mon Sep 17 00:00:00 2001 From: Antal K Date: Tue, 3 Aug 2021 15:40:03 +0200 Subject: [PATCH 088/103] What is 52 in Backend52 --- .../java/org/jabref/logic/openoffice/backend/Backend52.java | 5 +++++ .../java/org/jabref/logic/openoffice/backend/Codec52.java | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java index cf91ad1043e..c03bd24496a 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java @@ -39,6 +39,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Backend52, Codec52 and OODataModel.JabRef52 refer to the mode of storage, encoding and + * what-is-stored in the document under JabRef version 5.2. These basically did not change up to + * JabRef 5.4. + */ public class Backend52 { private static final Logger LOGGER = LoggerFactory.getLogger(Backend52.class); public final OODataModel dataModel; diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java index e4405dc6115..93f57e5d99d 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java @@ -13,7 +13,7 @@ import org.jabref.model.openoffice.uno.NoDocumentException; /** - * How and what is encoded in a mark names. + * How and what is encoded in reference mark names under JabRef 5.2. * * - pageInfo does not appear here. It is not encoded in the mark name. */ From 26fa1b6bbcb3b8f439eb1d3b190e1f719ca329ab Mon Sep 17 00:00:00 2001 From: Antal K Date: Tue, 3 Aug 2021 15:40:03 +0200 Subject: [PATCH 089/103] What is 52 in Backend52 --- .../java/org/jabref/logic/openoffice/backend/Backend52.java | 5 +++++ .../java/org/jabref/logic/openoffice/backend/Codec52.java | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java index cf91ad1043e..c03bd24496a 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java @@ -39,6 +39,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Backend52, Codec52 and OODataModel.JabRef52 refer to the mode of storage, encoding and + * what-is-stored in the document under JabRef version 5.2. These basically did not change up to + * JabRef 5.4. + */ public class Backend52 { private static final Logger LOGGER = LoggerFactory.getLogger(Backend52.class); public final OODataModel dataModel; diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java index e4405dc6115..93f57e5d99d 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java @@ -13,7 +13,7 @@ import org.jabref.model.openoffice.uno.NoDocumentException; /** - * How and what is encoded in a mark names. + * How and what is encoded in reference mark names under JabRef 5.2. * * - pageInfo does not appear here. It is not encoded in the mark name. */ From f373daf3ca20e5b7caec0acbf02af942dc9fa88d Mon Sep 17 00:00:00 2001 From: Antal K Date: Fri, 20 Aug 2021 12:09:54 +0200 Subject: [PATCH 090/103] apply 2021-08-20-a/oobranch-E-update.patch Brings oobranch-E up to 89b096881 @ origin/improve-reversibility-rebased-03 Merge remote-tracking branch 'upstream/main' into improve-reversibility-rebased-03 --- .../logic/openoffice/backend/Backend52.java | 60 +++++-------------- .../logic/openoffice/backend/Codec52.java | 19 +++--- .../logic/openoffice/backend/GetContext.java | 8 +-- .../backend/NamedRangeReferenceMark.java | 35 +++++------ .../style/OOProcessAuthorYearMarkers.java | 3 - .../model/openoffice/backend/NamedRange.java | 21 +++---- .../openoffice/backend/NamedRangeManager.java | 14 ++--- 7 files changed, 58 insertions(+), 102 deletions(-) diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java index c03bd24496a..878571090f0 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java @@ -28,10 +28,7 @@ import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; @@ -39,11 +36,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** - * Backend52, Codec52 and OODataModel.JabRef52 refer to the mode of storage, encoding and - * what-is-stored in the document under JabRef version 5.2. These basically did not change up to - * JabRef 5.4. - */ public class Backend52 { private static final Logger LOGGER = LoggerFactory.getLogger(Backend52.class); public final OODataModel dataModel; @@ -118,25 +110,17 @@ public Optional healthReport(XTextDocument doc) private static void setPageInfoInDataInitial(List citations, Optional pageInfo) { // attribute to last citation (initially localOrder == storageOrder) - if (citations.size() > 0) { - citations.get(citations.size() - 1).setPageInfo(pageInfo); - } - } - - private static void setPageInfoInData(CitationGroup cg, Optional pageInfo) { - List citations = cg.getCitationsInLocalOrder(); - if (citations.size() > 0) { + if (!citations.isEmpty()) { citations.get(citations.size() - 1).setPageInfo(pageInfo); } } private static Optional getPageInfoFromData(CitationGroup cg) { List citations = cg.getCitationsInLocalOrder(); - if (citations.size() > 0) { - return citations.get(citations.size() - 1).getPageInfo(); - } else { + if (citations.isEmpty()) { return Optional.empty(); } + return citations.get(citations.size() - 1).getPageInfo(); } /** @@ -148,20 +132,18 @@ public CitationGroup readCitationGroupFromDocumentOrThrow(XTextDocument doc, Str WrappedTargetException, NoDocumentException { - Optional op = Codec52.parseMarkName(refMarkName); - if (op.isEmpty()) { + Optional optionalParsed = Codec52.parseMarkName(refMarkName); + if (optionalParsed.isEmpty()) { throw new IllegalArgumentException("readCitationGroupFromDocumentOrThrow:" + " found unparsable referenceMarkName"); } - Codec52.ParsedMarkName ov = op.get(); - CitationGroupId cgid = new CitationGroupId(refMarkName); - List citations = (ov.citationKeys.stream() + Codec52.ParsedMarkName parsed = optionalParsed.get(); + List citations = (parsed.citationKeys.stream() .map(Citation::new) .collect(Collectors.toList())); - Optional pageInfo = - (UnoUserDefinedProperty.getStringValue(doc, refMarkName) - .map(OOText::fromString)); + Optional pageInfo = (UnoUserDefinedProperty.getStringValue(doc, refMarkName) + .map(OOText::fromString)); pageInfo = PageInfo.normalizePageInfo(pageInfo); setPageInfoInDataInitial(citations, pageInfo); @@ -173,9 +155,10 @@ public CitationGroup readCitationGroupFromDocumentOrThrow(XTextDocument doc, Str + " referenceMarkName is not in the document"); } + CitationGroupId cgid = new CitationGroupId(refMarkName); CitationGroup cg = new CitationGroup(OODataModel.JabRef52, cgid, - ov.citationType, + parsed.citationType, citations, Optional.of(refMarkName)); this.cgidToNamedRange.put(cgid, namedRange.get()); @@ -203,7 +186,6 @@ public CitationGroup createCitationGroup(XTextDocument doc, NoDocumentException, WrappedTargetException, NotRemoveableException, - PropertyExistException, PropertyVetoException, IllegalTypeException { @@ -243,6 +225,8 @@ public CitationGroup createCitationGroup(XTextDocument doc, case JabRef60: cit.setPageInfo(pageInfo); break; + default: + throw new IllegalStateException("Unhandled dataModel in Backend52.createCitationGroup"); } } @@ -325,7 +309,6 @@ public List> combinePageInfos(List joinableGroup private NamedRange getNamedRangeOrThrow(CitationGroup cg) { NamedRange namedRange = this.cgidToNamedRange.get(cg.cgid); if (namedRange == null) { - String msg = "getNamedRange: could not lookup namedRange"; throw new IllegalStateException("getNamedRange: could not lookup namedRange"); } return namedRange; @@ -335,11 +318,7 @@ public void removeCitationGroup(CitationGroup cg, XTextDocument doc) throws WrappedTargetException, NoDocumentException, - NoSuchElementException, - NotRemoveableException, - IllegalTypeException, - PropertyExistException { - + NotRemoveableException { NamedRange namedRange = getNamedRangeOrThrow(cg); String refMarkName = namedRange.nrGetRangeName(); namedRange.nrRemoveFromDocument(doc); @@ -388,15 +367,13 @@ public XTextCursor getFillCursorForCitationGroup(CitationGroup cg, XTextDocument public void cleanFillCursorForCitationGroup(CitationGroup cg, XTextDocument doc) throws NoDocumentException, - WrappedTargetException, - CreationException { + WrappedTargetException { NamedRange namedRange = getNamedRangeOrThrow(cg); namedRange.nrCleanFillCursor(doc); } public List getCitationEntries(XTextDocument doc, CitationGroups cgs) throws - UnknownPropertyException, WrappedTargetException, NoDocumentException { @@ -404,8 +381,7 @@ public List getCitationEntries(XTextDocument doc, CitationGroups case JabRef52: // One context per CitationGroup: Backend52 (DataModel.JabRef52) // For DataModel.JabRef60 (Backend60) we need one context per Citation - int n = cgs.numberOfCitationGroups(); - List citations = new ArrayList<>(n); + List citations = new ArrayList<>(cgs.numberOfCitationGroups()); for (CitationGroup cg : cgs.getCitationGroupsUnordered()) { String name = cg.cgid.citationGroupIdAsString(); XTextCursor cursor = (this @@ -433,13 +409,9 @@ public List getCitationEntries(XTextDocument doc, CitationGroups */ public void applyCitationEntries(XTextDocument doc, List citationEntries) throws - UnknownPropertyException, - NotRemoveableException, - PropertyExistException, PropertyVetoException, IllegalTypeException, IllegalArgumentException, - NoDocumentException, WrappedTargetException { switch (dataModel) { diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java index 93f57e5d99d..f6d2b12245e 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java @@ -10,10 +10,9 @@ import java.util.stream.Collectors; import org.jabref.model.openoffice.style.CitationType; -import org.jabref.model.openoffice.uno.NoDocumentException; /** - * How and what is encoded in reference mark names under JabRef 5.2. + * How and what is encoded in a mark names. * * - pageInfo does not appear here. It is not encoded in the mark name. */ @@ -24,6 +23,10 @@ class Codec52 { // citationType is always "1" "2" or "3" Pattern.compile(BIB_CITATION + "(\\d*)_([123])_(.*)"); + private Codec52() { + /**/ + } + /** * This is what we get back from parsing a refMarkName. */ @@ -47,7 +50,7 @@ public static class ParsedMarkName { /** * Integer representation was written into the document in JabRef52, keep it for compatibility. */ - public static CitationType CitationTypeFromInt(int i) { + private static CitationType citationTypeFromInt(int i) { switch (i) { case 1: return CitationType.AUTHORYEAR_PAR; @@ -60,7 +63,7 @@ public static CitationType CitationTypeFromInt(int i) { } } - public static int CitationTypeToInt(CitationType i) { + private static int citationTypeToInt(CitationType i) { switch (i) { case AUTHORYEAR_PAR: return 1; @@ -86,12 +89,10 @@ public static int CitationTypeToInt(CitationType i) { */ public static String getUniqueMarkName(Set usedNames, String bibtexKey, - CitationType citationType) - throws - NoDocumentException { + CitationType citationType) { int i = 0; - int citTypeCode = CitationTypeToInt(citationType); + int citTypeCode = citationTypeToInt(citationType); String name = BIB_CITATION + '_' + citTypeCode + '_' + bibtexKey; while (usedNames.contains(name)) { name = BIB_CITATION + i + '_' + citTypeCode + '_' + bibtexKey; @@ -116,7 +117,7 @@ public static Optional parseMarkName(String refMarkName) { List keys = Arrays.asList(citeMatcher.group(3).split(",")); String i = citeMatcher.group(1); int citTypeCode = Integer.parseInt(citeMatcher.group(2)); - CitationType citationType = CitationTypeFromInt(citTypeCode); + CitationType citationType = citationTypeFromInt(citTypeCode); return (Optional.of(new Codec52.ParsedMarkName(i, citationType, keys))); } diff --git a/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java b/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java index 4cde12ad236..ffce5b9553e 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java @@ -1,8 +1,5 @@ package org.jabref.logic.openoffice.backend; -import org.jabref.model.openoffice.uno.NoDocumentException; - -import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,10 +31,7 @@ private GetContext() { public static String getCursorStringWithContext(XTextCursor cursor, int charBefore, int charAfter, - boolean htmlMarkup) - throws - WrappedTargetException, - NoDocumentException { + boolean htmlMarkup) { String citPart = cursor.getString(); 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 29a90601056..a11e29aecd1 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java @@ -8,7 +8,6 @@ import org.jabref.model.openoffice.uno.UnoCursor; import org.jabref.model.openoffice.uno.UnoReferenceMark; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XText; import com.sun.star.text.XTextContent; @@ -57,24 +56,24 @@ String getId() { * {@code safeInsertSpaces(n): para, para, left, space(n), right-delete, left(n), left-delete} * * @param position Where to insert (at position.getStart()) - * @param n Number of spaces to insert. + * @param numSpaces Number of spaces to insert. * * @return a new cursor, covering the just-inserted spaces. * */ - private static XTextCursor safeInsertSpacesBetweenReferenceMarks(XTextRange position, int n) { + private static XTextCursor safeInsertSpacesBetweenReferenceMarks(XTextRange position, int numSpaces) { // Start with an empty cursor at position.getStart(); XText text = position.getText(); XTextCursor cursor = text.createTextCursorByRange(position.getStart()); text.insertString(cursor, "\r\r", false); // para, para cursor.goLeft((short) 1, false); // left - text.insertString(cursor, " ".repeat(n), false); // space(n) + text.insertString(cursor, " ".repeat(numSpaces), false); // space(numSpaces) cursor.goRight((short) 1, true); cursor.setString(""); // right-delete - cursor.goLeft((short) n, false); // left(n) + cursor.goLeft((short) numSpaces, false); // left(numSpaces) cursor.goLeft((short) 1, true); cursor.setString(""); // left-delete - cursor.goRight((short) n, true); // select the newly inserted spaces + cursor.goRight((short) numSpaces, true); // select the newly inserted spaces return cursor; } @@ -101,8 +100,6 @@ private static void createReprInDocument(XTextDocument doc, final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; - final short leftLength = (short) left.length(); - final short rightLength = (short) right.length(); String bracketedContent = (withoutBrackets ? "" : left + right); @@ -111,9 +108,11 @@ private static void createReprInDocument(XTextDocument doc, UnoReferenceMark.create(doc, refMarkName, cursor, true /* absorb */); + // eat the first inserted space cursorBefore.goRight((short) 1, true); cursorBefore.setString(""); if (!insertSpaceAfter) { + // eat the second inserted space cursorAfter.goLeft((short) 1, true); cursorAfter.setString(""); } @@ -151,8 +150,7 @@ static Optional getFromDocument(XTextDocument doc, Stri public void nrRemoveFromDocument(XTextDocument doc) throws WrappedTargetException, - NoDocumentException, - NoSuchElementException { + NoDocumentException { UnoReferenceMark.removeIfExists(doc, this.nrGetRangeName()); } @@ -193,7 +191,6 @@ public Optional nrGetRawCursor(XTextDocument doc) WrappedTargetException { String name = this.nrGetRangeName(); - Optional full = Optional.empty(); Optional markAsTextContent = UnoReferenceMark.getAsTextContent(doc, name); @@ -201,10 +198,9 @@ public Optional nrGetRawCursor(XTextDocument doc) LOGGER.warn("nrGetRawCursor: markAsTextContent({}).isEmpty()", name); } - full = UnoCursor.getTextCursorOfTextContentAnchor(markAsTextContent.get()); + Optional full = UnoCursor.getTextCursorOfTextContentAnchor(markAsTextContent.get()); if (full.isEmpty()) { - String msg = "nrGetRawCursor: full.isEmpty()"; - LOGGER.warn(msg); + LOGGER.warn("nrGetRawCursor: full.isEmpty()"); return Optional.empty(); } return full; @@ -224,8 +220,6 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; - final short leftLength = (short) left.length(); - final short rightLength = (short) right.length(); final boolean debugThisFun = false; XTextCursor full = null; @@ -286,6 +280,7 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) beta.goRight((short) (fullText.length() - 2), true); LOGGER.debug("nrGetFillCursor: beta(1) covers '{}'", beta.getString()); + final short rightLength = (short) right.length(); if (fullText.startsWith(left) && fullText.endsWith(right)) { beta.setString(""); } else { @@ -334,6 +329,7 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) beta.setString(""); // should be OK now. if (debugThisFun) { + final short leftLength = (short) left.length(); alpha.goRight(leftLength, true); LOGGER.debug("nrGetFillCursor: alpha(7) covers '{}', should be '{}'", alpha.getString(), left); omega.goLeft(rightLength, true); @@ -351,8 +347,6 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) public static void checkFillCursor(XTextCursor cursor) { final String left = REFERENCE_MARK_LEFT_BRACKET; final String right = REFERENCE_MARK_RIGHT_BRACKET; - final short leftLength = (short) left.length(); - final short rightLength = (short) right.length(); XTextCursor alpha = cursor.getText().createTextCursorByRange(cursor); alpha.collapseToStart(); @@ -360,6 +354,7 @@ public static void checkFillCursor(XTextCursor cursor) { XTextCursor omega = cursor.getText().createTextCursorByRange(cursor); omega.collapseToEnd(); + final short leftLength = (short) left.length(); if (leftLength > 0) { alpha.goLeft(leftLength, true); if (!left.equals(alpha.getString())) { @@ -370,6 +365,7 @@ public static void checkFillCursor(XTextCursor cursor) { } } + final short rightLength = (short) right.length(); if (rightLength > 0) { omega.goRight(rightLength, true); if (!right.equals(omega.getString())) { @@ -391,8 +387,7 @@ public static void checkFillCursor(XTextCursor cursor) { public void nrCleanFillCursor(XTextDocument doc) throws NoDocumentException, - WrappedTargetException, - CreationException { + WrappedTargetException { // alwaysRemoveBrackets : full compatibility with JabRef 5.2: brackets are temporary, only // exist between nrGetFillCursor and nrCleanFillCursor. diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java index 306c0111a22..896e747913f 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java @@ -64,9 +64,6 @@ private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroup String citationKey = citedKey.citationKey; List clashingKeys = normCitMarkerToClachingKeys.putIfAbsent(normCitMarker, new ArrayList<>(1)); - if (clashingKeys == null) { - clashingKeys = normCitMarkerToClachingKeys.get(normCitMarker); - } if (!clashingKeys.contains(citationKey)) { // First appearance of citationKey, add to list. clashingKeys.add(citationKey); diff --git a/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java index d8e1832b6ef..aa09f36edef 100644 --- a/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java +++ b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java @@ -5,7 +5,6 @@ import org.jabref.model.openoffice.uno.CreationException; import org.jabref.model.openoffice.uno.NoDocumentException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; @@ -13,12 +12,12 @@ public interface NamedRange { - public String nrGetRangeName(); + String nrGetRangeName(); /** * @return Optional.empty if the mark is missing from the document. */ - public Optional nrGetMarkRange(XTextDocument doc) + Optional nrGetMarkRange(XTextDocument doc) throws NoDocumentException, WrappedTargetException; @@ -27,7 +26,7 @@ public Optional nrGetMarkRange(XTextDocument doc) * Cursor for the reference marks as is, not prepared for filling, but does not need * nrCleanFillCursor either. */ - public Optional nrGetRawCursor(XTextDocument doc) + Optional nrGetRawCursor(XTextDocument doc) throws NoDocumentException, WrappedTargetException; @@ -37,7 +36,7 @@ public Optional nrGetRawCursor(XTextDocument doc) * * Must be followed by nrCleanFillCursor() */ - public XTextCursor nrGetFillCursor(XTextDocument doc) + XTextCursor nrGetFillCursor(XTextDocument doc) throws NoDocumentException, WrappedTargetException, @@ -45,21 +44,19 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) /** * Remove brackets, but if the result would become empty, leave them; if the result would be a - * single characer, leave the left bracket. + * single character, leave the left bracket. * */ - public void nrCleanFillCursor(XTextDocument doc) + void nrCleanFillCursor(XTextDocument doc) throws NoDocumentException, - WrappedTargetException, - CreationException; + WrappedTargetException; /** * Note: create is in NamedRangeManager */ - public void nrRemoveFromDocument(XTextDocument doc) + void nrRemoveFromDocument(XTextDocument doc) throws WrappedTargetException, - NoDocumentException, - NoSuchElementException; + NoDocumentException; } diff --git a/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java b/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java index f53fcc72527..536871b5c34 100644 --- a/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java +++ b/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java @@ -12,19 +12,19 @@ public interface NamedRangeManager { - public NamedRange nrmCreate(XTextDocument doc, - String markName, - XTextCursor position, - boolean insertSpaceAfter, - boolean withoutBrackets) + NamedRange nrmCreate(XTextDocument doc, + String markName, + XTextCursor position, + boolean insertSpaceAfter, + boolean withoutBrackets) throws CreationException; - public List nrmGetUsedNames(XTextDocument doc) + List nrmGetUsedNames(XTextDocument doc) throws NoDocumentException; - public Optional nrmGetFromDocument(XTextDocument doc, String markName) + Optional nrmGetFromDocument(XTextDocument doc, String markName) throws NoDocumentException, WrappedTargetException; From f33bafa85acf3a069bce7384d57ba2ae7e89fed0 Mon Sep 17 00:00:00 2001 From: Antal K Date: Fri, 20 Aug 2021 12:09:54 +0200 Subject: [PATCH 091/103] apply 2021-08-20-a/oobranch-E-update.patch Brings oobranch-E up to 89b096881 @ origin/improve-reversibility-rebased-03 Merge remote-tracking branch 'upstream/main' into improve-reversibility-rebased-03 --- .../logic/openoffice/backend/Backend52.java | 60 +++++-------------- .../logic/openoffice/backend/Codec52.java | 19 +++--- .../logic/openoffice/backend/GetContext.java | 8 +-- .../backend/NamedRangeReferenceMark.java | 35 +++++------ .../style/OOProcessAuthorYearMarkers.java | 3 - .../model/openoffice/backend/NamedRange.java | 21 +++---- .../openoffice/backend/NamedRangeManager.java | 14 ++--- 7 files changed, 58 insertions(+), 102 deletions(-) diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java index c03bd24496a..878571090f0 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java @@ -28,10 +28,7 @@ import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; @@ -39,11 +36,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** - * Backend52, Codec52 and OODataModel.JabRef52 refer to the mode of storage, encoding and - * what-is-stored in the document under JabRef version 5.2. These basically did not change up to - * JabRef 5.4. - */ public class Backend52 { private static final Logger LOGGER = LoggerFactory.getLogger(Backend52.class); public final OODataModel dataModel; @@ -118,25 +110,17 @@ public Optional healthReport(XTextDocument doc) private static void setPageInfoInDataInitial(List citations, Optional pageInfo) { // attribute to last citation (initially localOrder == storageOrder) - if (citations.size() > 0) { - citations.get(citations.size() - 1).setPageInfo(pageInfo); - } - } - - private static void setPageInfoInData(CitationGroup cg, Optional pageInfo) { - List citations = cg.getCitationsInLocalOrder(); - if (citations.size() > 0) { + if (!citations.isEmpty()) { citations.get(citations.size() - 1).setPageInfo(pageInfo); } } private static Optional getPageInfoFromData(CitationGroup cg) { List citations = cg.getCitationsInLocalOrder(); - if (citations.size() > 0) { - return citations.get(citations.size() - 1).getPageInfo(); - } else { + if (citations.isEmpty()) { return Optional.empty(); } + return citations.get(citations.size() - 1).getPageInfo(); } /** @@ -148,20 +132,18 @@ public CitationGroup readCitationGroupFromDocumentOrThrow(XTextDocument doc, Str WrappedTargetException, NoDocumentException { - Optional op = Codec52.parseMarkName(refMarkName); - if (op.isEmpty()) { + Optional optionalParsed = Codec52.parseMarkName(refMarkName); + if (optionalParsed.isEmpty()) { throw new IllegalArgumentException("readCitationGroupFromDocumentOrThrow:" + " found unparsable referenceMarkName"); } - Codec52.ParsedMarkName ov = op.get(); - CitationGroupId cgid = new CitationGroupId(refMarkName); - List citations = (ov.citationKeys.stream() + Codec52.ParsedMarkName parsed = optionalParsed.get(); + List citations = (parsed.citationKeys.stream() .map(Citation::new) .collect(Collectors.toList())); - Optional pageInfo = - (UnoUserDefinedProperty.getStringValue(doc, refMarkName) - .map(OOText::fromString)); + Optional pageInfo = (UnoUserDefinedProperty.getStringValue(doc, refMarkName) + .map(OOText::fromString)); pageInfo = PageInfo.normalizePageInfo(pageInfo); setPageInfoInDataInitial(citations, pageInfo); @@ -173,9 +155,10 @@ public CitationGroup readCitationGroupFromDocumentOrThrow(XTextDocument doc, Str + " referenceMarkName is not in the document"); } + CitationGroupId cgid = new CitationGroupId(refMarkName); CitationGroup cg = new CitationGroup(OODataModel.JabRef52, cgid, - ov.citationType, + parsed.citationType, citations, Optional.of(refMarkName)); this.cgidToNamedRange.put(cgid, namedRange.get()); @@ -203,7 +186,6 @@ public CitationGroup createCitationGroup(XTextDocument doc, NoDocumentException, WrappedTargetException, NotRemoveableException, - PropertyExistException, PropertyVetoException, IllegalTypeException { @@ -243,6 +225,8 @@ public CitationGroup createCitationGroup(XTextDocument doc, case JabRef60: cit.setPageInfo(pageInfo); break; + default: + throw new IllegalStateException("Unhandled dataModel in Backend52.createCitationGroup"); } } @@ -325,7 +309,6 @@ public List> combinePageInfos(List joinableGroup private NamedRange getNamedRangeOrThrow(CitationGroup cg) { NamedRange namedRange = this.cgidToNamedRange.get(cg.cgid); if (namedRange == null) { - String msg = "getNamedRange: could not lookup namedRange"; throw new IllegalStateException("getNamedRange: could not lookup namedRange"); } return namedRange; @@ -335,11 +318,7 @@ public void removeCitationGroup(CitationGroup cg, XTextDocument doc) throws WrappedTargetException, NoDocumentException, - NoSuchElementException, - NotRemoveableException, - IllegalTypeException, - PropertyExistException { - + NotRemoveableException { NamedRange namedRange = getNamedRangeOrThrow(cg); String refMarkName = namedRange.nrGetRangeName(); namedRange.nrRemoveFromDocument(doc); @@ -388,15 +367,13 @@ public XTextCursor getFillCursorForCitationGroup(CitationGroup cg, XTextDocument public void cleanFillCursorForCitationGroup(CitationGroup cg, XTextDocument doc) throws NoDocumentException, - WrappedTargetException, - CreationException { + WrappedTargetException { NamedRange namedRange = getNamedRangeOrThrow(cg); namedRange.nrCleanFillCursor(doc); } public List getCitationEntries(XTextDocument doc, CitationGroups cgs) throws - UnknownPropertyException, WrappedTargetException, NoDocumentException { @@ -404,8 +381,7 @@ public List getCitationEntries(XTextDocument doc, CitationGroups case JabRef52: // One context per CitationGroup: Backend52 (DataModel.JabRef52) // For DataModel.JabRef60 (Backend60) we need one context per Citation - int n = cgs.numberOfCitationGroups(); - List citations = new ArrayList<>(n); + List citations = new ArrayList<>(cgs.numberOfCitationGroups()); for (CitationGroup cg : cgs.getCitationGroupsUnordered()) { String name = cg.cgid.citationGroupIdAsString(); XTextCursor cursor = (this @@ -433,13 +409,9 @@ public List getCitationEntries(XTextDocument doc, CitationGroups */ public void applyCitationEntries(XTextDocument doc, List citationEntries) throws - UnknownPropertyException, - NotRemoveableException, - PropertyExistException, PropertyVetoException, IllegalTypeException, IllegalArgumentException, - NoDocumentException, WrappedTargetException { switch (dataModel) { diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java index 93f57e5d99d..f6d2b12245e 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java @@ -10,10 +10,9 @@ import java.util.stream.Collectors; import org.jabref.model.openoffice.style.CitationType; -import org.jabref.model.openoffice.uno.NoDocumentException; /** - * How and what is encoded in reference mark names under JabRef 5.2. + * How and what is encoded in a mark names. * * - pageInfo does not appear here. It is not encoded in the mark name. */ @@ -24,6 +23,10 @@ class Codec52 { // citationType is always "1" "2" or "3" Pattern.compile(BIB_CITATION + "(\\d*)_([123])_(.*)"); + private Codec52() { + /**/ + } + /** * This is what we get back from parsing a refMarkName. */ @@ -47,7 +50,7 @@ public static class ParsedMarkName { /** * Integer representation was written into the document in JabRef52, keep it for compatibility. */ - public static CitationType CitationTypeFromInt(int i) { + private static CitationType citationTypeFromInt(int i) { switch (i) { case 1: return CitationType.AUTHORYEAR_PAR; @@ -60,7 +63,7 @@ public static CitationType CitationTypeFromInt(int i) { } } - public static int CitationTypeToInt(CitationType i) { + private static int citationTypeToInt(CitationType i) { switch (i) { case AUTHORYEAR_PAR: return 1; @@ -86,12 +89,10 @@ public static int CitationTypeToInt(CitationType i) { */ public static String getUniqueMarkName(Set usedNames, String bibtexKey, - CitationType citationType) - throws - NoDocumentException { + CitationType citationType) { int i = 0; - int citTypeCode = CitationTypeToInt(citationType); + int citTypeCode = citationTypeToInt(citationType); String name = BIB_CITATION + '_' + citTypeCode + '_' + bibtexKey; while (usedNames.contains(name)) { name = BIB_CITATION + i + '_' + citTypeCode + '_' + bibtexKey; @@ -116,7 +117,7 @@ public static Optional parseMarkName(String refMarkName) { List keys = Arrays.asList(citeMatcher.group(3).split(",")); String i = citeMatcher.group(1); int citTypeCode = Integer.parseInt(citeMatcher.group(2)); - CitationType citationType = CitationTypeFromInt(citTypeCode); + CitationType citationType = citationTypeFromInt(citTypeCode); return (Optional.of(new Codec52.ParsedMarkName(i, citationType, keys))); } diff --git a/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java b/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java index 4cde12ad236..ffce5b9553e 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java @@ -1,8 +1,5 @@ package org.jabref.logic.openoffice.backend; -import org.jabref.model.openoffice.uno.NoDocumentException; - -import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,10 +31,7 @@ private GetContext() { public static String getCursorStringWithContext(XTextCursor cursor, int charBefore, int charAfter, - boolean htmlMarkup) - throws - WrappedTargetException, - NoDocumentException { + boolean htmlMarkup) { String citPart = cursor.getString(); 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 29a90601056..a11e29aecd1 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java @@ -8,7 +8,6 @@ import org.jabref.model.openoffice.uno.UnoCursor; import org.jabref.model.openoffice.uno.UnoReferenceMark; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XText; import com.sun.star.text.XTextContent; @@ -57,24 +56,24 @@ String getId() { * {@code safeInsertSpaces(n): para, para, left, space(n), right-delete, left(n), left-delete} * * @param position Where to insert (at position.getStart()) - * @param n Number of spaces to insert. + * @param numSpaces Number of spaces to insert. * * @return a new cursor, covering the just-inserted spaces. * */ - private static XTextCursor safeInsertSpacesBetweenReferenceMarks(XTextRange position, int n) { + private static XTextCursor safeInsertSpacesBetweenReferenceMarks(XTextRange position, int numSpaces) { // Start with an empty cursor at position.getStart(); XText text = position.getText(); XTextCursor cursor = text.createTextCursorByRange(position.getStart()); text.insertString(cursor, "\r\r", false); // para, para cursor.goLeft((short) 1, false); // left - text.insertString(cursor, " ".repeat(n), false); // space(n) + text.insertString(cursor, " ".repeat(numSpaces), false); // space(numSpaces) cursor.goRight((short) 1, true); cursor.setString(""); // right-delete - cursor.goLeft((short) n, false); // left(n) + cursor.goLeft((short) numSpaces, false); // left(numSpaces) cursor.goLeft((short) 1, true); cursor.setString(""); // left-delete - cursor.goRight((short) n, true); // select the newly inserted spaces + cursor.goRight((short) numSpaces, true); // select the newly inserted spaces return cursor; } @@ -101,8 +100,6 @@ private static void createReprInDocument(XTextDocument doc, final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; - final short leftLength = (short) left.length(); - final short rightLength = (short) right.length(); String bracketedContent = (withoutBrackets ? "" : left + right); @@ -111,9 +108,11 @@ private static void createReprInDocument(XTextDocument doc, UnoReferenceMark.create(doc, refMarkName, cursor, true /* absorb */); + // eat the first inserted space cursorBefore.goRight((short) 1, true); cursorBefore.setString(""); if (!insertSpaceAfter) { + // eat the second inserted space cursorAfter.goLeft((short) 1, true); cursorAfter.setString(""); } @@ -151,8 +150,7 @@ static Optional getFromDocument(XTextDocument doc, Stri public void nrRemoveFromDocument(XTextDocument doc) throws WrappedTargetException, - NoDocumentException, - NoSuchElementException { + NoDocumentException { UnoReferenceMark.removeIfExists(doc, this.nrGetRangeName()); } @@ -193,7 +191,6 @@ public Optional nrGetRawCursor(XTextDocument doc) WrappedTargetException { String name = this.nrGetRangeName(); - Optional full = Optional.empty(); Optional markAsTextContent = UnoReferenceMark.getAsTextContent(doc, name); @@ -201,10 +198,9 @@ public Optional nrGetRawCursor(XTextDocument doc) LOGGER.warn("nrGetRawCursor: markAsTextContent({}).isEmpty()", name); } - full = UnoCursor.getTextCursorOfTextContentAnchor(markAsTextContent.get()); + Optional full = UnoCursor.getTextCursorOfTextContentAnchor(markAsTextContent.get()); if (full.isEmpty()) { - String msg = "nrGetRawCursor: full.isEmpty()"; - LOGGER.warn(msg); + LOGGER.warn("nrGetRawCursor: full.isEmpty()"); return Optional.empty(); } return full; @@ -224,8 +220,6 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; - final short leftLength = (short) left.length(); - final short rightLength = (short) right.length(); final boolean debugThisFun = false; XTextCursor full = null; @@ -286,6 +280,7 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) beta.goRight((short) (fullText.length() - 2), true); LOGGER.debug("nrGetFillCursor: beta(1) covers '{}'", beta.getString()); + final short rightLength = (short) right.length(); if (fullText.startsWith(left) && fullText.endsWith(right)) { beta.setString(""); } else { @@ -334,6 +329,7 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) beta.setString(""); // should be OK now. if (debugThisFun) { + final short leftLength = (short) left.length(); alpha.goRight(leftLength, true); LOGGER.debug("nrGetFillCursor: alpha(7) covers '{}', should be '{}'", alpha.getString(), left); omega.goLeft(rightLength, true); @@ -351,8 +347,6 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) public static void checkFillCursor(XTextCursor cursor) { final String left = REFERENCE_MARK_LEFT_BRACKET; final String right = REFERENCE_MARK_RIGHT_BRACKET; - final short leftLength = (short) left.length(); - final short rightLength = (short) right.length(); XTextCursor alpha = cursor.getText().createTextCursorByRange(cursor); alpha.collapseToStart(); @@ -360,6 +354,7 @@ public static void checkFillCursor(XTextCursor cursor) { XTextCursor omega = cursor.getText().createTextCursorByRange(cursor); omega.collapseToEnd(); + final short leftLength = (short) left.length(); if (leftLength > 0) { alpha.goLeft(leftLength, true); if (!left.equals(alpha.getString())) { @@ -370,6 +365,7 @@ public static void checkFillCursor(XTextCursor cursor) { } } + final short rightLength = (short) right.length(); if (rightLength > 0) { omega.goRight(rightLength, true); if (!right.equals(omega.getString())) { @@ -391,8 +387,7 @@ public static void checkFillCursor(XTextCursor cursor) { public void nrCleanFillCursor(XTextDocument doc) throws NoDocumentException, - WrappedTargetException, - CreationException { + WrappedTargetException { // alwaysRemoveBrackets : full compatibility with JabRef 5.2: brackets are temporary, only // exist between nrGetFillCursor and nrCleanFillCursor. diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java index 306c0111a22..896e747913f 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java @@ -64,9 +64,6 @@ private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroup String citationKey = citedKey.citationKey; List clashingKeys = normCitMarkerToClachingKeys.putIfAbsent(normCitMarker, new ArrayList<>(1)); - if (clashingKeys == null) { - clashingKeys = normCitMarkerToClachingKeys.get(normCitMarker); - } if (!clashingKeys.contains(citationKey)) { // First appearance of citationKey, add to list. clashingKeys.add(citationKey); diff --git a/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java index d8e1832b6ef..aa09f36edef 100644 --- a/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java +++ b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java @@ -5,7 +5,6 @@ import org.jabref.model.openoffice.uno.CreationException; import org.jabref.model.openoffice.uno.NoDocumentException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; @@ -13,12 +12,12 @@ public interface NamedRange { - public String nrGetRangeName(); + String nrGetRangeName(); /** * @return Optional.empty if the mark is missing from the document. */ - public Optional nrGetMarkRange(XTextDocument doc) + Optional nrGetMarkRange(XTextDocument doc) throws NoDocumentException, WrappedTargetException; @@ -27,7 +26,7 @@ public Optional nrGetMarkRange(XTextDocument doc) * Cursor for the reference marks as is, not prepared for filling, but does not need * nrCleanFillCursor either. */ - public Optional nrGetRawCursor(XTextDocument doc) + Optional nrGetRawCursor(XTextDocument doc) throws NoDocumentException, WrappedTargetException; @@ -37,7 +36,7 @@ public Optional nrGetRawCursor(XTextDocument doc) * * Must be followed by nrCleanFillCursor() */ - public XTextCursor nrGetFillCursor(XTextDocument doc) + XTextCursor nrGetFillCursor(XTextDocument doc) throws NoDocumentException, WrappedTargetException, @@ -45,21 +44,19 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) /** * Remove brackets, but if the result would become empty, leave them; if the result would be a - * single characer, leave the left bracket. + * single character, leave the left bracket. * */ - public void nrCleanFillCursor(XTextDocument doc) + void nrCleanFillCursor(XTextDocument doc) throws NoDocumentException, - WrappedTargetException, - CreationException; + WrappedTargetException; /** * Note: create is in NamedRangeManager */ - public void nrRemoveFromDocument(XTextDocument doc) + void nrRemoveFromDocument(XTextDocument doc) throws WrappedTargetException, - NoDocumentException, - NoSuchElementException; + NoDocumentException; } diff --git a/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java b/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java index f53fcc72527..536871b5c34 100644 --- a/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java +++ b/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java @@ -12,19 +12,19 @@ public interface NamedRangeManager { - public NamedRange nrmCreate(XTextDocument doc, - String markName, - XTextCursor position, - boolean insertSpaceAfter, - boolean withoutBrackets) + NamedRange nrmCreate(XTextDocument doc, + String markName, + XTextCursor position, + boolean insertSpaceAfter, + boolean withoutBrackets) throws CreationException; - public List nrmGetUsedNames(XTextDocument doc) + List nrmGetUsedNames(XTextDocument doc) throws NoDocumentException; - public Optional nrmGetFromDocument(XTextDocument doc, String markName) + Optional nrmGetFromDocument(XTextDocument doc, String markName) throws NoDocumentException, WrappedTargetException; From 1fcb009e1016a2041294d1c923cda2f44fa75598 Mon Sep 17 00:00:00 2001 From: Antal K Date: Fri, 20 Aug 2021 14:41:34 +0200 Subject: [PATCH 092/103] sync to improve-reversibility-rebased-03 cb132566f32cba17af24b41d037446a96a90dc16 commit cb132566f32cba17af24b41d037446a96a90dc16 (HEAD -> improve-reversibility-rebased-03, origin/improve-reversibility-rebased-03) Author: Antal K Date: Fri Aug 20 11:39:39 2021 +0200 align dots --- .../org/jabref/gui/openoffice/OOBibBase2.java | 102 ++---- .../gui/openoffice/OOBibBaseConnect.java | 4 - .../logic/openoffice/action/EditInsert.java | 16 +- .../logic/openoffice/action/EditMerge.java | 52 +-- .../logic/openoffice/action/EditSeparate.java | 24 +- .../logic/openoffice/action/ExportCited.java | 8 +- .../openoffice/action/ManageCitations.java | 11 +- .../logic/openoffice/action/Update.java | 24 +- .../logic/openoffice/backend/Backend52.java | 340 +++++++++--------- .../logic/openoffice/backend/Codec52.java | 56 ++- .../NamedRangeManagerReferenceMark.java | 14 +- .../backend/NamedRangeReferenceMark.java | 79 ++-- .../logic/openoffice/frontend/OOFrontend.java | 131 +++---- .../frontend/UpdateBibliography.java | 18 +- .../frontend/UpdateCitationMarkers.java | 55 ++- .../style/OOFormatBibliography.java | 12 +- .../style/OOProcessAuthorYearMarkers.java | 15 +- .../style/OOProcessCitationKeyMarkers.java | 6 +- .../style/OOProcessNumericMarkers.java | 6 +- .../model/openoffice/backend/NamedRange.java | 25 +- .../openoffice/backend/NamedRangeManager.java | 14 +- .../model/openoffice/ootext/OOTextIntoOO.java | 248 ++++++------- .../model/openoffice/style/CitationGroup.java | 6 +- .../openoffice/style/CitationGroups.java | 54 +-- .../model/openoffice/style/CitationType.java | 4 +- 25 files changed, 602 insertions(+), 722 deletions(-) diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java index 29829b9e038..9832adb991d 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java @@ -40,16 +40,13 @@ import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; import com.sun.star.comp.helper.BootstrapException; import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.DisposedException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; -import com.sun.star.util.InvalidStateException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -256,13 +253,7 @@ private static OOVoidResult checkRangeOverlapsWithCursor(XTextDocument final String title = "checkRangeOverlapsWithCursor"; List> userRanges; - try { - userRanges = fr.viewCursorRanges(doc); - } catch (NoDocumentException ex) { - return OOVoidResult.error(OOError.from(ex).setTitle(title)); - } catch (WrappedTargetException ex) { - return OOVoidResult.error(OOError.fromMisc(ex).setTitle(title)); - } + userRanges = fr.viewCursorRanges(doc); boolean requireSeparation = false; OOVoidResult res; @@ -370,7 +361,6 @@ private OOVoidResult checkStyleExistsInTheDocument(String familyName, String labelInJstyleFile, String pathToStyleFile) throws - NoSuchElementException, WrappedTargetException { Optional internalName = UnoStyle.getInternalNameOfStyle(doc, familyName, styleName); @@ -378,18 +368,18 @@ private OOVoidResult checkStyleExistsInTheDocument(String familyName, if (internalName.isEmpty()) { String msg = switch (familyName) { - case UnoStyle.PARAGRAPH_STYLES -> - Localization.lang("The %0 paragraph style '%1' is missing from the document", - labelInJstyleFile, - styleName); - case UnoStyle.CHARACTER_STYLES -> - Localization.lang("The %0 character style '%1' is missing from the document", - labelInJstyleFile, - styleName); - default -> - throw new IllegalArgumentException("Expected " + UnoStyle.CHARACTER_STYLES - + " or " + UnoStyle.PARAGRAPH_STYLES - + " for familyName"); + case UnoStyle.PARAGRAPH_STYLES -> + Localization.lang("The %0 paragraph style '%1' is missing from the document", + labelInJstyleFile, + styleName); + case UnoStyle.CHARACTER_STYLES -> + Localization.lang("The %0 character style '%1' is missing from the document", + labelInJstyleFile, + styleName); + default -> + throw new IllegalArgumentException("Expected " + UnoStyle.CHARACTER_STYLES + + " or " + UnoStyle.PARAGRAPH_STYLES + + " for familyName"); } + "\n" + Localization.lang("Please create it in the document or change in the file:") @@ -401,20 +391,20 @@ private OOVoidResult checkStyleExistsInTheDocument(String familyName, if (!internalName.get().equals(styleName)) { String msg = switch (familyName) { - case UnoStyle.PARAGRAPH_STYLES -> - Localization.lang("The %0 paragraph style '%1' is a display name for '%2'.", - labelInJstyleFile, - styleName, - internalName.get()); - case UnoStyle.CHARACTER_STYLES -> - Localization.lang("The %0 character style '%1' is a display name for '%2'.", - labelInJstyleFile, - styleName, - internalName.get()); - default -> - throw new IllegalArgumentException("Expected " + UnoStyle.CHARACTER_STYLES - + " or " + UnoStyle.PARAGRAPH_STYLES - + " for familyName"); + case UnoStyle.PARAGRAPH_STYLES -> + Localization.lang("The %0 paragraph style '%1' is a display name for '%2'.", + labelInJstyleFile, + styleName, + internalName.get()); + case UnoStyle.CHARACTER_STYLES -> + Localization.lang("The %0 character style '%1' is a display name for '%2'.", + labelInJstyleFile, + styleName, + internalName.get()); + default -> + throw new IllegalArgumentException("Expected " + UnoStyle.CHARACTER_STYLES + + " or " + UnoStyle.PARAGRAPH_STYLES + + " for familyName"); } + "\n" + Localization.lang("Please use the latter in the style file below" @@ -449,8 +439,7 @@ public OOVoidResult checkStylesExistInTheDocument(OOBibStyle style, XTe "CitationCharacterFormat", pathToStyleFile)); } - } catch (NoSuchElementException - | WrappedTargetException ex) { + } catch (WrappedTargetException ex) { results.add(OOVoidResult.error(new OOError("Other error in checkStyleExistsInTheDocument", ex.getMessage(), ex))); @@ -490,8 +479,7 @@ public Optional> guiActionGetCitationEntries() { } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); return FAIL; - } catch (UnknownPropertyException - | WrappedTargetException ex) { + } catch (WrappedTargetException ex) { LOGGER.warn(title, ex); OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); return FAIL; @@ -541,10 +529,7 @@ public void guiActionApplyCitationEntries(List citationEntries) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); - } catch (UnknownPropertyException - | NotRemoveableException - | PropertyExistException - | PropertyVetoException + } catch (PropertyVetoException | IllegalTypeException | WrappedTargetException | com.sun.star.lang.IllegalArgumentException ex) { @@ -668,16 +653,10 @@ public void guiActionInsertEntry(List entries, } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); return; - } catch (JabRefException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); - return; } catch (CreationException | IllegalTypeException - | NoSuchElementException | NotRemoveableException - | PropertyExistException | PropertyVetoException - | UnknownPropertyException | WrappedTargetException ex) { LOGGER.warn("Could not insert entry", ex); OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); @@ -728,16 +707,10 @@ public void guiActionMergeCitationGroups(List databases, OOBibStyle OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); - } catch (JabRefException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (CreationException | IllegalTypeException - | InvalidStateException - | NoSuchElementException | NotRemoveableException - | PropertyExistException | PropertyVetoException - | UnknownPropertyException | WrappedTargetException | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn("Problem combining cite markers", ex); @@ -791,16 +764,10 @@ public void guiActionSeparateCitations(List databases, OOBibStyle s OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); - } catch (JabRefException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (CreationException | IllegalTypeException - | InvalidStateException - | NoSuchElementException | NotRemoveableException - | PropertyExistException | PropertyVetoException - | UnknownPropertyException | WrappedTargetException | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn("Problem during separating cite markers", ex); @@ -875,9 +842,7 @@ public Optional exportCitedHelper(List databases, OOError.from(ex).showErrorDialog(dialogService); } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); - } catch (NoSuchElementException - | UnknownPropertyException - | WrappedTargetException + } catch (WrappedTargetException | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn("Problem generating new database.", ex); OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); @@ -946,16 +911,11 @@ public void guiActionUpdateDocument(List databases, OOBibStyle styl return; } - } catch (JabRefException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (NoDocumentException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (CreationException - | NoSuchElementException - | PropertyVetoException - | UnknownPropertyException | WrappedTargetException | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn("Could not update bibliography", ex); diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java b/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java index c9f6246062b..728b5cf541e 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java @@ -25,16 +25,12 @@ import com.sun.star.lang.XMultiComponentFactory; import com.sun.star.text.XTextDocument; import com.sun.star.uno.XComponentContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Establish connection to a document opened in OpenOffice or LibreOffice. */ class OOBibBaseConnect { - private static final Logger LOGGER = LoggerFactory.getLogger(OOBibBaseConnect.class); - /* variables */ private final DialogService dialogService; private final XDesktop xDesktop; diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java index 1345f1f2a99..81491bd8590 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java @@ -5,7 +5,6 @@ import java.util.List; import java.util.Optional; -import org.jabref.logic.JabRefException; import org.jabref.logic.openoffice.frontend.OOFrontend; import org.jabref.logic.openoffice.frontend.UpdateCitationMarkers; import org.jabref.logic.openoffice.style.OOBibStyle; @@ -24,19 +23,16 @@ import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class EditInsert { - private static final Logger LOGGER = LoggerFactory.getLogger(EditInsert.class); + private EditInsert() { + /**/ + } /** * In insertEntry we receive BibEntry values from the GUI. @@ -68,16 +64,12 @@ public static void insertCitationGroup(XTextDocument doc, CitationType citationType, String pageInfo) throws - UnknownPropertyException, NoDocumentException, NotRemoveableException, WrappedTargetException, PropertyVetoException, - PropertyExistException, - NoSuchElementException, CreationException, - IllegalTypeException, - JabRefException { + IllegalTypeException { List citationKeys = OOListUtil.map(entries, EditInsert::insertEntryGetCitationKey); diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java index 4cd225eb1a8..43bdcd59e2d 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java @@ -6,7 +6,6 @@ import java.util.Optional; import java.util.stream.Collectors; -import org.jabref.logic.JabRefException; import org.jabref.logic.openoffice.frontend.OOFrontend; import org.jabref.logic.openoffice.frontend.UpdateCitationMarkers; import org.jabref.logic.openoffice.style.OOBibStyle; @@ -22,15 +21,11 @@ import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; import com.sun.star.text.XTextRange; -import com.sun.star.util.InvalidStateException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,14 +45,9 @@ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend fr, OOBi CreationException, IllegalArgumentException, IllegalTypeException, - InvalidStateException, - JabRefException, NoDocumentException, - NoSuchElementException, NotRemoveableException, - PropertyExistException, PropertyVetoException, - UnknownPropertyException, WrappedTargetException { boolean madeModifications = false; @@ -72,7 +62,7 @@ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend fr, OOBi List cgs = joinableGroupData.group; List newCitations = (cgs.stream() - .flatMap(cg -> cg.citationsInStorageOrder.stream()) + .flatMap(group -> group.citationsInStorageOrder.stream()) .collect(Collectors.toList())); CitationType citationType = cgs.get(0).citationType; @@ -155,15 +145,15 @@ void reset() { } /** - * Decide if cg could be added to state.currentGroup + * Decide if group could be added to state.currentGroup * - * @param cg The CitationGroup to test - * @param currentRange The XTextRange corresponding to cg. + * @param group The CitationGroup to test + * @param currentRange The XTextRange corresponding to group. * * @return false if cannot add, true if can. If returned true, then state.cursorBetween and * state.currentGroupCursor are expanded to end at the start of currentRange. */ - private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextRange currentRange) { + private static boolean checkAddToGroup(ScanState state, CitationGroup group, XTextRange currentRange) { if (state.currentGroup.isEmpty()) { return false; @@ -175,14 +165,14 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextR Objects.requireNonNull(state.prevRange); // Only combine (Author 2000) type citations - if (cg.citationType != CitationType.AUTHORYEAR_PAR) { + if (group.citationType != CitationType.AUTHORYEAR_PAR) { return false; } if (state.prev != null) { // Even if we combine AUTHORYEAR_INTEXT citations, we would not mix them with AUTHORYEAR_PAR - if (cg.citationType != state.prev.citationType) { + if (group.citationType != state.prev.citationType) { return false; } @@ -253,20 +243,16 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextR } } - if (!couldExpand) { - return false; - } - - return true; + return couldExpand; } /** - * Add cg to state.currentGroup + * Add group to state.currentGroup * Set state.cursorBetween to start at currentRange.getEnd() * Expand state.currentGroupCursor to also cover currentRange - * Set state.prev to cg, state.prevRange to currentRange + * Set state.prev to group, state.prevRange to currentRange */ - private static void addToCurrentGroup(ScanState state, CitationGroup cg, XTextRange currentRange) { + private static void addToCurrentGroup(ScanState state, CitationGroup group, XTextRange currentRange) { final boolean isNewGroup = state.currentGroup.isEmpty(); if (!isNewGroup) { Objects.requireNonNull(state.currentGroupCursor); @@ -276,7 +262,7 @@ private static void addToCurrentGroup(ScanState state, CitationGroup cg, XTextRa } // Add the current entry to a group. - state.currentGroup.add(cg); + state.currentGroup.add(group); // Set up cursorBetween to start at currentRange.getEnd() XTextRange rangeEnd = currentRange.getEnd(); @@ -297,7 +283,7 @@ private static void addToCurrentGroup(ScanState state, CitationGroup cg, XTextRa } /* Store data about last entry in currentGroup */ - state.prev = cg; + state.prev = group; state.prevRange = currentRange; } @@ -317,22 +303,22 @@ private static List scan(XTextDocument doc, OOFrontend fr) ScanState state = new ScanState(); - for (CitationGroup cg : cgs) { + for (CitationGroup group : cgs) { - XTextRange currentRange = (fr.getMarkRange(doc, cg) + XTextRange currentRange = (fr.getMarkRange(doc, group) .orElseThrow(IllegalStateException::new)); /* - * Decide if we add cg to the group. False when the group is empty. + * Decide if we add group to the group. False when the group is empty. */ - boolean addToGroup = checkAddToGroup(state, cg, currentRange); + boolean addToGroup = checkAddToGroup(state, group, currentRange); /* * Even if we do not add it to an existing group, we might use it to start a new group. * * Can it start a new group? */ - boolean canStartGroup = (cg.citationType == CitationType.AUTHORYEAR_PAR); + boolean canStartGroup = (group.citationType == CitationType.AUTHORYEAR_PAR); if (!addToGroup) { // close currentGroup @@ -344,7 +330,7 @@ private static List scan(XTextDocument doc, OOFrontend fr) } if (addToGroup || canStartGroup) { - addToCurrentGroup(state, cg, currentRange); + addToCurrentGroup(state, group, currentRange); } } diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java index 0293159d34f..fba50a93c6e 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java @@ -2,7 +2,6 @@ import java.util.List; -import org.jabref.logic.JabRefException; import org.jabref.logic.openoffice.frontend.OOFrontend; import org.jabref.logic.openoffice.frontend.UpdateCitationMarkers; import org.jabref.logic.openoffice.style.OOBibStyle; @@ -17,18 +16,18 @@ import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; import com.sun.star.text.XTextRange; -import com.sun.star.util.InvalidStateException; public class EditSeparate { + private EditSeparate() { + /**/ + } + public static boolean separateCitations(XTextDocument doc, OOFrontend fr, List databases, @@ -36,14 +35,9 @@ public static boolean separateCitations(XTextDocument doc, throws CreationException, IllegalTypeException, - InvalidStateException, - JabRefException, NoDocumentException, - NoSuchElementException, NotRemoveableException, - PropertyExistException, PropertyVetoException, - UnknownPropertyException, WrappedTargetException, com.sun.star.lang.IllegalArgumentException { @@ -61,19 +55,19 @@ public static boolean separateCitations(XTextDocument doc, try { UnoScreenRefresh.lockControllers(doc); - for (CitationGroup cg : cgs) { + for (CitationGroup group : cgs) { XTextRange range1 = (fr - .getMarkRange(doc, cg) + .getMarkRange(doc, group) .orElseThrow(IllegalStateException::new)); XTextCursor textCursor = range1.getText().createTextCursorByRange(range1); - List cits = cg.citationsInStorageOrder; + List cits = group.citationsInStorageOrder; if (cits.size() <= 1) { continue; } - fr.removeCitationGroup(cg, doc); + fr.removeCitationGroup(group, doc); // Now we own the content of cits // Create a citation group for each citation. @@ -86,7 +80,7 @@ public static boolean separateCitations(XTextDocument doc, doc, List.of(cit.citationKey), List.of(cit.getPageInfo()), - cg.citationType, + group.citationType, OOText.fromString(cit.citationKey), textCursor, style, diff --git a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java index ef7985d666a..26ed654de21 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java +++ b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java @@ -13,13 +13,15 @@ import org.jabref.model.openoffice.style.CitedKeys; import org.jabref.model.openoffice.uno.NoDocumentException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextDocument; public class ExportCited { + private ExportCited() { + /**/ + } + public static class GenerateDatabaseResult { /** * null: not done; isEmpty: no unresolved @@ -47,8 +49,6 @@ public static class GenerateDatabaseResult { public static GenerateDatabaseResult generateDatabase(XTextDocument doc, List databases) throws NoDocumentException, - NoSuchElementException, - UnknownPropertyException, WrappedTargetException { OOFrontend fr = new OOFrontend(doc); diff --git a/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java b/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java index 4046cbbe11b..9782261f612 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java +++ b/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java @@ -7,19 +7,19 @@ import org.jabref.model.openoffice.uno.NoDocumentException; import com.sun.star.beans.IllegalTypeException; -import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextDocument; public class ManageCitations { + private ManageCitations() { + /**/ + } + public static List getCitationEntries(XTextDocument doc) throws NoDocumentException, - UnknownPropertyException, WrappedTargetException { OOFrontend fr = new OOFrontend(doc); return fr.getCitationEntries(doc); @@ -28,9 +28,6 @@ public static List getCitationEntries(XTextDocument doc) public static void applyCitationEntries(XTextDocument doc, List citationEntries) throws NoDocumentException, - UnknownPropertyException, - NotRemoveableException, - PropertyExistException, PropertyVetoException, IllegalTypeException, WrappedTargetException, diff --git a/src/main/java/org/jabref/logic/openoffice/action/Update.java b/src/main/java/org/jabref/logic/openoffice/action/Update.java index 675afb2a79f..49f79d6d2e7 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/Update.java +++ b/src/main/java/org/jabref/logic/openoffice/action/Update.java @@ -2,7 +2,6 @@ import java.util.List; -import org.jabref.logic.JabRefException; import org.jabref.logic.openoffice.frontend.OOFrontend; import org.jabref.logic.openoffice.frontend.UpdateBibliography; import org.jabref.logic.openoffice.frontend.UpdateCitationMarkers; @@ -14,9 +13,6 @@ import org.jabref.model.openoffice.uno.NoDocumentException; import org.jabref.model.openoffice.uno.UnoScreenRefresh; -import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextDocument; @@ -25,6 +21,10 @@ */ public class Update { + private Update() { + /**/ + } + /** * @return the list of unresolved citation keys */ @@ -37,11 +37,7 @@ private static List updateDocument(XTextDocument doc, boolean alwaysAddCitedOnPages) throws CreationException, - JabRefException, NoDocumentException, - NoSuchElementException, - PropertyVetoException, - UnknownPropertyException, WrappedTargetException, com.sun.star.lang.IllegalArgumentException { @@ -64,8 +60,8 @@ private static List updateDocument(XTextDocument doc, style, alwaysAddCitedOnPages); } - List result = fr.citationGroups.getUnresolvedKeys(); - return result; + + return fr.citationGroups.getUnresolvedKeys(); } finally { if (useLockControllers && UnoScreenRefresh.hasControllersLocked(doc)) { UnoScreenRefresh.unlockControllers(doc); @@ -103,11 +99,7 @@ public static List synchronizeDocument(XTextDocument doc, SyncOptions syncOptions) throws CreationException, - JabRefException, NoDocumentException, - NoSuchElementException, - PropertyVetoException, - UnknownPropertyException, WrappedTargetException, com.sun.star.lang.IllegalArgumentException { @@ -129,11 +121,7 @@ public static List resyncDocument(XTextDocument doc, SyncOptions syncOptions) throws CreationException, - JabRefException, NoDocumentException, - NoSuchElementException, - PropertyVetoException, - UnknownPropertyException, WrappedTargetException, com.sun.star.lang.IllegalArgumentException { diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java index 878571090f0..0016e5e4510 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java @@ -36,6 +36,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Backend52, Codec52 and OODataModel.JabRef52 refer to the mode of storage, encoding and + * what-is-stored in the document under JabRef version 5.2. These basically did not change up to + * JabRef 5.4. + */ public class Backend52 { private static final Logger LOGGER = LoggerFactory.getLogger(Backend52.class); public final OODataModel dataModel; @@ -59,7 +64,7 @@ public Backend52() { public List getJabRefReferenceMarkNames(XTextDocument doc) throws NoDocumentException { - List allNames = this.citationStorageManager.nrmGetUsedNames(doc); + List allNames = this.citationStorageManager.getUsedNames(doc); return Codec52.filterIsJabRefReferenceMarkName(allNames); } @@ -73,8 +78,7 @@ public List getJabRefReferenceMarkNames(XTextDocument doc) private List findUnusedJabrefPropertyNames(XTextDocument doc, List citationGroupNames) { - // Collect unused jabrefPropertyNames - Set citationGroupNamesSet = citationGroupNames.stream().collect(Collectors.toSet()); + Set citationGroupNamesSet = new HashSet<>(citationGroupNames); List pageInfoThrash = new ArrayList<>(); List jabrefPropertyNames = @@ -99,13 +103,13 @@ public Optional healthReport(XTextDocument doc) List pageInfoThrash = this.findUnusedJabrefPropertyNames(doc, this.getJabRefReferenceMarkNames(doc)); if (pageInfoThrash.isEmpty()) { - return Optional.empty(); // "Backend52: found no unused pageInfo data"; + return Optional.empty(); } - String msg = - "Backend52: found unused pageInfo data, with names listed below.\n" - + "In LibreOffice you may remove these in [File]/[Properties]/[Custom Properties]\n"; - msg += "" + String.join("\n", pageInfoThrash) + ""; - return Optional.of(msg); + + StringBuilder msg = new StringBuilder("Backend52: found unused pageInfo data, with names listed below.\n"); + msg.append("In LibreOffice you may remove these in [File]/[Properties]/[Custom Properties]\n"); + msg.append(String.join("\n", pageInfoThrash)); + return Optional.of(msg.toString()); } private static void setPageInfoInDataInitial(List citations, Optional pageInfo) { @@ -115,8 +119,8 @@ private static void setPageInfoInDataInitial(List citations, Optional< } } - private static Optional getPageInfoFromData(CitationGroup cg) { - List citations = cg.getCitationsInLocalOrder(); + private static Optional getPageInfoFromData(CitationGroup group) { + List citations = group.getCitationsInLocalOrder(); if (citations.isEmpty()) { return Optional.empty(); } @@ -124,54 +128,52 @@ private static Optional getPageInfoFromData(CitationGroup cg) { } /** - * We have circular dependency here: backend uses - * class from ... + * @param markName Reference mark name */ - public CitationGroup readCitationGroupFromDocumentOrThrow(XTextDocument doc, String refMarkName) + public CitationGroup readCitationGroupFromDocumentOrThrow(XTextDocument doc, String markName) throws WrappedTargetException, NoDocumentException { - Optional optionalParsed = Codec52.parseMarkName(refMarkName); - if (optionalParsed.isEmpty()) { - throw new IllegalArgumentException("readCitationGroupFromDocumentOrThrow:" - + " found unparsable referenceMarkName"); - } - Codec52.ParsedMarkName parsed = optionalParsed.get(); + Codec52.ParsedMarkName parsed = Codec52.parseMarkName(markName).orElseThrow(IllegalArgumentException::new); + List citations = (parsed.citationKeys.stream() .map(Citation::new) .collect(Collectors.toList())); - Optional pageInfo = (UnoUserDefinedProperty.getStringValue(doc, refMarkName) + Optional pageInfo = (UnoUserDefinedProperty.getStringValue(doc, markName) .map(OOText::fromString)); pageInfo = PageInfo.normalizePageInfo(pageInfo); setPageInfoInDataInitial(citations, pageInfo); - Optional namedRange = citationStorageManager.nrmGetFromDocument(doc, refMarkName); - - if (namedRange.isEmpty()) { - throw new IllegalArgumentException("readCitationGroupFromDocumentOrThrow:" - + " referenceMarkName is not in the document"); - } - - CitationGroupId cgid = new CitationGroupId(refMarkName); - CitationGroup cg = new CitationGroup(OODataModel.JabRef52, - cgid, - parsed.citationType, - citations, - Optional.of(refMarkName)); - this.cgidToNamedRange.put(cgid, namedRange.get()); - return cg; + NamedRange namedRange = (citationStorageManager.getNamedRangeFromDocument(doc, markName) + .orElseThrow(IllegalArgumentException::new)); + + CitationGroupId groupId = new CitationGroupId(markName); + CitationGroup group = new CitationGroup(OODataModel.JabRef52, + groupId, + parsed.citationType, + citations, + Optional.of(markName)); + this.cgidToNamedRange.put(groupId, namedRange); + return group; } /** - * Create a reference mark with the given name, at the end of position. + * Create a reference mark at the end of {@code position} in the document. * * On return {@code position} is collapsed, and is after the inserted space, or at the end of * the reference mark. * + * @param citationKeys Keys to be cited. + * + * @param pageInfos An optional pageInfo for each citation key. + * Backend52 only uses and stores the last pageInfo, + * all others should be Optional.empty() + * * @param position Collapsed to its end. + * * @param insertSpaceAfter We insert a space after the mark, that carries on format of * characters from the original position. */ @@ -191,42 +193,46 @@ public CitationGroup createCitationGroup(XTextDocument doc, Objects.requireNonNull(pageInfos); if (pageInfos.size() != citationKeys.size()) { - throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); + throw new IllegalArgumentException(); } - // Get a new refMarkName - Set usedNames = new HashSet<>(this.citationStorageManager.nrmGetUsedNames(doc)); - String xkey = (citationKeys.stream().collect(Collectors.joining(","))); - String refMarkName = Codec52.getUniqueMarkName(usedNames, xkey, citationType); + /* + * Backend52 uses reference marks to (1) mark the location of the citation in the text and (2) to encode + * the citation keys and citation type in the name of the reference mark. The name of the reference mark + * has to be unique in the document. + */ + String markName = Codec52.getUniqueMarkName(new HashSet<>(citationStorageManager.getUsedNames(doc)), + citationKeys, + citationType); - CitationGroupId cgid = new CitationGroupId(refMarkName); + CitationGroupId groupId = new CitationGroupId(markName); - final int nCitations = citationKeys.size(); - final int last = nCitations - 1; + final int numberOfCitations = citationKeys.size(); + final int last = numberOfCitations - 1; // Build citations, add pageInfo to each citation - List citations = new ArrayList<>(nCitations); - for (int i = 0; i < nCitations; i++) { + List citations = new ArrayList<>(numberOfCitations); + for (int i = 0; i < numberOfCitations; i++) { Citation cit = new Citation(citationKeys.get(i)); citations.add(cit); Optional pageInfo = PageInfo.normalizePageInfo(pageInfos.get(i)); switch (dataModel) { - case JabRef52: - if (i == last) { - cit.setPageInfo(pageInfo); - } else { - if (pageInfo.isPresent()) { - LOGGER.warn("dataModel JabRef52" - + " only supports pageInfo for the last citation of a group"); + case JabRef52: + if (i == last) { + cit.setPageInfo(pageInfo); + } else { + if (pageInfo.isPresent()) { + LOGGER.warn("dataModel JabRef52" + + " only supports pageInfo for the last citation of a group"); + } } - } - break; - case JabRef60: - cit.setPageInfo(pageInfo); - break; - default: - throw new IllegalStateException("Unhandled dataModel in Backend52.createCitationGroup"); + break; + case JabRef60: + cit.setPageInfo(pageInfo); + break; + default: + throw new IllegalStateException("Unhandled dataModel in Backend52.createCitationGroup"); } } @@ -234,29 +240,33 @@ public CitationGroup createCitationGroup(XTextDocument doc, * Apply to document */ boolean withoutBrackets = (citationType == CitationType.INVISIBLE_CIT); - NamedRange namedRange = - this.citationStorageManager.nrmCreate(doc, refMarkName, position, insertSpaceAfter, - withoutBrackets); + NamedRange namedRange = this.citationStorageManager.createNamedRange(doc, + markName, + position, + insertSpaceAfter, + withoutBrackets); switch (dataModel) { - case JabRef52: - Optional pageInfo = PageInfo.normalizePageInfo(pageInfos.get(last)); - - if (pageInfo.isPresent()) { - String pageInfoString = OOText.toString(pageInfo.get()); - UnoUserDefinedProperty.setStringProperty(doc, refMarkName, pageInfoString); - } else { - // do not inherit from trash - UnoUserDefinedProperty.removeIfExists(doc, refMarkName); - } - CitationGroup cg = new CitationGroup(OODataModel.JabRef52, - cgid, - citationType, citations, - Optional.of(refMarkName)); - this.cgidToNamedRange.put(cgid, namedRange); - return cg; - default: - throw new IllegalStateException("Backend52 requires JabRef52 dataModel"); + case JabRef52: + Optional pageInfo = PageInfo.normalizePageInfo(pageInfos.get(last)); + + if (pageInfo.isPresent()) { + String pageInfoString = OOText.toString(pageInfo.get()); + UnoUserDefinedProperty.setStringProperty(doc, markName, pageInfoString); + } else { + // do not inherit from trash + UnoUserDefinedProperty.removeIfExists(doc, markName); + } + CitationGroup group = new CitationGroup(OODataModel.JabRef52, + groupId, + citationType, citations, + Optional.of(markName)); + this.cgidToNamedRange.put(groupId, namedRange); + return group; + case JabRef60: + throw new IllegalStateException("createCitationGroup for JabRef60 is not implemented yet"); + default: + throw new IllegalStateException("Unhandled dataModel in Backend52.createCitationGroup"); } } @@ -269,33 +279,33 @@ public CitationGroup createCitationGroup(XTextDocument doc, public static List> combinePageInfosCommon(OODataModel dataModel, List joinableGroup) { switch (dataModel) { - case JabRef52: - // collect to cgPageInfos - List> cgPageInfos = OOListUtil.map(joinableGroup, - Backend52::getPageInfoFromData); - - // Try to do something of the cgPageInfos. - String cgPageInfo = (cgPageInfos.stream() - .filter(pi -> pi.isPresent()) - .map(pi -> OOText.toString(pi.get())) - .distinct() - .collect(Collectors.joining("; "))); - - int nCitations = (joinableGroup.stream() - .map(CitationGroup::numberOfCitations) - .mapToInt(Integer::intValue).sum()); - if ("".equals(cgPageInfo)) { - cgPageInfo = null; - } - return OODataModel.fakePageInfos(cgPageInfo, nCitations); - - case JabRef60: - return (joinableGroup.stream() - .flatMap(cg -> (cg.citationsInStorageOrder.stream() - .map(Citation::getPageInfo))) - .collect(Collectors.toList())); - default: - throw new IllegalArgumentException("unhandled dataModel here"); + case JabRef52: + // collect to pageInfos + List> pageInfos = OOListUtil.map(joinableGroup, + Backend52::getPageInfoFromData); + + // Try to do something of the pageInfos. + String singlePageInfo = (pageInfos.stream() + .filter(Optional::isPresent) + .map(pi -> OOText.toString(pi.get())) + .distinct() + .collect(Collectors.joining("; "))); + + int totalCitations = (joinableGroup.stream() + .map(CitationGroup::numberOfCitations) + .mapToInt(Integer::intValue).sum()); + if ("".equals(singlePageInfo)) { + singlePageInfo = null; + } + return OODataModel.fakePageInfos(singlePageInfo, totalCitations); + + case JabRef60: + return (joinableGroup.stream() + .flatMap(group -> (group.citationsInStorageOrder.stream() + .map(Citation::getPageInfo))) + .collect(Collectors.toList())); + default: + throw new IllegalArgumentException("unhandled dataModel here"); } } @@ -306,70 +316,70 @@ public List> combinePageInfos(List joinableGroup return combinePageInfosCommon(this.dataModel, joinableGroup); } - private NamedRange getNamedRangeOrThrow(CitationGroup cg) { - NamedRange namedRange = this.cgidToNamedRange.get(cg.cgid); + private NamedRange getNamedRangeOrThrow(CitationGroup group) { + NamedRange namedRange = this.cgidToNamedRange.get(group.groupId); if (namedRange == null) { throw new IllegalStateException("getNamedRange: could not lookup namedRange"); } return namedRange; } - public void removeCitationGroup(CitationGroup cg, XTextDocument doc) + public void removeCitationGroup(CitationGroup group, XTextDocument doc) throws WrappedTargetException, NoDocumentException, NotRemoveableException { - NamedRange namedRange = getNamedRangeOrThrow(cg); - String refMarkName = namedRange.nrGetRangeName(); - namedRange.nrRemoveFromDocument(doc); + NamedRange namedRange = getNamedRangeOrThrow(group); + String refMarkName = namedRange.getRangeName(); + namedRange.removeFromDocument(doc); UnoUserDefinedProperty.removeIfExists(doc, refMarkName); - this.cgidToNamedRange.remove(cg.cgid); + this.cgidToNamedRange.remove(group.groupId); } /** * @return Optional.empty if the reference mark is missing. */ - public Optional getMarkRange(CitationGroup cg, XTextDocument doc) + public Optional getMarkRange(CitationGroup group, XTextDocument doc) throws NoDocumentException, WrappedTargetException { - NamedRange namedRange = getNamedRangeOrThrow(cg); - return namedRange.nrGetMarkRange(doc); + NamedRange namedRange = getNamedRangeOrThrow(group); + return namedRange.getMarkRange(doc); } /** * Cursor for the reference marks as is: not prepared for filling, but does not need * cleanFillCursorForCitationGroup either. */ - public Optional getRawCursorForCitationGroup(CitationGroup cg, XTextDocument doc) + public Optional getRawCursorForCitationGroup(CitationGroup group, XTextDocument doc) throws NoDocumentException, WrappedTargetException { - NamedRange namedRange = getNamedRangeOrThrow(cg); - return namedRange.nrGetRawCursor(doc); + NamedRange namedRange = getNamedRangeOrThrow(group); + return namedRange.getRawCursor(doc); } /** * Must be followed by call to cleanFillCursorForCitationGroup */ - public XTextCursor getFillCursorForCitationGroup(CitationGroup cg, XTextDocument doc) + public XTextCursor getFillCursorForCitationGroup(CitationGroup group, XTextDocument doc) throws NoDocumentException, WrappedTargetException, CreationException { - NamedRange namedRange = getNamedRangeOrThrow(cg); - return namedRange.nrGetFillCursor(doc); + NamedRange namedRange = getNamedRangeOrThrow(group); + return namedRange.getFillCursor(doc); } /** To be called after getFillCursorForCitationGroup */ - public void cleanFillCursorForCitationGroup(CitationGroup cg, XTextDocument doc) + public void cleanFillCursorForCitationGroup(CitationGroup group, XTextDocument doc) throws NoDocumentException, WrappedTargetException { - NamedRange namedRange = getNamedRangeOrThrow(cg); - namedRange.nrCleanFillCursor(doc); + NamedRange namedRange = getNamedRangeOrThrow(group); + namedRange.cleanFillCursor(doc); } public List getCitationEntries(XTextDocument doc, CitationGroups cgs) @@ -378,29 +388,29 @@ public List getCitationEntries(XTextDocument doc, CitationGroups NoDocumentException { switch (dataModel) { - case JabRef52: - // One context per CitationGroup: Backend52 (DataModel.JabRef52) - // For DataModel.JabRef60 (Backend60) we need one context per Citation - List citations = new ArrayList<>(cgs.numberOfCitationGroups()); - for (CitationGroup cg : cgs.getCitationGroupsUnordered()) { - String name = cg.cgid.citationGroupIdAsString(); - XTextCursor cursor = (this - .getRawCursorForCitationGroup(cg, doc) - .orElseThrow(IllegalStateException::new)); - String context = GetContext.getCursorStringWithContext(cursor, 30, 30, true); - Optional pageInfo = (cg.numberOfCitations() > 0 - ? (getPageInfoFromData(cg) - .map(e -> OOText.toString(e))) - : Optional.empty()); - CitationEntry entry = new CitationEntry(name, context, pageInfo); - citations.add(entry); - } - return citations; - case JabRef60: - // xx - throw new IllegalStateException("getCitationEntries for JabRef60 is not implemented yet"); - default: - throw new IllegalStateException("getCitationEntries: unhandled dataModel "); + case JabRef52: + // One context per CitationGroup: Backend52 (DataModel.JabRef52) + // For DataModel.JabRef60 (Backend60) we need one context per Citation + List citations = new ArrayList<>(cgs.numberOfCitationGroups()); + for (CitationGroup group : cgs.getCitationGroupsUnordered()) { + String name = group.groupId.citationGroupIdAsString(); + XTextCursor cursor = (this + .getRawCursorForCitationGroup(group, doc) + .orElseThrow(IllegalStateException::new)); + String context = GetContext.getCursorStringWithContext(cursor, 30, 30, true); + Optional pageInfo = (group.numberOfCitations() > 0 + ? (getPageInfoFromData(group) + .map(e -> OOText.toString(e))) + : Optional.empty()); + CitationEntry entry = new CitationEntry(name, context, pageInfo); + citations.add(entry); + } + return citations; + case JabRef60: + // xx + throw new IllegalStateException("getCitationEntries for JabRef60 is not implemented yet"); + default: + throw new IllegalStateException("getCitationEntries: unhandled dataModel "); } } @@ -415,21 +425,21 @@ public void applyCitationEntries(XTextDocument doc, List citation WrappedTargetException { switch (dataModel) { - case JabRef52: - for (CitationEntry entry : citationEntries) { - Optional pageInfo = entry.getPageInfo().map(OOText::fromString); - pageInfo = PageInfo.normalizePageInfo(pageInfo); - if (pageInfo.isPresent()) { - String name = entry.getRefMarkName(); - UnoUserDefinedProperty.setStringProperty(doc, name, pageInfo.get().toString()); + case JabRef52: + for (CitationEntry entry : citationEntries) { + Optional pageInfo = entry.getPageInfo().map(OOText::fromString); + pageInfo = PageInfo.normalizePageInfo(pageInfo); + if (pageInfo.isPresent()) { + String name = entry.getRefMarkName(); + UnoUserDefinedProperty.setStringProperty(doc, name, pageInfo.get().toString()); + } } - } - break; - case JabRef60: - // xx - throw new IllegalStateException("applyCitationEntries for JabRef60 is not implemented yet"); - default: - throw new IllegalStateException("applyCitationEntries: unhandled dataModel "); + break; + case JabRef60: + // xx + throw new IllegalStateException("applyCitationEntries for JabRef60 is not implemented yet"); + default: + throw new IllegalStateException("applyCitationEntries: unhandled dataModel "); } } diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java index f6d2b12245e..f567a3e459e 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java @@ -12,7 +12,7 @@ import org.jabref.model.openoffice.style.CitationType; /** - * How and what is encoded in a mark names. + * How and what is encoded in reference mark names under JabRef 5.2. * * - pageInfo does not appear here. It is not encoded in the mark name. */ @@ -51,51 +51,46 @@ public static class ParsedMarkName { * Integer representation was written into the document in JabRef52, keep it for compatibility. */ private static CitationType citationTypeFromInt(int i) { - switch (i) { - case 1: - return CitationType.AUTHORYEAR_PAR; - case 2: - return CitationType.AUTHORYEAR_INTEXT; - case 3: - return CitationType.INVISIBLE_CIT; - default: - throw new IllegalArgumentException("Invalid CitationType code"); - } + return switch (i) { + case 1 -> CitationType.AUTHORYEAR_PAR; + case 2 -> CitationType.AUTHORYEAR_INTEXT; + case 3 -> CitationType.INVISIBLE_CIT; + default -> throw new IllegalArgumentException("Invalid CitationType code"); + }; } private static int citationTypeToInt(CitationType i) { - switch (i) { - case AUTHORYEAR_PAR: - return 1; - case AUTHORYEAR_INTEXT: - return 2; - case INVISIBLE_CIT: - return 3; - default: - throw new IllegalArgumentException("Invalid CitationType"); - } + return switch (i) { + case AUTHORYEAR_PAR -> 1; + case AUTHORYEAR_INTEXT -> 2; + case INVISIBLE_CIT -> 3; + default -> throw new IllegalArgumentException("Invalid CitationType"); + }; } /** - * Produce a reference mark name for JabRef for the given citation key and citationType that + * Produce a reference mark name for JabRef for the given citationType and list citation keys that * does not yet appear among the reference marks of the document. * - * @param bibtexKey The citation key. + * @param usedNames Reference mark names already in use. + * @param citationKeys Identifies the cited sources. * @param citationType Encodes the effect of withText and inParenthesis options. * - * The first occurrence of bibtexKey gets no serial number, the second gets 0, the third 1 ... + * The first occurrence of citationKeys gets no serial number, the second gets 0, the third 1 ... * * Or the first unused in this series, after removals. */ public static String getUniqueMarkName(Set usedNames, - String bibtexKey, + List citationKeys, CitationType citationType) { + String citationKeysPart = String.join(",", citationKeys); + int i = 0; int citTypeCode = citationTypeToInt(citationType); - String name = BIB_CITATION + '_' + citTypeCode + '_' + bibtexKey; + String name = BIB_CITATION + '_' + citTypeCode + '_' + citationKeysPart; while (usedNames.contains(name)) { - name = BIB_CITATION + i + '_' + citTypeCode + '_' + bibtexKey; + name = BIB_CITATION + i + '_' + citTypeCode + '_' + citationKeysPart; i++; } return name; @@ -135,9 +130,8 @@ public static boolean isJabRefReferenceMarkName(String name) { * @param names The list to be filtered. */ public static List filterIsJabRefReferenceMarkName(List names) { - return (names - .stream() - .filter(Codec52::isJabRefReferenceMarkName) - .collect(Collectors.toList())); + return (names.stream() + .filter(Codec52::isJabRefReferenceMarkName) + .collect(Collectors.toList())); } } diff --git a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java index d82ad08378e..93ad6d12908 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java @@ -16,25 +16,25 @@ public class NamedRangeManagerReferenceMark implements NamedRangeManager { @Override - public NamedRange nrmCreate(XTextDocument doc, - String refMarkName, - XTextCursor position, - boolean insertSpaceAfter, - boolean withoutBrackets) + public NamedRange createNamedRange(XTextDocument doc, + String refMarkName, + XTextCursor position, + boolean insertSpaceAfter, + boolean withoutBrackets) throws CreationException { return NamedRangeReferenceMark.create(doc, refMarkName, position, insertSpaceAfter, withoutBrackets); } @Override - public List nrmGetUsedNames(XTextDocument doc) + public List getUsedNames(XTextDocument doc) throws NoDocumentException { return UnoReferenceMark.getListOfNames(doc); } @Override - public Optional nrmGetFromDocument(XTextDocument doc, String refMarkName) + public Optional getNamedRangeFromDocument(XTextDocument doc, String refMarkName) throws NoDocumentException, WrappedTargetException { 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 a11e29aecd1..cfabb1e2de0 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java @@ -141,43 +141,42 @@ static Optional getFromDocument(XTextDocument doc, Stri .map(e -> new NamedRangeReferenceMark(refMarkName))); } - /* + /** * Remove it from the document. * * See: removeCitationGroups */ @Override - public void nrRemoveFromDocument(XTextDocument doc) + public void removeFromDocument(XTextDocument doc) throws WrappedTargetException, NoDocumentException { - UnoReferenceMark.removeIfExists(doc, this.nrGetRangeName()); + UnoReferenceMark.removeIfExists(doc, this.getRangeName()); } @Override - public String nrGetRangeName() { + public String getRangeName() { return id; } - /* - * ranges controlled by citation groups should not overlap with each other. + /** * * @return Optional.empty if the reference mark is missing. * * See: UnoReferenceMark.getAnchor */ @Override - public Optional nrGetMarkRange(XTextDocument doc) + public Optional getMarkRange(XTextDocument doc) throws NoDocumentException, WrappedTargetException { - String name = this.nrGetRangeName(); + String name = this.getRangeName(); return UnoReferenceMark.getAnchor(doc, name); } /** * Cursor for the reference marks as is, not prepared for filling, but does not need - * nrCleanFillCursor either. + * cleanFillCursor either. * * @return Optional.empty() if reference mark is missing from the document, * otherwise an XTextCursor for getMarkRange @@ -185,22 +184,22 @@ public Optional nrGetMarkRange(XTextDocument doc) * See: getRawCursorForCitationGroup */ @Override - public Optional nrGetRawCursor(XTextDocument doc) + public Optional getRawCursor(XTextDocument doc) throws NoDocumentException, WrappedTargetException { - String name = this.nrGetRangeName(); + String name = this.getRangeName(); Optional markAsTextContent = UnoReferenceMark.getAsTextContent(doc, name); if (markAsTextContent.isEmpty()) { - LOGGER.warn("nrGetRawCursor: markAsTextContent({}).isEmpty()", name); + LOGGER.warn("getRawCursor: markAsTextContent({}).isEmpty()", name); } Optional full = UnoCursor.getTextCursorOfTextContentAnchor(markAsTextContent.get()); if (full.isEmpty()) { - LOGGER.warn("nrGetRawCursor: full.isEmpty()"); + LOGGER.warn("getRawCursor: full.isEmpty()"); return Optional.empty(); } return full; @@ -210,13 +209,13 @@ public Optional nrGetRawCursor(XTextDocument doc) * See: getFillCursorForCitationGroup */ @Override - public XTextCursor nrGetFillCursor(XTextDocument doc) + public XTextCursor getFillCursor(XTextDocument doc) throws NoDocumentException, WrappedTargetException, CreationException { - String name = this.nrGetRangeName(); + String name = this.getRangeName(); final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; @@ -228,31 +227,31 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) Optional markAsTextContent = UnoReferenceMark.getAsTextContent(doc, name); if (markAsTextContent.isEmpty()) { - String msg = String.format("nrGetFillCursor: markAsTextContent(%s).isEmpty (attempt %d)", name, i); + String msg = String.format("getFillCursor: markAsTextContent(%s).isEmpty (attempt %d)", name, i); throw new IllegalStateException(msg); } full = UnoCursor.getTextCursorOfTextContentAnchor(markAsTextContent.get()).orElse(null); if (full == null) { - String msg = String.format("nrGetFillCursor: full == null (attempt %d)", i); + String msg = String.format("getFillCursor: full == null (attempt %d)", i); throw new IllegalStateException(msg); } fullText = full.getString(); - LOGGER.debug("nrGetFillCursor: fulltext = '{}'", fullText); + LOGGER.debug("getFillCursor: fulltext = '{}'", fullText); if (fullText.length() >= 2) { - LOGGER.debug("nrGetFillCursor: (attempt: {}) fulltext.length() >= 2, break loop%n", i); + LOGGER.debug("getFillCursor: (attempt: {}) fulltext.length() >= 2, break loop%n", i); break; } else { // (fullText.length() < 2) if (i == 2) { - String msg = String.format("nrGetFillCursor: (fullText.length() < 2) (attempt %d)", i); + String msg = String.format("getFillCursor: (fullText.length() < 2) (attempt %d)", i); throw new IllegalStateException(msg); } // too short, recreate - LOGGER.warn("nrGetFillCursor: too short, recreate"); + LOGGER.warn("getFillCursor: too short, recreate"); full.setString(""); UnoReferenceMark.removeIfExists(doc, name); @@ -264,27 +263,27 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) } if (full == null) { - throw new IllegalStateException("nrGetFillCursorFor: full == null (after loop)"); + throw new IllegalStateException("getFillCursorFor: full == null (after loop)"); } if (fullText == null) { - throw new IllegalStateException("nrGetFillCursor: fullText == null (after loop)"); + throw new IllegalStateException("getFillCursor: fullText == null (after loop)"); } fullText = full.getString(); if (fullText.length() < 2) { - throw new IllegalStateException("nrGetFillCursor: fullText.length() < 2 (after loop)'%n"); + throw new IllegalStateException("getFillCursor: fullText.length() < 2 (after loop)'%n"); } XTextCursor beta = full.getText().createTextCursorByRange(full); beta.collapseToStart(); beta.goRight((short) 1, false); beta.goRight((short) (fullText.length() - 2), true); - LOGGER.debug("nrGetFillCursor: beta(1) covers '{}'", beta.getString()); + LOGGER.debug("getFillCursor: beta(1) covers '{}'", beta.getString()); final short rightLength = (short) right.length(); if (fullText.startsWith(left) && fullText.endsWith(right)) { beta.setString(""); } else { - LOGGER.debug("nrGetFillCursor: recreating brackets for '{}'", fullText); + LOGGER.debug("getFillCursor: recreating brackets for '{}'", fullText); // we have at least two characters inside XTextCursor alpha = full.getText().createTextCursorByRange(full); @@ -299,41 +298,41 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) String paddingy = "y"; String paddingz = "z"; beta.setString(paddingx + left + paddingy + right + paddingz); - LOGGER.debug("nrGetFillCursor: beta(2) covers '{}'", beta.getString()); + LOGGER.debug("getFillCursor: beta(2) covers '{}'", beta.getString()); // move beta to before the right bracket beta.collapseToEnd(); beta.goLeft((short) (rightLength + 1), false); // remove middle padding beta.goLeft((short) 1, true); - LOGGER.debug("nrGetFillCursor: beta(3) covers '{}'", beta.getString()); + LOGGER.debug("getFillCursor: beta(3) covers '{}'", beta.getString()); // only drop paddingy later: beta.setString(""); // drop the initial character and paddingx alpha.collapseToStart(); alpha.goRight((short) (1 + 1), true); - LOGGER.debug("nrGetFillCursor: alpha(4) covers '{}'", alpha.getString()); + LOGGER.debug("getFillCursor: alpha(4) covers '{}'", alpha.getString()); alpha.setString(""); // drop the last character and paddingz omega.collapseToEnd(); omega.goLeft((short) (1 + 1), true); - LOGGER.debug("nrGetFillCursor: omega(5) covers '{}'", omega.getString()); + LOGGER.debug("getFillCursor: omega(5) covers '{}'", omega.getString()); omega.setString(""); // drop paddingy now - LOGGER.debug("nrGetFillCursor: beta(6) covers '{}'", beta.getString()); + LOGGER.debug("getFillCursor: beta(6) covers '{}'", beta.getString()); beta.setString(""); // should be OK now. if (debugThisFun) { final short leftLength = (short) left.length(); alpha.goRight(leftLength, true); - LOGGER.debug("nrGetFillCursor: alpha(7) covers '{}', should be '{}'", alpha.getString(), left); + LOGGER.debug("getFillCursor: alpha(7) covers '{}', should be '{}'", alpha.getString(), left); omega.goLeft(rightLength, true); - LOGGER.debug("nrGetFillCursor: omega(8) covers '{}', should be '{}'", omega.getString(), right); + LOGGER.debug("getFillCursor: omega(8) covers '{}', should be '{}'", omega.getString(), right); } } @@ -384,13 +383,13 @@ public static void checkFillCursor(XTextCursor cursor) { * See: cleanFillCursorForCitationGroup */ @Override - public void nrCleanFillCursor(XTextDocument doc) + public void cleanFillCursor(XTextDocument doc) throws NoDocumentException, WrappedTargetException { // alwaysRemoveBrackets : full compatibility with JabRef 5.2: brackets are temporary, only - // exist between nrGetFillCursor and nrCleanFillCursor. + // exist between getFillCursor and cleanFillCursor. final boolean alwaysRemoveBrackets = false; // removeBracketsFromEmpty is intended to force removal if we are working on an "Empty citation" (INVISIBLE_CIT). @@ -401,25 +400,25 @@ public void nrCleanFillCursor(XTextDocument doc) final short leftLength = (short) left.length(); final short rightLength = (short) right.length(); - String name = this.nrGetRangeName(); + String name = this.getRangeName(); - XTextCursor full = this.nrGetRawCursor(doc).orElseThrow(IllegalStateException::new); + XTextCursor full = this.getRawCursor(doc).orElseThrow(IllegalStateException::new); final String fullText = full.getString(); final int fullTextLength = fullText.length(); if (!fullText.startsWith(left)) { - String msg = String.format("nrCleanFillCursor: (%s) does not start with REFERENCE_MARK_LEFT_BRACKET", name); + String msg = String.format("cleanFillCursor: (%s) does not start with REFERENCE_MARK_LEFT_BRACKET", name); throw new IllegalStateException(msg); } if (!fullText.endsWith(right)) { - String msg = String.format("nrCleanFillCursor: (%s) does not end with REFERENCE_MARK_RIGHT_BRACKET", name); + String msg = String.format("cleanFillCursor: (%s) does not end with REFERENCE_MARK_RIGHT_BRACKET", name); throw new IllegalStateException(msg); } final int contentLength = (fullTextLength - (leftLength + rightLength)); if (contentLength < 0) { - String msg = String.format("nrCleanFillCursor: length(%s) < 0", name); + String msg = String.format("cleanFillCursor: length(%s) < 0", name); throw new IllegalStateException(msg); } diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java index 967a8cf084d..58057c382e7 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java @@ -35,19 +35,14 @@ import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; import com.sun.star.text.XTextRange; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class OOFrontend { - private static final Logger LOGGER = LoggerFactory.getLogger(OOFrontend.class); + public final Backend52 backend; public final CitationGroups citationGroups; @@ -86,10 +81,9 @@ public Optional healthReport(XTextDocument doc) NoDocumentException { Map citationGroups = new HashMap<>(); - for (int i = 0; i < citationGroupNames.size(); i++) { - final String name = citationGroupNames.get(i); - CitationGroup cg = backend.readCitationGroupFromDocumentOrThrow(doc, name); - citationGroups.put(cg.cgid, cg); + for (String name : citationGroupNames) { + CitationGroup group = backend.readCitationGroupFromDocumentOrThrow(doc, name); + citationGroups.put(group.groupId, group); } return citationGroups; } @@ -117,11 +111,11 @@ public Optional healthReport(XTextDocument doc) WrappedTargetException { List> sortables = new ArrayList<>(); - for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { + for (CitationGroup group : citationGroups.getCitationGroupsUnordered()) { XTextRange range = (this - .getMarkRange(doc, cg) + .getMarkRange(doc, group) .orElseThrow(IllegalStateException::new)); - sortables.add(new RangeSortEntry<>(range, 0, cg)); + sortables.add(new RangeSortEntry<>(range, 0, group)); } /* @@ -150,9 +144,7 @@ public Optional healthReport(XTextDocument doc) for (List> partition : partitions.getPartitions()) { int indexInPartition = 0; - for (int i = 0; i < partition.size(); i++) { - RangeSortEntry sortable = partition.get(i); - XTextRange aRange = sortable.getRange(); + for (RangeSortEntry sortable : partition) { sortable.setIndexInPosition(indexInPartition++); if (mapFootnotesToFootnoteMarks) { Optional footnoteMarkRange = @@ -183,18 +175,15 @@ private List getVisuallySortedCitationGroups(XTextDocument doc, FunctionalTextViewCursor fcursor) throws WrappedTargetException, - NoDocumentException, - JabRefException { + NoDocumentException { List> sortables = createVisualSortInput(doc, mapFootnotesToFootnoteMarks); List> sorted = RangeSortVisual.visualSort(sortables, doc, fcursor); - List result = (sorted.stream() - .map(RangeSortable::getContent) - .collect(Collectors.toList())); - - return result; + return (sorted.stream() + .map(RangeSortable::getContent) + .collect(Collectors.toList())); } /** @@ -240,7 +229,6 @@ public CitationGroup createCitationGroup(XTextDocument doc, NoDocumentException, WrappedTargetException, NotRemoveableException, - PropertyExistException, PropertyVetoException, IllegalTypeException { @@ -248,44 +236,38 @@ public CitationGroup createCitationGroup(XTextDocument doc, if (pageInfos.size() != citationKeys.size()) { throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); } - CitationGroup cg = backend.createCitationGroup(doc, - citationKeys, - pageInfos, - citationType, - position, - insertSpaceAfter); - - this.citationGroups.afterCreateCitationGroup(cg); - return cg; + CitationGroup group = backend.createCitationGroup(doc, + citationKeys, + pageInfos, + citationType, + position, + insertSpaceAfter); + + this.citationGroups.afterCreateCitationGroup(group); + return group; } /** - * Remove {@code cg} both from the document and notify {@code citationGroups} + * Remove {@code group} both from the document and notify {@code citationGroups} */ - public void removeCitationGroup(CitationGroup cg, XTextDocument doc) + public void removeCitationGroup(CitationGroup group, XTextDocument doc) throws WrappedTargetException, NoDocumentException, - NoSuchElementException, - NotRemoveableException, - PropertyExistException, - IllegalTypeException { + NotRemoveableException { - backend.removeCitationGroup(cg, doc); - this.citationGroups.afterRemoveCitationGroup(cg); + backend.removeCitationGroup(group, doc); + this.citationGroups.afterRemoveCitationGroup(group); } public void removeCitationGroups(List cgs, XTextDocument doc) throws WrappedTargetException, NoDocumentException, - NoSuchElementException, - NotRemoveableException, - PropertyExistException, - IllegalTypeException { + NotRemoveableException { - for (CitationGroup cg : cgs) { - removeCitationGroup(cg, doc); + for (CitationGroup group : cgs) { + removeCitationGroup(group, doc); } } @@ -295,31 +277,30 @@ public void removeCitationGroups(List cgs, XTextDocument doc) * @return Optional.empty() if the reference mark is missing. * */ - public Optional getMarkRange(XTextDocument doc, CitationGroup cg) + public Optional getMarkRange(XTextDocument doc, CitationGroup group) throws NoDocumentException, WrappedTargetException { - return backend.getMarkRange(cg, doc); + return backend.getMarkRange(group, doc); } - public XTextCursor getFillCursorForCitationGroup(XTextDocument doc, CitationGroup cg) + public XTextCursor getFillCursorForCitationGroup(XTextDocument doc, CitationGroup group) throws NoDocumentException, WrappedTargetException, CreationException { - return backend.getFillCursorForCitationGroup(cg, doc); + return backend.getFillCursorForCitationGroup(group, doc); } /** * Remove brackets added by getFillCursorForCitationGroup. */ - public void cleanFillCursorForCitationGroup(XTextDocument doc, CitationGroup cg) + public void cleanFillCursorForCitationGroup(XTextDocument doc, CitationGroup group) throws NoDocumentException, - WrappedTargetException, - CreationException { + WrappedTargetException { - backend.cleanFillCursorForCitationGroup(cg, doc); + backend.cleanFillCursorForCitationGroup(group, doc); } /** @@ -335,11 +316,11 @@ public List> citationRanges(XTextDocument List> result = new ArrayList<>(citationGroups.numberOfCitationGroups()); - for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { - XTextRange range = this.getMarkRange(doc, cg).orElseThrow(IllegalStateException::new); - String description = cg.cgid.citationGroupIdAsString(); + for (CitationGroup group : citationGroups.getCitationGroupsUnordered()) { + XTextRange range = this.getMarkRange(doc, group).orElseThrow(IllegalStateException::new); + String description = group.groupId.citationGroupIdAsString(); result.add(new RangeForOverlapCheck<>(range, - cg.cgid, + group.groupId, RangeForOverlapCheck.REFERENCE_MARK_KIND, description)); } @@ -364,10 +345,7 @@ public List> bibliographyRanges(XTextDocum return result; } - public List> viewCursorRanges(XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException { + public List> viewCursorRanges(XTextDocument doc) { List> result = new ArrayList<>(); @@ -394,10 +372,7 @@ public List> viewCursorRanges(XTextDocumen * ranges. */ public List> - footnoteMarkRanges(XTextDocument doc, List> citationRanges) - throws - NoDocumentException, - WrappedTargetException { + footnoteMarkRanges(XTextDocument doc, List> citationRanges) { // We partition by XText and use a single range from // each partition to get at the corresponding footnotemark range. @@ -432,7 +407,7 @@ public List> viewCursorRanges(XTextDocumen static String rangeOverlapsToMessage(List>> overlaps) { - if (overlaps.size() == 0) { + if (overlaps.isEmpty()) { return "(*no overlaps*)"; } @@ -443,9 +418,9 @@ static String rangeOverlapsToMessage(List Localization.lang("Found identical ranges"); - case OVERLAP -> Localization.lang("Found overlapping ranges"); - case TOUCH -> Localization.lang("Found touching ranges"); + case EQUAL_RANGE -> Localization.lang("Found identical ranges"); + case OVERLAP -> Localization.lang("Found overlapping ranges"); + case TOUCH -> Localization.lang("Found touching ranges"); }); msg.append(": "); msg.append(listOfRanges); @@ -483,7 +458,7 @@ static String rangeOverlapsToMessage(List checkRangeOverlaps(XTextDocument doc, List>> overlaps = RangeOverlapWithin.findOverlappingRanges(doc, ranges, requireSeparation, reportAtMost); - if (overlaps.size() == 0) { + if (overlaps.isEmpty()) { return OOVoidResult.ok(); } return OOVoidResult.error(new JabRefException("Found overlapping or touching ranges", @@ -552,7 +527,6 @@ public OOVoidResult checkRangeOverlaps(XTextDocument doc, */ public List getCitationEntries(XTextDocument doc) throws - UnknownPropertyException, WrappedTargetException, NoDocumentException { return this.backend.getCitationEntries(doc, citationGroups); @@ -560,13 +534,9 @@ public List getCitationEntries(XTextDocument doc) public void applyCitationEntries(XTextDocument doc, List citationEntries) throws - UnknownPropertyException, - NotRemoveableException, - PropertyExistException, PropertyVetoException, IllegalTypeException, IllegalArgumentException, - NoDocumentException, WrappedTargetException { this.backend.applyCitationEntries(doc, citationEntries); } @@ -574,13 +544,12 @@ public void applyCitationEntries(XTextDocument doc, List citation public void imposeGlobalOrder(XTextDocument doc, FunctionalTextViewCursor fcursor) throws WrappedTargetException, - NoDocumentException, - JabRefException { + NoDocumentException { boolean mapFootnotesToFootnoteMarks = true; List sortedCitationGroups = getVisuallySortedCitationGroups(doc, mapFootnotesToFootnoteMarks, fcursor); - List sortedCitationGroupIds = OOListUtil.map(sortedCitationGroups, cg -> cg.cgid); + List sortedCitationGroupIds = OOListUtil.map(sortedCitationGroups, group -> group.groupId); citationGroups.setGlobalOrder(sortedCitationGroupIds); } } 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 2d0de320ca6..f7b3d14def6 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java @@ -12,9 +12,6 @@ import org.jabref.model.openoffice.uno.UnoBookmark; import org.jabref.model.openoffice.uno.UnoTextSection; -import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; @@ -28,12 +25,15 @@ public class UpdateBibliography { private static final String BIB_SECTION_NAME = "JR_bib"; private static final String BIB_SECTION_END_NAME = "JR_bib_end"; + private UpdateBibliography() { + /**/ + } + public static Optional getBibliographyRange(XTextDocument doc) throws NoDocumentException, WrappedTargetException { - Optional sectionRange = UnoTextSection.getAnchor(doc, BIB_SECTION_NAME); - return sectionRange; + return UnoTextSection.getAnchor(doc, BIB_SECTION_NAME); } /** @@ -45,11 +45,8 @@ public static void rebuildBibTextSection(XTextDocument doc, OOBibStyle style, boolean alwaysAddCitedOnPages) throws - NoSuchElementException, WrappedTargetException, CreationException, - PropertyVetoException, - UnknownPropertyException, NoDocumentException { clearBibTextSectionContent2(doc); @@ -116,9 +113,6 @@ private static void populateBibTextSection(XTextDocument doc, CreationException, IllegalArgumentException, NoDocumentException, - NoSuchElementException, - PropertyVetoException, - UnknownPropertyException, WrappedTargetException { XTextRange sectionRange = getBibliographyRange(doc).orElseThrow(IllegalStateException::new); @@ -134,7 +128,7 @@ private static void populateBibTextSection(XTextDocument doc, OOTextIntoOO.write(doc, cursor, bibliographyText); cursor.collapseToEnd(); - // remove the inital empty paragraph from the section. + // remove the initial empty paragraph from the section. sectionRange = getBibliographyRange(doc).orElseThrow(IllegalStateException::new); XTextCursor initialParagraph = doc.getText().createTextCursorByRange(sectionRange); initialParagraph.collapseToStart(); diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java index a3363938797..55f04775094 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java @@ -4,7 +4,6 @@ import java.util.Objects; import java.util.Optional; -import org.jabref.logic.JabRefException; import org.jabref.logic.openoffice.style.OOBibStyle; import org.jabref.model.openoffice.ootext.OOText; import org.jabref.model.openoffice.ootext.OOTextIntoOO; @@ -16,10 +15,7 @@ import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; @@ -33,6 +29,10 @@ public class UpdateCitationMarkers { private static final Logger LOGGER = LoggerFactory.getLogger(UpdateCitationMarkers.class); + private UpdateCitationMarkers() { + /**/ + } + /** * Visit each reference mark in referenceMarkNames, overwrite its * text content. @@ -48,33 +48,29 @@ public class UpdateCitationMarkers { public static void applyNewCitationMarkers(XTextDocument doc, OOFrontend fr, OOBibStyle style) throws NoDocumentException, - UnknownPropertyException, CreationException, - WrappedTargetException, - PropertyVetoException, - NoSuchElementException, - JabRefException { + WrappedTargetException { CitationGroups citationGroups = fr.citationGroups; - for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { + for (CitationGroup group : citationGroups.getCitationGroupsUnordered()) { - boolean withText = (cg.citationType != CitationType.INVISIBLE_CIT); - Optional marker = cg.getCitationMarker(); + boolean withText = (group.citationType != CitationType.INVISIBLE_CIT); + Optional marker = group.getCitationMarker(); if (!marker.isPresent()) { LOGGER.warn("applyNewCitationMarkers: no marker for {}", - cg.cgid.citationGroupIdAsString()); + group.groupId.citationGroupIdAsString()); continue; } if (withText && marker.isPresent()) { - XTextCursor cursor = fr.getFillCursorForCitationGroup(doc, cg); + XTextCursor cursor = fr.getFillCursorForCitationGroup(doc, group); fillCitationMarkInCursor(doc, cursor, marker.get(), withText, style); - fr.cleanFillCursorForCitationGroup(doc, cg); + fr.cleanFillCursorForCitationGroup(doc, group); } } @@ -85,11 +81,8 @@ public static void fillCitationMarkInCursor(XTextDocument doc, OOText citationText, boolean withText, OOBibStyle style) - throws - UnknownPropertyException, - PropertyVetoException, + throws WrappedTargetException, - NoSuchElementException, CreationException, IllegalArgumentException { @@ -135,37 +128,33 @@ public static void createAndFillCitationGroup(OOFrontend fr, OOBibStyle style, boolean insertSpaceAfter) throws - UnknownPropertyException, NotRemoveableException, - PropertyExistException, - PropertyVetoException, WrappedTargetException, PropertyVetoException, IllegalArgumentException, CreationException, NoDocumentException, - IllegalTypeException, - NoSuchElementException { + IllegalTypeException { Objects.requireNonNull(pageInfos); if (pageInfos.size() != citationKeys.size()) { throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); } - CitationGroup cg = fr.createCitationGroup(doc, - citationKeys, - pageInfos, - citationType, - position, - insertSpaceAfter); + CitationGroup group = fr.createCitationGroup(doc, + citationKeys, + pageInfos, + citationType, + position, + insertSpaceAfter); final boolean withText = citationType.withText(); if (withText) { - XTextCursor c2 = fr.getFillCursorForCitationGroup(doc, cg); + XTextCursor fillCursor = fr.getFillCursorForCitationGroup(doc, group); - UpdateCitationMarkers.fillCitationMarkInCursor(doc, c2, citationText, withText, style); + UpdateCitationMarkers.fillCitationMarkInCursor(doc, fillCursor, citationText, withText, style); - fr.cleanFillCursorForCitationGroup(doc, cg); + fr.cleanFillCursorForCitationGroup(doc, group); } position.collapseToEnd(); } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java b/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java index 6c22c8abb09..4bc3fac6191 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java @@ -168,12 +168,12 @@ private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey ck) { List citationGroups = new ArrayList<>(); for (CitationPath p : ck.getCitationPaths()) { - CitationGroupId cgid = p.group; - Optional cg = cgs.getCitationGroup(cgid); - if (cg.isEmpty()) { + CitationGroupId groupId = p.group; + Optional group = cgs.getCitationGroup(groupId); + if (group.isEmpty()) { throw new IllegalStateException(); } - citationGroups.add(cg.get()); + citationGroups.add(group.get()); } // sort the citationGroups according to their indexInGlobalOrder @@ -184,11 +184,11 @@ private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey ck) { }); int i = 0; - for (CitationGroup cg : citationGroups) { + for (CitationGroup group : citationGroups) { if (i > 0) { sb.append(", "); } - String markName = cg.getReferenceMarkNameForLinking().orElseThrow(IllegalStateException::new); + String markName = group.getReferenceMarkNameForLinking().orElseThrow(IllegalStateException::new); OOText xref = OOFormat.formatReferenceToPageNumberOfReferenceMark(markName); sb.append(xref.toString()); i++; diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java index 896e747913f..1aaeb538930 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java @@ -64,6 +64,9 @@ private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroup String citationKey = citedKey.citationKey; List clashingKeys = normCitMarkerToClachingKeys.putIfAbsent(normCitMarker, new ArrayList<>(1)); + if (clashingKeys == null) { + clashingKeys = normCitMarkerToClachingKeys.get(normCitMarker); + } if (!clashingKeys.contains(citationKey)) { // First appearance of citationKey, add to list. clashingKeys.add(citationKey); @@ -107,8 +110,8 @@ private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroup */ private static void setIsFirstAppearanceOfSourceInCitations(CitationGroups cgs) { Set seenBefore = new HashSet<>(); - for (CitationGroup cg : cgs.getCitationGroupsInGlobalOrder()) { - for (Citation cit : cg.getCitationsInLocalOrder()) { + for (CitationGroup group : cgs.getCitationGroupsInGlobalOrder()) { + for (Citation cit : group.getCitationsInLocalOrder()) { String currentKey = cit.citationKey; if (!seenBefore.contains(currentKey)) { cit.setIsFirstAppearanceOfSource(true); @@ -142,17 +145,17 @@ static void produceCitationMarkers(CitationGroups cgs, OOBibStyle style) { // Mark first appearance of each citationKey setIsFirstAppearanceOfSourceInCitations(cgs); - for (CitationGroup cg : cgs.getCitationGroupsInGlobalOrder()) { + for (CitationGroup group : cgs.getCitationGroupsInGlobalOrder()) { - final boolean inParenthesis = (cg.citationType == CitationType.AUTHORYEAR_PAR); + final boolean inParenthesis = (group.citationType == CitationType.AUTHORYEAR_PAR); final NonUniqueCitationMarker strictlyUnique = NonUniqueCitationMarker.THROWS; - List cits = cg.getCitationsInLocalOrder(); + List cits = group.getCitationsInLocalOrder(); List citationMarkerEntries = OOListUtil.map(cits, e -> e); OOText citMarker = style.createCitationMarker(citationMarkerEntries, inParenthesis, strictlyUnique); - cg.setCitationMarker(Optional.of(citMarker)); + group.setCitationMarker(Optional.of(citMarker)); } } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java index 9789d6c6caa..5329d9ca021 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java @@ -24,12 +24,12 @@ static void produceCitationMarkers(CitationGroups cgs, OOBibStyle style) { cgs.createPlainBibliographySortedByComparator(OOProcess.AUTHOR_YEAR_TITLE_COMPARATOR); - for (CitationGroup cg : cgs.getCitationGroupsInGlobalOrder()) { + for (CitationGroup group : cgs.getCitationGroupsInGlobalOrder()) { String citMarker = style.getCitationGroupMarkupBefore() - + String.join(",", OOListUtil.map(cg.getCitationsInLocalOrder(), Citation::getCitationKey)) + + String.join(",", OOListUtil.map(group.getCitationsInLocalOrder(), Citation::getCitationKey)) + style.getCitationGroupMarkupAfter(); - cg.setCitationMarker(Optional.of(OOText.fromString(citMarker))); + group.setCitationMarker(Optional.of(OOText.fromString(citMarker))); } } } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java index 589ebfb7a48..deddab66cca 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java @@ -37,10 +37,10 @@ static void produceCitationMarkers(CitationGroups cgs, OOBibStyle style) { cgs.createNumberedBibliographySortedByComparator(OOProcess.AUTHOR_YEAR_TITLE_COMPARATOR); } - for (CitationGroup cg : cgs.getCitationGroupsInGlobalOrder()) { - List cits = OOListUtil.map(cg.getCitationsInLocalOrder(), e -> e); + for (CitationGroup group : cgs.getCitationGroupsInGlobalOrder()) { + List cits = OOListUtil.map(group.getCitationsInLocalOrder(), e -> e); OOText citMarker = style.getNumCitationMarker2(cits); - cg.setCitationMarker(Optional.of(citMarker)); + group.setCitationMarker(Optional.of(citMarker)); } } diff --git a/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java index aa09f36edef..63981ceba70 100644 --- a/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java +++ b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java @@ -10,23 +10,32 @@ import com.sun.star.text.XTextDocument; import com.sun.star.text.XTextRange; +/** + * NamedRange (with NamedRangeManager) attempts to provide a common interface for working with + * reference mark based and bookmark based text ranges to be used as locations to fill with citation + * markers. LibreOffice supports name-based lookup and listing names for both (hence the name). + * + * Note: currently only implemented for refence marks (in NamedRangeReferenceMark and + * NamedRangeManagerReferenceMark). + * + */ public interface NamedRange { - String nrGetRangeName(); + String getRangeName(); /** * @return Optional.empty if the mark is missing from the document. */ - Optional nrGetMarkRange(XTextDocument doc) + Optional getMarkRange(XTextDocument doc) throws NoDocumentException, WrappedTargetException; /** * Cursor for the reference marks as is, not prepared for filling, but does not need - * nrCleanFillCursor either. + * cleanFillCursor either. */ - Optional nrGetRawCursor(XTextDocument doc) + Optional getRawCursor(XTextDocument doc) throws NoDocumentException, WrappedTargetException; @@ -34,9 +43,9 @@ Optional nrGetRawCursor(XTextDocument doc) /** * Get a cursor for filling in text. * - * Must be followed by nrCleanFillCursor() + * Must be followed by cleanFillCursor() */ - XTextCursor nrGetFillCursor(XTextDocument doc) + XTextCursor getFillCursor(XTextDocument doc) throws NoDocumentException, WrappedTargetException, @@ -47,7 +56,7 @@ XTextCursor nrGetFillCursor(XTextDocument doc) * single character, leave the left bracket. * */ - void nrCleanFillCursor(XTextDocument doc) + void cleanFillCursor(XTextDocument doc) throws NoDocumentException, WrappedTargetException; @@ -55,7 +64,7 @@ void nrCleanFillCursor(XTextDocument doc) /** * Note: create is in NamedRangeManager */ - void nrRemoveFromDocument(XTextDocument doc) + void removeFromDocument(XTextDocument doc) throws WrappedTargetException, NoDocumentException; diff --git a/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java b/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java index 536871b5c34..9bbcc752350 100644 --- a/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java +++ b/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java @@ -12,19 +12,19 @@ public interface NamedRangeManager { - NamedRange nrmCreate(XTextDocument doc, - String markName, - XTextCursor position, - boolean insertSpaceAfter, - boolean withoutBrackets) + NamedRange createNamedRange(XTextDocument doc, + String markName, + XTextCursor position, + boolean insertSpaceAfter, + boolean withoutBrackets) throws CreationException; - List nrmGetUsedNames(XTextDocument doc) + List getUsedNames(XTextDocument doc) throws NoDocumentException; - Optional nrmGetFromDocument(XTextDocument doc, String markName) + Optional getNamedRangeFromDocument(XTextDocument doc, String markName) throws NoDocumentException, WrappedTargetException; diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java index 6e61faed147..909b088b5b3 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java @@ -189,135 +189,135 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) // Handle tags: switch (tagName) { - case "b": - formatStack.pushLayer(setCharWeight(FontWeight.BOLD)); - expectEnd.push("/" + tagName); - break; - case "i": - case "em": - formatStack.pushLayer(setCharPosture(FontSlant.ITALIC)); - expectEnd.push("/" + tagName); - break; - case "smallcaps": - formatStack.pushLayer(setCharCaseMap(CaseMap.SMALLCAPS)); - expectEnd.push("/" + tagName); - break; - case "sup": - formatStack.pushLayer(setSuperScript(formatStack)); - expectEnd.push("/" + tagName); - break; - case "sub": - formatStack.pushLayer(setSubScript(formatStack)); - expectEnd.push("/" + tagName); - break; - case "u": - formatStack.pushLayer(setCharUnderline(FontUnderline.SINGLE)); - expectEnd.push("/" + tagName); - break; - case "s": - formatStack.pushLayer(setCharStrikeout(FontStrikeout.SINGLE)); - expectEnd.push("/" + tagName); - break; - case "/p": - // nop - break; - case "p": - insertParagraphBreak(text, cursor); - cursor.collapseToEnd(); - for (OOPair pair : attributes) { - String key = pair.a; - String value = pair.b; - switch (key) { - case "oo:ParaStyleName": - //

- if (StringUtil.isNullOrEmpty(value)) { - LOGGER.debug(String.format("oo:ParaStyleName inherited")); - } else { - if (setParagraphStyle(cursor, value)) { - // Presumably tested already: - LOGGER.debug(String.format("oo:ParaStyleName=\"%s\" failed", value)); - } + case "b": + formatStack.pushLayer(setCharWeight(FontWeight.BOLD)); + expectEnd.push("/" + tagName); + break; + case "i": + case "em": + formatStack.pushLayer(setCharPosture(FontSlant.ITALIC)); + expectEnd.push("/" + tagName); + break; + case "smallcaps": + formatStack.pushLayer(setCharCaseMap(CaseMap.SMALLCAPS)); + expectEnd.push("/" + tagName); + break; + case "sup": + formatStack.pushLayer(setSuperScript(formatStack)); + expectEnd.push("/" + tagName); + break; + case "sub": + formatStack.pushLayer(setSubScript(formatStack)); + expectEnd.push("/" + tagName); + break; + case "u": + formatStack.pushLayer(setCharUnderline(FontUnderline.SINGLE)); + expectEnd.push("/" + tagName); + break; + case "s": + formatStack.pushLayer(setCharStrikeout(FontStrikeout.SINGLE)); + expectEnd.push("/" + tagName); + break; + case "/p": + // nop + break; + case "p": + insertParagraphBreak(text, cursor); + cursor.collapseToEnd(); + for (OOPair pair : attributes) { + String key = pair.a; + String value = pair.b; + switch (key) { + case "oo:ParaStyleName": + //

+ if (StringUtil.isNullOrEmpty(value)) { + LOGGER.debug(String.format("oo:ParaStyleName inherited")); + } else { + if (setParagraphStyle(cursor, value)) { + // Presumably tested already: + LOGGER.debug(String.format("oo:ParaStyleName=\"%s\" failed", value)); + } + } + break; + default: + LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); + break; } - break; - default: - LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); - break; } - } - break; - case "oo:referenceToPageNumberOfReferenceMark": - for (OOPair pair : attributes) { - String key = pair.a; - String value = pair.b; - switch (key) { - case "target": - UnoCrossRef.insertReferenceToPageNumberOfReferenceMark(doc, value, cursor); - break; - default: - LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); - break; + break; + case "oo:referenceToPageNumberOfReferenceMark": + for (OOPair pair : attributes) { + String key = pair.a; + String value = pair.b; + switch (key) { + case "target": + UnoCrossRef.insertReferenceToPageNumberOfReferenceMark(doc, value, cursor); + break; + default: + LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); + break; + } } - } - break; - case "tt": - // Note: "Example" names a character style in LibreOffice. - formatStack.pushLayer(setCharStyleName("Example")); - expectEnd.push("/" + tagName); - break; - case "span": - List> settings = new ArrayList<>(); - for (OOPair pair : attributes) { - String key = pair.a; - String value = pair.b; - switch (key) { - case "oo:CharStyleName": - // - settings.addAll(setCharStyleName(value)); - break; - case "lang": - // - // - settings.addAll(setCharLocale(value)); - break; - case "style": - // HTML-style small-caps - if ("font-variant: small-caps".equals(value)) { - settings.addAll(setCharCaseMap(CaseMap.SMALLCAPS)); - break; + break; + case "tt": + // Note: "Example" names a character style in LibreOffice. + formatStack.pushLayer(setCharStyleName("Example")); + expectEnd.push("/" + tagName); + break; + case "span": + List> settings = new ArrayList<>(); + for (OOPair pair : attributes) { + String key = pair.a; + String value = pair.b; + switch (key) { + case "oo:CharStyleName": + // + settings.addAll(setCharStyleName(value)); + break; + case "lang": + // + // + settings.addAll(setCharLocale(value)); + break; + case "style": + // HTML-style small-caps + if ("font-variant: small-caps".equals(value)) { + settings.addAll(setCharCaseMap(CaseMap.SMALLCAPS)); + break; + } + LOGGER.warn(String.format("Unexpected value %s for attribute '%s' for <%s>", + value, key, tagName)); + break; + default: + LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); + break; } - LOGGER.warn(String.format("Unexpected value %s for attribute '%s' for <%s>", - value, key, tagName)); - break; - default: - LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); - break; } - } - formatStack.pushLayer(settings); - expectEnd.push("/" + tagName); - break; - case "/b": - case "/i": - case "/em": - case "/tt": - case "/smallcaps": - case "/sup": - case "/sub": - case "/u": - case "/s": - case "/span": - formatStack.popLayer(); - String expected = expectEnd.pop(); - if (!tagName.equals(expected)) { - LOGGER.warn(String.format("expected '<%s>', found '<%s>' after '%s'", - expected, - tagName, - currentSubstring)); - } - break; - default: - LOGGER.warn(String.format("ignoring unknown tag '<%s>'", tagName)); - break; + formatStack.pushLayer(settings); + expectEnd.push("/" + tagName); + break; + case "/b": + case "/i": + case "/em": + case "/tt": + case "/smallcaps": + case "/sup": + case "/sub": + case "/u": + case "/s": + case "/span": + formatStack.popLayer(); + String expected = expectEnd.pop(); + if (!tagName.equals(expected)) { + LOGGER.warn(String.format("expected '<%s>', found '<%s>' after '%s'", + expected, + tagName, + currentSubstring)); + } + break; + default: + LOGGER.warn(String.format("ignoring unknown tag '<%s>'", tagName)); + break; } piv = tagMatcher.end(); diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java index 3b9021eb73f..90afb872d4f 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java @@ -19,7 +19,7 @@ public class CitationGroup { /* * Identifies this citation group. */ - public final CitationGroupId cgid; + public final CitationGroupId groupId; /* * The core data, stored in the document: @@ -60,12 +60,12 @@ public class CitationGroup { private Optional citationMarker; public CitationGroup(OODataModel dataModel, - CitationGroupId cgid, + CitationGroupId groupId, CitationType citationType, List citationsInStorageOrder, Optional referenceMarkNameForLinking) { this.dataModel = dataModel; - this.cgid = cgid; + this.groupId = groupId; this.citationType = citationType; this.citationsInStorageOrder = Collections.unmodifiableList(citationsInStorageOrder); this.localOrder = OOListUtil.makeIndices(citationsInStorageOrder.size()); diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java index 0bfe4a832d0..b03028b76ef 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java @@ -62,12 +62,12 @@ public void distributeToCitations(List where, T value) { for (CitationPath p : where) { - CitationGroup cg = citationGroupsUnordered.get(p.group); - if (cg == null) { + CitationGroup group = citationGroupsUnordered.get(p.group); + if (group == null) { LOGGER.warn("CitationGroups.distributeToCitations: group missing"); continue; } - Citation cit = cg.citationsInStorageOrder.get(p.storageIndexInGroup); + Citation cit = group.citationsInStorageOrder.get(p.storageIndexInGroup); fun.accept(new OOPair<>(cit, value)); } } @@ -96,8 +96,8 @@ public void lookupCitations(List databases) { // right thing. Seems to work. But what we gained from avoiding collect-and-distribute // may be lost in more complicated consistency checking in addPath. // - /// for (CitationGroup cg : getCitationGroupsUnordered()) { - /// for (Citation cit : cg.citationsInStorageOrder) { + /// for (CitationGroup group : getCitationGroupsUnordered()) { + /// for (Citation cit : group.citationsInStorageOrder) { /// cit.lookupInDatabases(databases); /// } /// } @@ -114,7 +114,7 @@ public List getCitationGroupsInGlobalOrder() { if (globalOrder.isEmpty()) { throw new IllegalStateException("getCitationGroupsInGlobalOrder: not ordered yet"); } - return OOListUtil.map(globalOrder.get(), cgid -> citationGroupsUnordered.get(cgid)); + return OOListUtil.map(globalOrder.get(), groupId -> citationGroupsUnordered.get(groupId)); } /** @@ -132,8 +132,8 @@ public void setGlobalOrder(List globalOrder) { // Propagate to each CitationGroup int i = 0; - for (CitationGroupId cgid : globalOrder) { - citationGroupsUnordered.get(cgid).setIndexInGlobalOrder(Optional.of(i)); + for (CitationGroupId groupId : globalOrder) { + citationGroupsUnordered.get(groupId).setIndexInGlobalOrder(Optional.of(i)); i++; } } @@ -146,8 +146,8 @@ public boolean hasGlobalOrder() { * Impose an order for citations within each group. */ public void imposeLocalOrder(Comparator entryComparator) { - for (CitationGroup cg : citationGroupsUnordered.values()) { - cg.imposeLocalOrder(entryComparator); + for (CitationGroup group : citationGroupsUnordered.values()) { + group.imposeLocalOrder(entryComparator); } } @@ -157,11 +157,11 @@ public void imposeLocalOrder(Comparator entryComparator) { */ public CitedKeys getCitedKeysUnordered() { LinkedHashMap res = new LinkedHashMap<>(); - for (CitationGroup cg : citationGroupsUnordered.values()) { + for (CitationGroup group : citationGroupsUnordered.values()) { int storageIndexInGroup = 0; - for (Citation cit : cg.citationsInStorageOrder) { + for (Citation cit : group.citationsInStorageOrder) { String key = cit.citationKey; - CitationPath path = new CitationPath(cg.cgid, storageIndexInGroup); + CitationPath path = new CitationPath(group.groupId, storageIndexInGroup); if (res.containsKey(key)) { res.get(key).addPath(path, cit); } else { @@ -181,11 +181,11 @@ public CitedKeys getCitedKeysSortedInOrderOfAppearance() { throw new IllegalStateException("getSortedCitedKeys: no globalOrder"); } LinkedHashMap res = new LinkedHashMap<>(); - for (CitationGroup cg : getCitationGroupsInGlobalOrder()) { - for (int i : cg.getLocalOrder()) { - Citation cit = cg.citationsInStorageOrder.get(i); + for (CitationGroup group : getCitationGroupsInGlobalOrder()) { + for (int i : group.getLocalOrder()) { + Citation cit = group.citationsInStorageOrder.get(i); String citationKey = cit.citationKey; - CitationPath path = new CitationPath(cg.cgid, i); + CitationPath path = new CitationPath(group.groupId, i); if (res.containsKey(citationKey)) { res.get(citationKey).addPath(path, cit); } else { @@ -257,17 +257,17 @@ public void createNumberedBibliographySortedByComparator(Comparator en * Query by CitationGroupId */ - public Optional getCitationGroup(CitationGroupId cgid) { - CitationGroup cg = citationGroupsUnordered.get(cgid); - return Optional.ofNullable(cg); + public Optional getCitationGroup(CitationGroupId groupId) { + CitationGroup group = citationGroupsUnordered.get(groupId); + return Optional.ofNullable(group); } /* * @return true if all citation groups have referenceMarkNameForLinking */ public boolean citationGroupsProvideReferenceMarkNameForLinking() { - for (CitationGroup cg : citationGroupsUnordered.values()) { - if (cg.getReferenceMarkNameForLinking().isEmpty()) { + for (CitationGroup group : citationGroupsUnordered.values()) { + if (group.getReferenceMarkNameForLinking().isEmpty()) { return false; } } @@ -278,16 +278,16 @@ public boolean citationGroupsProvideReferenceMarkNameForLinking() { * Callbacks. */ - public void afterCreateCitationGroup(CitationGroup cg) { - citationGroupsUnordered.put(cg.cgid, cg); + public void afterCreateCitationGroup(CitationGroup group) { + citationGroupsUnordered.put(group.groupId, group); globalOrder = Optional.empty(); bibliography = Optional.empty(); } - public void afterRemoveCitationGroup(CitationGroup cg) { - citationGroupsUnordered.remove(cg.cgid); - globalOrder.map(l -> l.remove(cg.cgid)); + public void afterRemoveCitationGroup(CitationGroup group) { + citationGroupsUnordered.remove(group.groupId); + globalOrder.map(l -> l.remove(group.groupId)); bibliography = Optional.empty(); } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationType.java b/src/main/java/org/jabref/model/openoffice/style/CitationType.java index 14189e903e3..567996ec56e 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationType.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationType.java @@ -11,8 +11,8 @@ public enum CitationType { public boolean inParenthesis() { return switch (this) { - case AUTHORYEAR_PAR, INVISIBLE_CIT -> true; - case AUTHORYEAR_INTEXT -> false; + case AUTHORYEAR_PAR, INVISIBLE_CIT -> true; + case AUTHORYEAR_INTEXT -> false; }; } From 0cea6aef134063c9b127ac60ed983426d2dabf74 Mon Sep 17 00:00:00 2001 From: Antal K Date: Fri, 20 Aug 2021 15:11:21 +0200 Subject: [PATCH 093/103] sync to improve-reversibility-rebased-03 cb132566f32cba17af24b41d037446a96a90dc16 commit cb132566f32cba17af24b41d037446a96a90dc16 (HEAD -> improve-reversibility-rebased-03, origin/improve-reversibility-rebased-03) Author: Antal K Date: Fri Aug 20 11:39:39 2021 +0200 align dots --- .../org/jabref/gui/openoffice/OOBibBase2.java | 102 ++---- .../gui/openoffice/OOBibBaseConnect.java | 4 - .../logic/openoffice/action/EditInsert.java | 16 +- .../logic/openoffice/action/EditMerge.java | 52 +-- .../logic/openoffice/action/EditSeparate.java | 24 +- .../logic/openoffice/action/ExportCited.java | 8 +- .../openoffice/action/ManageCitations.java | 11 +- .../logic/openoffice/action/Update.java | 24 +- .../logic/openoffice/backend/Backend52.java | 340 +++++++++--------- .../logic/openoffice/backend/Codec52.java | 56 ++- .../NamedRangeManagerReferenceMark.java | 14 +- .../backend/NamedRangeReferenceMark.java | 79 ++-- .../logic/openoffice/frontend/OOFrontend.java | 131 +++---- .../frontend/UpdateBibliography.java | 18 +- .../frontend/UpdateCitationMarkers.java | 55 ++- .../style/OOFormatBibliography.java | 12 +- .../style/OOProcessAuthorYearMarkers.java | 15 +- .../style/OOProcessCitationKeyMarkers.java | 6 +- .../style/OOProcessNumericMarkers.java | 6 +- .../model/openoffice/backend/NamedRange.java | 25 +- .../openoffice/backend/NamedRangeManager.java | 14 +- .../model/openoffice/ootext/OOTextIntoOO.java | 248 ++++++------- .../model/openoffice/style/CitationGroup.java | 6 +- .../openoffice/style/CitationGroups.java | 54 +-- .../model/openoffice/style/CitationType.java | 4 +- 25 files changed, 602 insertions(+), 722 deletions(-) diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java index 29829b9e038..9832adb991d 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java @@ -40,16 +40,13 @@ import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; import com.sun.star.comp.helper.BootstrapException; import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.DisposedException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; -import com.sun.star.util.InvalidStateException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -256,13 +253,7 @@ private static OOVoidResult checkRangeOverlapsWithCursor(XTextDocument final String title = "checkRangeOverlapsWithCursor"; List> userRanges; - try { - userRanges = fr.viewCursorRanges(doc); - } catch (NoDocumentException ex) { - return OOVoidResult.error(OOError.from(ex).setTitle(title)); - } catch (WrappedTargetException ex) { - return OOVoidResult.error(OOError.fromMisc(ex).setTitle(title)); - } + userRanges = fr.viewCursorRanges(doc); boolean requireSeparation = false; OOVoidResult res; @@ -370,7 +361,6 @@ private OOVoidResult checkStyleExistsInTheDocument(String familyName, String labelInJstyleFile, String pathToStyleFile) throws - NoSuchElementException, WrappedTargetException { Optional internalName = UnoStyle.getInternalNameOfStyle(doc, familyName, styleName); @@ -378,18 +368,18 @@ private OOVoidResult checkStyleExistsInTheDocument(String familyName, if (internalName.isEmpty()) { String msg = switch (familyName) { - case UnoStyle.PARAGRAPH_STYLES -> - Localization.lang("The %0 paragraph style '%1' is missing from the document", - labelInJstyleFile, - styleName); - case UnoStyle.CHARACTER_STYLES -> - Localization.lang("The %0 character style '%1' is missing from the document", - labelInJstyleFile, - styleName); - default -> - throw new IllegalArgumentException("Expected " + UnoStyle.CHARACTER_STYLES - + " or " + UnoStyle.PARAGRAPH_STYLES - + " for familyName"); + case UnoStyle.PARAGRAPH_STYLES -> + Localization.lang("The %0 paragraph style '%1' is missing from the document", + labelInJstyleFile, + styleName); + case UnoStyle.CHARACTER_STYLES -> + Localization.lang("The %0 character style '%1' is missing from the document", + labelInJstyleFile, + styleName); + default -> + throw new IllegalArgumentException("Expected " + UnoStyle.CHARACTER_STYLES + + " or " + UnoStyle.PARAGRAPH_STYLES + + " for familyName"); } + "\n" + Localization.lang("Please create it in the document or change in the file:") @@ -401,20 +391,20 @@ private OOVoidResult checkStyleExistsInTheDocument(String familyName, if (!internalName.get().equals(styleName)) { String msg = switch (familyName) { - case UnoStyle.PARAGRAPH_STYLES -> - Localization.lang("The %0 paragraph style '%1' is a display name for '%2'.", - labelInJstyleFile, - styleName, - internalName.get()); - case UnoStyle.CHARACTER_STYLES -> - Localization.lang("The %0 character style '%1' is a display name for '%2'.", - labelInJstyleFile, - styleName, - internalName.get()); - default -> - throw new IllegalArgumentException("Expected " + UnoStyle.CHARACTER_STYLES - + " or " + UnoStyle.PARAGRAPH_STYLES - + " for familyName"); + case UnoStyle.PARAGRAPH_STYLES -> + Localization.lang("The %0 paragraph style '%1' is a display name for '%2'.", + labelInJstyleFile, + styleName, + internalName.get()); + case UnoStyle.CHARACTER_STYLES -> + Localization.lang("The %0 character style '%1' is a display name for '%2'.", + labelInJstyleFile, + styleName, + internalName.get()); + default -> + throw new IllegalArgumentException("Expected " + UnoStyle.CHARACTER_STYLES + + " or " + UnoStyle.PARAGRAPH_STYLES + + " for familyName"); } + "\n" + Localization.lang("Please use the latter in the style file below" @@ -449,8 +439,7 @@ public OOVoidResult checkStylesExistInTheDocument(OOBibStyle style, XTe "CitationCharacterFormat", pathToStyleFile)); } - } catch (NoSuchElementException - | WrappedTargetException ex) { + } catch (WrappedTargetException ex) { results.add(OOVoidResult.error(new OOError("Other error in checkStyleExistsInTheDocument", ex.getMessage(), ex))); @@ -490,8 +479,7 @@ public Optional> guiActionGetCitationEntries() { } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); return FAIL; - } catch (UnknownPropertyException - | WrappedTargetException ex) { + } catch (WrappedTargetException ex) { LOGGER.warn(title, ex); OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); return FAIL; @@ -541,10 +529,7 @@ public void guiActionApplyCitationEntries(List citationEntries) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); - } catch (UnknownPropertyException - | NotRemoveableException - | PropertyExistException - | PropertyVetoException + } catch (PropertyVetoException | IllegalTypeException | WrappedTargetException | com.sun.star.lang.IllegalArgumentException ex) { @@ -668,16 +653,10 @@ public void guiActionInsertEntry(List entries, } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); return; - } catch (JabRefException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); - return; } catch (CreationException | IllegalTypeException - | NoSuchElementException | NotRemoveableException - | PropertyExistException | PropertyVetoException - | UnknownPropertyException | WrappedTargetException ex) { LOGGER.warn("Could not insert entry", ex); OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); @@ -728,16 +707,10 @@ public void guiActionMergeCitationGroups(List databases, OOBibStyle OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); - } catch (JabRefException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (CreationException | IllegalTypeException - | InvalidStateException - | NoSuchElementException | NotRemoveableException - | PropertyExistException | PropertyVetoException - | UnknownPropertyException | WrappedTargetException | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn("Problem combining cite markers", ex); @@ -791,16 +764,10 @@ public void guiActionSeparateCitations(List databases, OOBibStyle s OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); - } catch (JabRefException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (CreationException | IllegalTypeException - | InvalidStateException - | NoSuchElementException | NotRemoveableException - | PropertyExistException | PropertyVetoException - | UnknownPropertyException | WrappedTargetException | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn("Problem during separating cite markers", ex); @@ -875,9 +842,7 @@ public Optional exportCitedHelper(List databases, OOError.from(ex).showErrorDialog(dialogService); } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); - } catch (NoSuchElementException - | UnknownPropertyException - | WrappedTargetException + } catch (WrappedTargetException | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn("Problem generating new database.", ex); OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); @@ -946,16 +911,11 @@ public void guiActionUpdateDocument(List databases, OOBibStyle styl return; } - } catch (JabRefException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (NoDocumentException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (CreationException - | NoSuchElementException - | PropertyVetoException - | UnknownPropertyException | WrappedTargetException | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn("Could not update bibliography", ex); diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java b/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java index c9f6246062b..728b5cf541e 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java @@ -25,16 +25,12 @@ import com.sun.star.lang.XMultiComponentFactory; import com.sun.star.text.XTextDocument; import com.sun.star.uno.XComponentContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Establish connection to a document opened in OpenOffice or LibreOffice. */ class OOBibBaseConnect { - private static final Logger LOGGER = LoggerFactory.getLogger(OOBibBaseConnect.class); - /* variables */ private final DialogService dialogService; private final XDesktop xDesktop; diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java index 1345f1f2a99..81491bd8590 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java @@ -5,7 +5,6 @@ import java.util.List; import java.util.Optional; -import org.jabref.logic.JabRefException; import org.jabref.logic.openoffice.frontend.OOFrontend; import org.jabref.logic.openoffice.frontend.UpdateCitationMarkers; import org.jabref.logic.openoffice.style.OOBibStyle; @@ -24,19 +23,16 @@ import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class EditInsert { - private static final Logger LOGGER = LoggerFactory.getLogger(EditInsert.class); + private EditInsert() { + /**/ + } /** * In insertEntry we receive BibEntry values from the GUI. @@ -68,16 +64,12 @@ public static void insertCitationGroup(XTextDocument doc, CitationType citationType, String pageInfo) throws - UnknownPropertyException, NoDocumentException, NotRemoveableException, WrappedTargetException, PropertyVetoException, - PropertyExistException, - NoSuchElementException, CreationException, - IllegalTypeException, - JabRefException { + IllegalTypeException { List citationKeys = OOListUtil.map(entries, EditInsert::insertEntryGetCitationKey); diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java index 4cd225eb1a8..43bdcd59e2d 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java @@ -6,7 +6,6 @@ import java.util.Optional; import java.util.stream.Collectors; -import org.jabref.logic.JabRefException; import org.jabref.logic.openoffice.frontend.OOFrontend; import org.jabref.logic.openoffice.frontend.UpdateCitationMarkers; import org.jabref.logic.openoffice.style.OOBibStyle; @@ -22,15 +21,11 @@ import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; import com.sun.star.text.XTextRange; -import com.sun.star.util.InvalidStateException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,14 +45,9 @@ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend fr, OOBi CreationException, IllegalArgumentException, IllegalTypeException, - InvalidStateException, - JabRefException, NoDocumentException, - NoSuchElementException, NotRemoveableException, - PropertyExistException, PropertyVetoException, - UnknownPropertyException, WrappedTargetException { boolean madeModifications = false; @@ -72,7 +62,7 @@ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend fr, OOBi List cgs = joinableGroupData.group; List newCitations = (cgs.stream() - .flatMap(cg -> cg.citationsInStorageOrder.stream()) + .flatMap(group -> group.citationsInStorageOrder.stream()) .collect(Collectors.toList())); CitationType citationType = cgs.get(0).citationType; @@ -155,15 +145,15 @@ void reset() { } /** - * Decide if cg could be added to state.currentGroup + * Decide if group could be added to state.currentGroup * - * @param cg The CitationGroup to test - * @param currentRange The XTextRange corresponding to cg. + * @param group The CitationGroup to test + * @param currentRange The XTextRange corresponding to group. * * @return false if cannot add, true if can. If returned true, then state.cursorBetween and * state.currentGroupCursor are expanded to end at the start of currentRange. */ - private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextRange currentRange) { + private static boolean checkAddToGroup(ScanState state, CitationGroup group, XTextRange currentRange) { if (state.currentGroup.isEmpty()) { return false; @@ -175,14 +165,14 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextR Objects.requireNonNull(state.prevRange); // Only combine (Author 2000) type citations - if (cg.citationType != CitationType.AUTHORYEAR_PAR) { + if (group.citationType != CitationType.AUTHORYEAR_PAR) { return false; } if (state.prev != null) { // Even if we combine AUTHORYEAR_INTEXT citations, we would not mix them with AUTHORYEAR_PAR - if (cg.citationType != state.prev.citationType) { + if (group.citationType != state.prev.citationType) { return false; } @@ -253,20 +243,16 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup cg, XTextR } } - if (!couldExpand) { - return false; - } - - return true; + return couldExpand; } /** - * Add cg to state.currentGroup + * Add group to state.currentGroup * Set state.cursorBetween to start at currentRange.getEnd() * Expand state.currentGroupCursor to also cover currentRange - * Set state.prev to cg, state.prevRange to currentRange + * Set state.prev to group, state.prevRange to currentRange */ - private static void addToCurrentGroup(ScanState state, CitationGroup cg, XTextRange currentRange) { + private static void addToCurrentGroup(ScanState state, CitationGroup group, XTextRange currentRange) { final boolean isNewGroup = state.currentGroup.isEmpty(); if (!isNewGroup) { Objects.requireNonNull(state.currentGroupCursor); @@ -276,7 +262,7 @@ private static void addToCurrentGroup(ScanState state, CitationGroup cg, XTextRa } // Add the current entry to a group. - state.currentGroup.add(cg); + state.currentGroup.add(group); // Set up cursorBetween to start at currentRange.getEnd() XTextRange rangeEnd = currentRange.getEnd(); @@ -297,7 +283,7 @@ private static void addToCurrentGroup(ScanState state, CitationGroup cg, XTextRa } /* Store data about last entry in currentGroup */ - state.prev = cg; + state.prev = group; state.prevRange = currentRange; } @@ -317,22 +303,22 @@ private static List scan(XTextDocument doc, OOFrontend fr) ScanState state = new ScanState(); - for (CitationGroup cg : cgs) { + for (CitationGroup group : cgs) { - XTextRange currentRange = (fr.getMarkRange(doc, cg) + XTextRange currentRange = (fr.getMarkRange(doc, group) .orElseThrow(IllegalStateException::new)); /* - * Decide if we add cg to the group. False when the group is empty. + * Decide if we add group to the group. False when the group is empty. */ - boolean addToGroup = checkAddToGroup(state, cg, currentRange); + boolean addToGroup = checkAddToGroup(state, group, currentRange); /* * Even if we do not add it to an existing group, we might use it to start a new group. * * Can it start a new group? */ - boolean canStartGroup = (cg.citationType == CitationType.AUTHORYEAR_PAR); + boolean canStartGroup = (group.citationType == CitationType.AUTHORYEAR_PAR); if (!addToGroup) { // close currentGroup @@ -344,7 +330,7 @@ private static List scan(XTextDocument doc, OOFrontend fr) } if (addToGroup || canStartGroup) { - addToCurrentGroup(state, cg, currentRange); + addToCurrentGroup(state, group, currentRange); } } diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java index 0293159d34f..fba50a93c6e 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java @@ -2,7 +2,6 @@ import java.util.List; -import org.jabref.logic.JabRefException; import org.jabref.logic.openoffice.frontend.OOFrontend; import org.jabref.logic.openoffice.frontend.UpdateCitationMarkers; import org.jabref.logic.openoffice.style.OOBibStyle; @@ -17,18 +16,18 @@ import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; import com.sun.star.text.XTextRange; -import com.sun.star.util.InvalidStateException; public class EditSeparate { + private EditSeparate() { + /**/ + } + public static boolean separateCitations(XTextDocument doc, OOFrontend fr, List databases, @@ -36,14 +35,9 @@ public static boolean separateCitations(XTextDocument doc, throws CreationException, IllegalTypeException, - InvalidStateException, - JabRefException, NoDocumentException, - NoSuchElementException, NotRemoveableException, - PropertyExistException, PropertyVetoException, - UnknownPropertyException, WrappedTargetException, com.sun.star.lang.IllegalArgumentException { @@ -61,19 +55,19 @@ public static boolean separateCitations(XTextDocument doc, try { UnoScreenRefresh.lockControllers(doc); - for (CitationGroup cg : cgs) { + for (CitationGroup group : cgs) { XTextRange range1 = (fr - .getMarkRange(doc, cg) + .getMarkRange(doc, group) .orElseThrow(IllegalStateException::new)); XTextCursor textCursor = range1.getText().createTextCursorByRange(range1); - List cits = cg.citationsInStorageOrder; + List cits = group.citationsInStorageOrder; if (cits.size() <= 1) { continue; } - fr.removeCitationGroup(cg, doc); + fr.removeCitationGroup(group, doc); // Now we own the content of cits // Create a citation group for each citation. @@ -86,7 +80,7 @@ public static boolean separateCitations(XTextDocument doc, doc, List.of(cit.citationKey), List.of(cit.getPageInfo()), - cg.citationType, + group.citationType, OOText.fromString(cit.citationKey), textCursor, style, diff --git a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java index ef7985d666a..26ed654de21 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java +++ b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java @@ -13,13 +13,15 @@ import org.jabref.model.openoffice.style.CitedKeys; import org.jabref.model.openoffice.uno.NoDocumentException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextDocument; public class ExportCited { + private ExportCited() { + /**/ + } + public static class GenerateDatabaseResult { /** * null: not done; isEmpty: no unresolved @@ -47,8 +49,6 @@ public static class GenerateDatabaseResult { public static GenerateDatabaseResult generateDatabase(XTextDocument doc, List databases) throws NoDocumentException, - NoSuchElementException, - UnknownPropertyException, WrappedTargetException { OOFrontend fr = new OOFrontend(doc); diff --git a/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java b/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java index 4046cbbe11b..9782261f612 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java +++ b/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java @@ -7,19 +7,19 @@ import org.jabref.model.openoffice.uno.NoDocumentException; import com.sun.star.beans.IllegalTypeException; -import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextDocument; public class ManageCitations { + private ManageCitations() { + /**/ + } + public static List getCitationEntries(XTextDocument doc) throws NoDocumentException, - UnknownPropertyException, WrappedTargetException { OOFrontend fr = new OOFrontend(doc); return fr.getCitationEntries(doc); @@ -28,9 +28,6 @@ public static List getCitationEntries(XTextDocument doc) public static void applyCitationEntries(XTextDocument doc, List citationEntries) throws NoDocumentException, - UnknownPropertyException, - NotRemoveableException, - PropertyExistException, PropertyVetoException, IllegalTypeException, WrappedTargetException, diff --git a/src/main/java/org/jabref/logic/openoffice/action/Update.java b/src/main/java/org/jabref/logic/openoffice/action/Update.java index 675afb2a79f..49f79d6d2e7 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/Update.java +++ b/src/main/java/org/jabref/logic/openoffice/action/Update.java @@ -2,7 +2,6 @@ import java.util.List; -import org.jabref.logic.JabRefException; import org.jabref.logic.openoffice.frontend.OOFrontend; import org.jabref.logic.openoffice.frontend.UpdateBibliography; import org.jabref.logic.openoffice.frontend.UpdateCitationMarkers; @@ -14,9 +13,6 @@ import org.jabref.model.openoffice.uno.NoDocumentException; import org.jabref.model.openoffice.uno.UnoScreenRefresh; -import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextDocument; @@ -25,6 +21,10 @@ */ public class Update { + private Update() { + /**/ + } + /** * @return the list of unresolved citation keys */ @@ -37,11 +37,7 @@ private static List updateDocument(XTextDocument doc, boolean alwaysAddCitedOnPages) throws CreationException, - JabRefException, NoDocumentException, - NoSuchElementException, - PropertyVetoException, - UnknownPropertyException, WrappedTargetException, com.sun.star.lang.IllegalArgumentException { @@ -64,8 +60,8 @@ private static List updateDocument(XTextDocument doc, style, alwaysAddCitedOnPages); } - List result = fr.citationGroups.getUnresolvedKeys(); - return result; + + return fr.citationGroups.getUnresolvedKeys(); } finally { if (useLockControllers && UnoScreenRefresh.hasControllersLocked(doc)) { UnoScreenRefresh.unlockControllers(doc); @@ -103,11 +99,7 @@ public static List synchronizeDocument(XTextDocument doc, SyncOptions syncOptions) throws CreationException, - JabRefException, NoDocumentException, - NoSuchElementException, - PropertyVetoException, - UnknownPropertyException, WrappedTargetException, com.sun.star.lang.IllegalArgumentException { @@ -129,11 +121,7 @@ public static List resyncDocument(XTextDocument doc, SyncOptions syncOptions) throws CreationException, - JabRefException, NoDocumentException, - NoSuchElementException, - PropertyVetoException, - UnknownPropertyException, WrappedTargetException, com.sun.star.lang.IllegalArgumentException { diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java index 878571090f0..0016e5e4510 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java @@ -36,6 +36,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Backend52, Codec52 and OODataModel.JabRef52 refer to the mode of storage, encoding and + * what-is-stored in the document under JabRef version 5.2. These basically did not change up to + * JabRef 5.4. + */ public class Backend52 { private static final Logger LOGGER = LoggerFactory.getLogger(Backend52.class); public final OODataModel dataModel; @@ -59,7 +64,7 @@ public Backend52() { public List getJabRefReferenceMarkNames(XTextDocument doc) throws NoDocumentException { - List allNames = this.citationStorageManager.nrmGetUsedNames(doc); + List allNames = this.citationStorageManager.getUsedNames(doc); return Codec52.filterIsJabRefReferenceMarkName(allNames); } @@ -73,8 +78,7 @@ public List getJabRefReferenceMarkNames(XTextDocument doc) private List findUnusedJabrefPropertyNames(XTextDocument doc, List citationGroupNames) { - // Collect unused jabrefPropertyNames - Set citationGroupNamesSet = citationGroupNames.stream().collect(Collectors.toSet()); + Set citationGroupNamesSet = new HashSet<>(citationGroupNames); List pageInfoThrash = new ArrayList<>(); List jabrefPropertyNames = @@ -99,13 +103,13 @@ public Optional healthReport(XTextDocument doc) List pageInfoThrash = this.findUnusedJabrefPropertyNames(doc, this.getJabRefReferenceMarkNames(doc)); if (pageInfoThrash.isEmpty()) { - return Optional.empty(); // "Backend52: found no unused pageInfo data"; + return Optional.empty(); } - String msg = - "Backend52: found unused pageInfo data, with names listed below.\n" - + "In LibreOffice you may remove these in [File]/[Properties]/[Custom Properties]\n"; - msg += "" + String.join("\n", pageInfoThrash) + ""; - return Optional.of(msg); + + StringBuilder msg = new StringBuilder("Backend52: found unused pageInfo data, with names listed below.\n"); + msg.append("In LibreOffice you may remove these in [File]/[Properties]/[Custom Properties]\n"); + msg.append(String.join("\n", pageInfoThrash)); + return Optional.of(msg.toString()); } private static void setPageInfoInDataInitial(List citations, Optional pageInfo) { @@ -115,8 +119,8 @@ private static void setPageInfoInDataInitial(List citations, Optional< } } - private static Optional getPageInfoFromData(CitationGroup cg) { - List citations = cg.getCitationsInLocalOrder(); + private static Optional getPageInfoFromData(CitationGroup group) { + List citations = group.getCitationsInLocalOrder(); if (citations.isEmpty()) { return Optional.empty(); } @@ -124,54 +128,52 @@ private static Optional getPageInfoFromData(CitationGroup cg) { } /** - * We have circular dependency here: backend uses - * class from ... + * @param markName Reference mark name */ - public CitationGroup readCitationGroupFromDocumentOrThrow(XTextDocument doc, String refMarkName) + public CitationGroup readCitationGroupFromDocumentOrThrow(XTextDocument doc, String markName) throws WrappedTargetException, NoDocumentException { - Optional optionalParsed = Codec52.parseMarkName(refMarkName); - if (optionalParsed.isEmpty()) { - throw new IllegalArgumentException("readCitationGroupFromDocumentOrThrow:" - + " found unparsable referenceMarkName"); - } - Codec52.ParsedMarkName parsed = optionalParsed.get(); + Codec52.ParsedMarkName parsed = Codec52.parseMarkName(markName).orElseThrow(IllegalArgumentException::new); + List citations = (parsed.citationKeys.stream() .map(Citation::new) .collect(Collectors.toList())); - Optional pageInfo = (UnoUserDefinedProperty.getStringValue(doc, refMarkName) + Optional pageInfo = (UnoUserDefinedProperty.getStringValue(doc, markName) .map(OOText::fromString)); pageInfo = PageInfo.normalizePageInfo(pageInfo); setPageInfoInDataInitial(citations, pageInfo); - Optional namedRange = citationStorageManager.nrmGetFromDocument(doc, refMarkName); - - if (namedRange.isEmpty()) { - throw new IllegalArgumentException("readCitationGroupFromDocumentOrThrow:" - + " referenceMarkName is not in the document"); - } - - CitationGroupId cgid = new CitationGroupId(refMarkName); - CitationGroup cg = new CitationGroup(OODataModel.JabRef52, - cgid, - parsed.citationType, - citations, - Optional.of(refMarkName)); - this.cgidToNamedRange.put(cgid, namedRange.get()); - return cg; + NamedRange namedRange = (citationStorageManager.getNamedRangeFromDocument(doc, markName) + .orElseThrow(IllegalArgumentException::new)); + + CitationGroupId groupId = new CitationGroupId(markName); + CitationGroup group = new CitationGroup(OODataModel.JabRef52, + groupId, + parsed.citationType, + citations, + Optional.of(markName)); + this.cgidToNamedRange.put(groupId, namedRange); + return group; } /** - * Create a reference mark with the given name, at the end of position. + * Create a reference mark at the end of {@code position} in the document. * * On return {@code position} is collapsed, and is after the inserted space, or at the end of * the reference mark. * + * @param citationKeys Keys to be cited. + * + * @param pageInfos An optional pageInfo for each citation key. + * Backend52 only uses and stores the last pageInfo, + * all others should be Optional.empty() + * * @param position Collapsed to its end. + * * @param insertSpaceAfter We insert a space after the mark, that carries on format of * characters from the original position. */ @@ -191,42 +193,46 @@ public CitationGroup createCitationGroup(XTextDocument doc, Objects.requireNonNull(pageInfos); if (pageInfos.size() != citationKeys.size()) { - throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); + throw new IllegalArgumentException(); } - // Get a new refMarkName - Set usedNames = new HashSet<>(this.citationStorageManager.nrmGetUsedNames(doc)); - String xkey = (citationKeys.stream().collect(Collectors.joining(","))); - String refMarkName = Codec52.getUniqueMarkName(usedNames, xkey, citationType); + /* + * Backend52 uses reference marks to (1) mark the location of the citation in the text and (2) to encode + * the citation keys and citation type in the name of the reference mark. The name of the reference mark + * has to be unique in the document. + */ + String markName = Codec52.getUniqueMarkName(new HashSet<>(citationStorageManager.getUsedNames(doc)), + citationKeys, + citationType); - CitationGroupId cgid = new CitationGroupId(refMarkName); + CitationGroupId groupId = new CitationGroupId(markName); - final int nCitations = citationKeys.size(); - final int last = nCitations - 1; + final int numberOfCitations = citationKeys.size(); + final int last = numberOfCitations - 1; // Build citations, add pageInfo to each citation - List citations = new ArrayList<>(nCitations); - for (int i = 0; i < nCitations; i++) { + List citations = new ArrayList<>(numberOfCitations); + for (int i = 0; i < numberOfCitations; i++) { Citation cit = new Citation(citationKeys.get(i)); citations.add(cit); Optional pageInfo = PageInfo.normalizePageInfo(pageInfos.get(i)); switch (dataModel) { - case JabRef52: - if (i == last) { - cit.setPageInfo(pageInfo); - } else { - if (pageInfo.isPresent()) { - LOGGER.warn("dataModel JabRef52" - + " only supports pageInfo for the last citation of a group"); + case JabRef52: + if (i == last) { + cit.setPageInfo(pageInfo); + } else { + if (pageInfo.isPresent()) { + LOGGER.warn("dataModel JabRef52" + + " only supports pageInfo for the last citation of a group"); + } } - } - break; - case JabRef60: - cit.setPageInfo(pageInfo); - break; - default: - throw new IllegalStateException("Unhandled dataModel in Backend52.createCitationGroup"); + break; + case JabRef60: + cit.setPageInfo(pageInfo); + break; + default: + throw new IllegalStateException("Unhandled dataModel in Backend52.createCitationGroup"); } } @@ -234,29 +240,33 @@ public CitationGroup createCitationGroup(XTextDocument doc, * Apply to document */ boolean withoutBrackets = (citationType == CitationType.INVISIBLE_CIT); - NamedRange namedRange = - this.citationStorageManager.nrmCreate(doc, refMarkName, position, insertSpaceAfter, - withoutBrackets); + NamedRange namedRange = this.citationStorageManager.createNamedRange(doc, + markName, + position, + insertSpaceAfter, + withoutBrackets); switch (dataModel) { - case JabRef52: - Optional pageInfo = PageInfo.normalizePageInfo(pageInfos.get(last)); - - if (pageInfo.isPresent()) { - String pageInfoString = OOText.toString(pageInfo.get()); - UnoUserDefinedProperty.setStringProperty(doc, refMarkName, pageInfoString); - } else { - // do not inherit from trash - UnoUserDefinedProperty.removeIfExists(doc, refMarkName); - } - CitationGroup cg = new CitationGroup(OODataModel.JabRef52, - cgid, - citationType, citations, - Optional.of(refMarkName)); - this.cgidToNamedRange.put(cgid, namedRange); - return cg; - default: - throw new IllegalStateException("Backend52 requires JabRef52 dataModel"); + case JabRef52: + Optional pageInfo = PageInfo.normalizePageInfo(pageInfos.get(last)); + + if (pageInfo.isPresent()) { + String pageInfoString = OOText.toString(pageInfo.get()); + UnoUserDefinedProperty.setStringProperty(doc, markName, pageInfoString); + } else { + // do not inherit from trash + UnoUserDefinedProperty.removeIfExists(doc, markName); + } + CitationGroup group = new CitationGroup(OODataModel.JabRef52, + groupId, + citationType, citations, + Optional.of(markName)); + this.cgidToNamedRange.put(groupId, namedRange); + return group; + case JabRef60: + throw new IllegalStateException("createCitationGroup for JabRef60 is not implemented yet"); + default: + throw new IllegalStateException("Unhandled dataModel in Backend52.createCitationGroup"); } } @@ -269,33 +279,33 @@ public CitationGroup createCitationGroup(XTextDocument doc, public static List> combinePageInfosCommon(OODataModel dataModel, List joinableGroup) { switch (dataModel) { - case JabRef52: - // collect to cgPageInfos - List> cgPageInfos = OOListUtil.map(joinableGroup, - Backend52::getPageInfoFromData); - - // Try to do something of the cgPageInfos. - String cgPageInfo = (cgPageInfos.stream() - .filter(pi -> pi.isPresent()) - .map(pi -> OOText.toString(pi.get())) - .distinct() - .collect(Collectors.joining("; "))); - - int nCitations = (joinableGroup.stream() - .map(CitationGroup::numberOfCitations) - .mapToInt(Integer::intValue).sum()); - if ("".equals(cgPageInfo)) { - cgPageInfo = null; - } - return OODataModel.fakePageInfos(cgPageInfo, nCitations); - - case JabRef60: - return (joinableGroup.stream() - .flatMap(cg -> (cg.citationsInStorageOrder.stream() - .map(Citation::getPageInfo))) - .collect(Collectors.toList())); - default: - throw new IllegalArgumentException("unhandled dataModel here"); + case JabRef52: + // collect to pageInfos + List> pageInfos = OOListUtil.map(joinableGroup, + Backend52::getPageInfoFromData); + + // Try to do something of the pageInfos. + String singlePageInfo = (pageInfos.stream() + .filter(Optional::isPresent) + .map(pi -> OOText.toString(pi.get())) + .distinct() + .collect(Collectors.joining("; "))); + + int totalCitations = (joinableGroup.stream() + .map(CitationGroup::numberOfCitations) + .mapToInt(Integer::intValue).sum()); + if ("".equals(singlePageInfo)) { + singlePageInfo = null; + } + return OODataModel.fakePageInfos(singlePageInfo, totalCitations); + + case JabRef60: + return (joinableGroup.stream() + .flatMap(group -> (group.citationsInStorageOrder.stream() + .map(Citation::getPageInfo))) + .collect(Collectors.toList())); + default: + throw new IllegalArgumentException("unhandled dataModel here"); } } @@ -306,70 +316,70 @@ public List> combinePageInfos(List joinableGroup return combinePageInfosCommon(this.dataModel, joinableGroup); } - private NamedRange getNamedRangeOrThrow(CitationGroup cg) { - NamedRange namedRange = this.cgidToNamedRange.get(cg.cgid); + private NamedRange getNamedRangeOrThrow(CitationGroup group) { + NamedRange namedRange = this.cgidToNamedRange.get(group.groupId); if (namedRange == null) { throw new IllegalStateException("getNamedRange: could not lookup namedRange"); } return namedRange; } - public void removeCitationGroup(CitationGroup cg, XTextDocument doc) + public void removeCitationGroup(CitationGroup group, XTextDocument doc) throws WrappedTargetException, NoDocumentException, NotRemoveableException { - NamedRange namedRange = getNamedRangeOrThrow(cg); - String refMarkName = namedRange.nrGetRangeName(); - namedRange.nrRemoveFromDocument(doc); + NamedRange namedRange = getNamedRangeOrThrow(group); + String refMarkName = namedRange.getRangeName(); + namedRange.removeFromDocument(doc); UnoUserDefinedProperty.removeIfExists(doc, refMarkName); - this.cgidToNamedRange.remove(cg.cgid); + this.cgidToNamedRange.remove(group.groupId); } /** * @return Optional.empty if the reference mark is missing. */ - public Optional getMarkRange(CitationGroup cg, XTextDocument doc) + public Optional getMarkRange(CitationGroup group, XTextDocument doc) throws NoDocumentException, WrappedTargetException { - NamedRange namedRange = getNamedRangeOrThrow(cg); - return namedRange.nrGetMarkRange(doc); + NamedRange namedRange = getNamedRangeOrThrow(group); + return namedRange.getMarkRange(doc); } /** * Cursor for the reference marks as is: not prepared for filling, but does not need * cleanFillCursorForCitationGroup either. */ - public Optional getRawCursorForCitationGroup(CitationGroup cg, XTextDocument doc) + public Optional getRawCursorForCitationGroup(CitationGroup group, XTextDocument doc) throws NoDocumentException, WrappedTargetException { - NamedRange namedRange = getNamedRangeOrThrow(cg); - return namedRange.nrGetRawCursor(doc); + NamedRange namedRange = getNamedRangeOrThrow(group); + return namedRange.getRawCursor(doc); } /** * Must be followed by call to cleanFillCursorForCitationGroup */ - public XTextCursor getFillCursorForCitationGroup(CitationGroup cg, XTextDocument doc) + public XTextCursor getFillCursorForCitationGroup(CitationGroup group, XTextDocument doc) throws NoDocumentException, WrappedTargetException, CreationException { - NamedRange namedRange = getNamedRangeOrThrow(cg); - return namedRange.nrGetFillCursor(doc); + NamedRange namedRange = getNamedRangeOrThrow(group); + return namedRange.getFillCursor(doc); } /** To be called after getFillCursorForCitationGroup */ - public void cleanFillCursorForCitationGroup(CitationGroup cg, XTextDocument doc) + public void cleanFillCursorForCitationGroup(CitationGroup group, XTextDocument doc) throws NoDocumentException, WrappedTargetException { - NamedRange namedRange = getNamedRangeOrThrow(cg); - namedRange.nrCleanFillCursor(doc); + NamedRange namedRange = getNamedRangeOrThrow(group); + namedRange.cleanFillCursor(doc); } public List getCitationEntries(XTextDocument doc, CitationGroups cgs) @@ -378,29 +388,29 @@ public List getCitationEntries(XTextDocument doc, CitationGroups NoDocumentException { switch (dataModel) { - case JabRef52: - // One context per CitationGroup: Backend52 (DataModel.JabRef52) - // For DataModel.JabRef60 (Backend60) we need one context per Citation - List citations = new ArrayList<>(cgs.numberOfCitationGroups()); - for (CitationGroup cg : cgs.getCitationGroupsUnordered()) { - String name = cg.cgid.citationGroupIdAsString(); - XTextCursor cursor = (this - .getRawCursorForCitationGroup(cg, doc) - .orElseThrow(IllegalStateException::new)); - String context = GetContext.getCursorStringWithContext(cursor, 30, 30, true); - Optional pageInfo = (cg.numberOfCitations() > 0 - ? (getPageInfoFromData(cg) - .map(e -> OOText.toString(e))) - : Optional.empty()); - CitationEntry entry = new CitationEntry(name, context, pageInfo); - citations.add(entry); - } - return citations; - case JabRef60: - // xx - throw new IllegalStateException("getCitationEntries for JabRef60 is not implemented yet"); - default: - throw new IllegalStateException("getCitationEntries: unhandled dataModel "); + case JabRef52: + // One context per CitationGroup: Backend52 (DataModel.JabRef52) + // For DataModel.JabRef60 (Backend60) we need one context per Citation + List citations = new ArrayList<>(cgs.numberOfCitationGroups()); + for (CitationGroup group : cgs.getCitationGroupsUnordered()) { + String name = group.groupId.citationGroupIdAsString(); + XTextCursor cursor = (this + .getRawCursorForCitationGroup(group, doc) + .orElseThrow(IllegalStateException::new)); + String context = GetContext.getCursorStringWithContext(cursor, 30, 30, true); + Optional pageInfo = (group.numberOfCitations() > 0 + ? (getPageInfoFromData(group) + .map(e -> OOText.toString(e))) + : Optional.empty()); + CitationEntry entry = new CitationEntry(name, context, pageInfo); + citations.add(entry); + } + return citations; + case JabRef60: + // xx + throw new IllegalStateException("getCitationEntries for JabRef60 is not implemented yet"); + default: + throw new IllegalStateException("getCitationEntries: unhandled dataModel "); } } @@ -415,21 +425,21 @@ public void applyCitationEntries(XTextDocument doc, List citation WrappedTargetException { switch (dataModel) { - case JabRef52: - for (CitationEntry entry : citationEntries) { - Optional pageInfo = entry.getPageInfo().map(OOText::fromString); - pageInfo = PageInfo.normalizePageInfo(pageInfo); - if (pageInfo.isPresent()) { - String name = entry.getRefMarkName(); - UnoUserDefinedProperty.setStringProperty(doc, name, pageInfo.get().toString()); + case JabRef52: + for (CitationEntry entry : citationEntries) { + Optional pageInfo = entry.getPageInfo().map(OOText::fromString); + pageInfo = PageInfo.normalizePageInfo(pageInfo); + if (pageInfo.isPresent()) { + String name = entry.getRefMarkName(); + UnoUserDefinedProperty.setStringProperty(doc, name, pageInfo.get().toString()); + } } - } - break; - case JabRef60: - // xx - throw new IllegalStateException("applyCitationEntries for JabRef60 is not implemented yet"); - default: - throw new IllegalStateException("applyCitationEntries: unhandled dataModel "); + break; + case JabRef60: + // xx + throw new IllegalStateException("applyCitationEntries for JabRef60 is not implemented yet"); + default: + throw new IllegalStateException("applyCitationEntries: unhandled dataModel "); } } diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java index f6d2b12245e..f567a3e459e 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java @@ -12,7 +12,7 @@ import org.jabref.model.openoffice.style.CitationType; /** - * How and what is encoded in a mark names. + * How and what is encoded in reference mark names under JabRef 5.2. * * - pageInfo does not appear here. It is not encoded in the mark name. */ @@ -51,51 +51,46 @@ public static class ParsedMarkName { * Integer representation was written into the document in JabRef52, keep it for compatibility. */ private static CitationType citationTypeFromInt(int i) { - switch (i) { - case 1: - return CitationType.AUTHORYEAR_PAR; - case 2: - return CitationType.AUTHORYEAR_INTEXT; - case 3: - return CitationType.INVISIBLE_CIT; - default: - throw new IllegalArgumentException("Invalid CitationType code"); - } + return switch (i) { + case 1 -> CitationType.AUTHORYEAR_PAR; + case 2 -> CitationType.AUTHORYEAR_INTEXT; + case 3 -> CitationType.INVISIBLE_CIT; + default -> throw new IllegalArgumentException("Invalid CitationType code"); + }; } private static int citationTypeToInt(CitationType i) { - switch (i) { - case AUTHORYEAR_PAR: - return 1; - case AUTHORYEAR_INTEXT: - return 2; - case INVISIBLE_CIT: - return 3; - default: - throw new IllegalArgumentException("Invalid CitationType"); - } + return switch (i) { + case AUTHORYEAR_PAR -> 1; + case AUTHORYEAR_INTEXT -> 2; + case INVISIBLE_CIT -> 3; + default -> throw new IllegalArgumentException("Invalid CitationType"); + }; } /** - * Produce a reference mark name for JabRef for the given citation key and citationType that + * Produce a reference mark name for JabRef for the given citationType and list citation keys that * does not yet appear among the reference marks of the document. * - * @param bibtexKey The citation key. + * @param usedNames Reference mark names already in use. + * @param citationKeys Identifies the cited sources. * @param citationType Encodes the effect of withText and inParenthesis options. * - * The first occurrence of bibtexKey gets no serial number, the second gets 0, the third 1 ... + * The first occurrence of citationKeys gets no serial number, the second gets 0, the third 1 ... * * Or the first unused in this series, after removals. */ public static String getUniqueMarkName(Set usedNames, - String bibtexKey, + List citationKeys, CitationType citationType) { + String citationKeysPart = String.join(",", citationKeys); + int i = 0; int citTypeCode = citationTypeToInt(citationType); - String name = BIB_CITATION + '_' + citTypeCode + '_' + bibtexKey; + String name = BIB_CITATION + '_' + citTypeCode + '_' + citationKeysPart; while (usedNames.contains(name)) { - name = BIB_CITATION + i + '_' + citTypeCode + '_' + bibtexKey; + name = BIB_CITATION + i + '_' + citTypeCode + '_' + citationKeysPart; i++; } return name; @@ -135,9 +130,8 @@ public static boolean isJabRefReferenceMarkName(String name) { * @param names The list to be filtered. */ public static List filterIsJabRefReferenceMarkName(List names) { - return (names - .stream() - .filter(Codec52::isJabRefReferenceMarkName) - .collect(Collectors.toList())); + return (names.stream() + .filter(Codec52::isJabRefReferenceMarkName) + .collect(Collectors.toList())); } } diff --git a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java index d82ad08378e..93ad6d12908 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java @@ -16,25 +16,25 @@ public class NamedRangeManagerReferenceMark implements NamedRangeManager { @Override - public NamedRange nrmCreate(XTextDocument doc, - String refMarkName, - XTextCursor position, - boolean insertSpaceAfter, - boolean withoutBrackets) + public NamedRange createNamedRange(XTextDocument doc, + String refMarkName, + XTextCursor position, + boolean insertSpaceAfter, + boolean withoutBrackets) throws CreationException { return NamedRangeReferenceMark.create(doc, refMarkName, position, insertSpaceAfter, withoutBrackets); } @Override - public List nrmGetUsedNames(XTextDocument doc) + public List getUsedNames(XTextDocument doc) throws NoDocumentException { return UnoReferenceMark.getListOfNames(doc); } @Override - public Optional nrmGetFromDocument(XTextDocument doc, String refMarkName) + public Optional getNamedRangeFromDocument(XTextDocument doc, String refMarkName) throws NoDocumentException, WrappedTargetException { 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 a11e29aecd1..cfabb1e2de0 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java @@ -141,43 +141,42 @@ static Optional getFromDocument(XTextDocument doc, Stri .map(e -> new NamedRangeReferenceMark(refMarkName))); } - /* + /** * Remove it from the document. * * See: removeCitationGroups */ @Override - public void nrRemoveFromDocument(XTextDocument doc) + public void removeFromDocument(XTextDocument doc) throws WrappedTargetException, NoDocumentException { - UnoReferenceMark.removeIfExists(doc, this.nrGetRangeName()); + UnoReferenceMark.removeIfExists(doc, this.getRangeName()); } @Override - public String nrGetRangeName() { + public String getRangeName() { return id; } - /* - * ranges controlled by citation groups should not overlap with each other. + /** * * @return Optional.empty if the reference mark is missing. * * See: UnoReferenceMark.getAnchor */ @Override - public Optional nrGetMarkRange(XTextDocument doc) + public Optional getMarkRange(XTextDocument doc) throws NoDocumentException, WrappedTargetException { - String name = this.nrGetRangeName(); + String name = this.getRangeName(); return UnoReferenceMark.getAnchor(doc, name); } /** * Cursor for the reference marks as is, not prepared for filling, but does not need - * nrCleanFillCursor either. + * cleanFillCursor either. * * @return Optional.empty() if reference mark is missing from the document, * otherwise an XTextCursor for getMarkRange @@ -185,22 +184,22 @@ public Optional nrGetMarkRange(XTextDocument doc) * See: getRawCursorForCitationGroup */ @Override - public Optional nrGetRawCursor(XTextDocument doc) + public Optional getRawCursor(XTextDocument doc) throws NoDocumentException, WrappedTargetException { - String name = this.nrGetRangeName(); + String name = this.getRangeName(); Optional markAsTextContent = UnoReferenceMark.getAsTextContent(doc, name); if (markAsTextContent.isEmpty()) { - LOGGER.warn("nrGetRawCursor: markAsTextContent({}).isEmpty()", name); + LOGGER.warn("getRawCursor: markAsTextContent({}).isEmpty()", name); } Optional full = UnoCursor.getTextCursorOfTextContentAnchor(markAsTextContent.get()); if (full.isEmpty()) { - LOGGER.warn("nrGetRawCursor: full.isEmpty()"); + LOGGER.warn("getRawCursor: full.isEmpty()"); return Optional.empty(); } return full; @@ -210,13 +209,13 @@ public Optional nrGetRawCursor(XTextDocument doc) * See: getFillCursorForCitationGroup */ @Override - public XTextCursor nrGetFillCursor(XTextDocument doc) + public XTextCursor getFillCursor(XTextDocument doc) throws NoDocumentException, WrappedTargetException, CreationException { - String name = this.nrGetRangeName(); + String name = this.getRangeName(); final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; @@ -228,31 +227,31 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) Optional markAsTextContent = UnoReferenceMark.getAsTextContent(doc, name); if (markAsTextContent.isEmpty()) { - String msg = String.format("nrGetFillCursor: markAsTextContent(%s).isEmpty (attempt %d)", name, i); + String msg = String.format("getFillCursor: markAsTextContent(%s).isEmpty (attempt %d)", name, i); throw new IllegalStateException(msg); } full = UnoCursor.getTextCursorOfTextContentAnchor(markAsTextContent.get()).orElse(null); if (full == null) { - String msg = String.format("nrGetFillCursor: full == null (attempt %d)", i); + String msg = String.format("getFillCursor: full == null (attempt %d)", i); throw new IllegalStateException(msg); } fullText = full.getString(); - LOGGER.debug("nrGetFillCursor: fulltext = '{}'", fullText); + LOGGER.debug("getFillCursor: fulltext = '{}'", fullText); if (fullText.length() >= 2) { - LOGGER.debug("nrGetFillCursor: (attempt: {}) fulltext.length() >= 2, break loop%n", i); + LOGGER.debug("getFillCursor: (attempt: {}) fulltext.length() >= 2, break loop%n", i); break; } else { // (fullText.length() < 2) if (i == 2) { - String msg = String.format("nrGetFillCursor: (fullText.length() < 2) (attempt %d)", i); + String msg = String.format("getFillCursor: (fullText.length() < 2) (attempt %d)", i); throw new IllegalStateException(msg); } // too short, recreate - LOGGER.warn("nrGetFillCursor: too short, recreate"); + LOGGER.warn("getFillCursor: too short, recreate"); full.setString(""); UnoReferenceMark.removeIfExists(doc, name); @@ -264,27 +263,27 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) } if (full == null) { - throw new IllegalStateException("nrGetFillCursorFor: full == null (after loop)"); + throw new IllegalStateException("getFillCursorFor: full == null (after loop)"); } if (fullText == null) { - throw new IllegalStateException("nrGetFillCursor: fullText == null (after loop)"); + throw new IllegalStateException("getFillCursor: fullText == null (after loop)"); } fullText = full.getString(); if (fullText.length() < 2) { - throw new IllegalStateException("nrGetFillCursor: fullText.length() < 2 (after loop)'%n"); + throw new IllegalStateException("getFillCursor: fullText.length() < 2 (after loop)'%n"); } XTextCursor beta = full.getText().createTextCursorByRange(full); beta.collapseToStart(); beta.goRight((short) 1, false); beta.goRight((short) (fullText.length() - 2), true); - LOGGER.debug("nrGetFillCursor: beta(1) covers '{}'", beta.getString()); + LOGGER.debug("getFillCursor: beta(1) covers '{}'", beta.getString()); final short rightLength = (short) right.length(); if (fullText.startsWith(left) && fullText.endsWith(right)) { beta.setString(""); } else { - LOGGER.debug("nrGetFillCursor: recreating brackets for '{}'", fullText); + LOGGER.debug("getFillCursor: recreating brackets for '{}'", fullText); // we have at least two characters inside XTextCursor alpha = full.getText().createTextCursorByRange(full); @@ -299,41 +298,41 @@ public XTextCursor nrGetFillCursor(XTextDocument doc) String paddingy = "y"; String paddingz = "z"; beta.setString(paddingx + left + paddingy + right + paddingz); - LOGGER.debug("nrGetFillCursor: beta(2) covers '{}'", beta.getString()); + LOGGER.debug("getFillCursor: beta(2) covers '{}'", beta.getString()); // move beta to before the right bracket beta.collapseToEnd(); beta.goLeft((short) (rightLength + 1), false); // remove middle padding beta.goLeft((short) 1, true); - LOGGER.debug("nrGetFillCursor: beta(3) covers '{}'", beta.getString()); + LOGGER.debug("getFillCursor: beta(3) covers '{}'", beta.getString()); // only drop paddingy later: beta.setString(""); // drop the initial character and paddingx alpha.collapseToStart(); alpha.goRight((short) (1 + 1), true); - LOGGER.debug("nrGetFillCursor: alpha(4) covers '{}'", alpha.getString()); + LOGGER.debug("getFillCursor: alpha(4) covers '{}'", alpha.getString()); alpha.setString(""); // drop the last character and paddingz omega.collapseToEnd(); omega.goLeft((short) (1 + 1), true); - LOGGER.debug("nrGetFillCursor: omega(5) covers '{}'", omega.getString()); + LOGGER.debug("getFillCursor: omega(5) covers '{}'", omega.getString()); omega.setString(""); // drop paddingy now - LOGGER.debug("nrGetFillCursor: beta(6) covers '{}'", beta.getString()); + LOGGER.debug("getFillCursor: beta(6) covers '{}'", beta.getString()); beta.setString(""); // should be OK now. if (debugThisFun) { final short leftLength = (short) left.length(); alpha.goRight(leftLength, true); - LOGGER.debug("nrGetFillCursor: alpha(7) covers '{}', should be '{}'", alpha.getString(), left); + LOGGER.debug("getFillCursor: alpha(7) covers '{}', should be '{}'", alpha.getString(), left); omega.goLeft(rightLength, true); - LOGGER.debug("nrGetFillCursor: omega(8) covers '{}', should be '{}'", omega.getString(), right); + LOGGER.debug("getFillCursor: omega(8) covers '{}', should be '{}'", omega.getString(), right); } } @@ -384,13 +383,13 @@ public static void checkFillCursor(XTextCursor cursor) { * See: cleanFillCursorForCitationGroup */ @Override - public void nrCleanFillCursor(XTextDocument doc) + public void cleanFillCursor(XTextDocument doc) throws NoDocumentException, WrappedTargetException { // alwaysRemoveBrackets : full compatibility with JabRef 5.2: brackets are temporary, only - // exist between nrGetFillCursor and nrCleanFillCursor. + // exist between getFillCursor and cleanFillCursor. final boolean alwaysRemoveBrackets = false; // removeBracketsFromEmpty is intended to force removal if we are working on an "Empty citation" (INVISIBLE_CIT). @@ -401,25 +400,25 @@ public void nrCleanFillCursor(XTextDocument doc) final short leftLength = (short) left.length(); final short rightLength = (short) right.length(); - String name = this.nrGetRangeName(); + String name = this.getRangeName(); - XTextCursor full = this.nrGetRawCursor(doc).orElseThrow(IllegalStateException::new); + XTextCursor full = this.getRawCursor(doc).orElseThrow(IllegalStateException::new); final String fullText = full.getString(); final int fullTextLength = fullText.length(); if (!fullText.startsWith(left)) { - String msg = String.format("nrCleanFillCursor: (%s) does not start with REFERENCE_MARK_LEFT_BRACKET", name); + String msg = String.format("cleanFillCursor: (%s) does not start with REFERENCE_MARK_LEFT_BRACKET", name); throw new IllegalStateException(msg); } if (!fullText.endsWith(right)) { - String msg = String.format("nrCleanFillCursor: (%s) does not end with REFERENCE_MARK_RIGHT_BRACKET", name); + String msg = String.format("cleanFillCursor: (%s) does not end with REFERENCE_MARK_RIGHT_BRACKET", name); throw new IllegalStateException(msg); } final int contentLength = (fullTextLength - (leftLength + rightLength)); if (contentLength < 0) { - String msg = String.format("nrCleanFillCursor: length(%s) < 0", name); + String msg = String.format("cleanFillCursor: length(%s) < 0", name); throw new IllegalStateException(msg); } diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java index 967a8cf084d..58057c382e7 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java @@ -35,19 +35,14 @@ import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; import com.sun.star.text.XTextRange; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class OOFrontend { - private static final Logger LOGGER = LoggerFactory.getLogger(OOFrontend.class); + public final Backend52 backend; public final CitationGroups citationGroups; @@ -86,10 +81,9 @@ public Optional healthReport(XTextDocument doc) NoDocumentException { Map citationGroups = new HashMap<>(); - for (int i = 0; i < citationGroupNames.size(); i++) { - final String name = citationGroupNames.get(i); - CitationGroup cg = backend.readCitationGroupFromDocumentOrThrow(doc, name); - citationGroups.put(cg.cgid, cg); + for (String name : citationGroupNames) { + CitationGroup group = backend.readCitationGroupFromDocumentOrThrow(doc, name); + citationGroups.put(group.groupId, group); } return citationGroups; } @@ -117,11 +111,11 @@ public Optional healthReport(XTextDocument doc) WrappedTargetException { List> sortables = new ArrayList<>(); - for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { + for (CitationGroup group : citationGroups.getCitationGroupsUnordered()) { XTextRange range = (this - .getMarkRange(doc, cg) + .getMarkRange(doc, group) .orElseThrow(IllegalStateException::new)); - sortables.add(new RangeSortEntry<>(range, 0, cg)); + sortables.add(new RangeSortEntry<>(range, 0, group)); } /* @@ -150,9 +144,7 @@ public Optional healthReport(XTextDocument doc) for (List> partition : partitions.getPartitions()) { int indexInPartition = 0; - for (int i = 0; i < partition.size(); i++) { - RangeSortEntry sortable = partition.get(i); - XTextRange aRange = sortable.getRange(); + for (RangeSortEntry sortable : partition) { sortable.setIndexInPosition(indexInPartition++); if (mapFootnotesToFootnoteMarks) { Optional footnoteMarkRange = @@ -183,18 +175,15 @@ private List getVisuallySortedCitationGroups(XTextDocument doc, FunctionalTextViewCursor fcursor) throws WrappedTargetException, - NoDocumentException, - JabRefException { + NoDocumentException { List> sortables = createVisualSortInput(doc, mapFootnotesToFootnoteMarks); List> sorted = RangeSortVisual.visualSort(sortables, doc, fcursor); - List result = (sorted.stream() - .map(RangeSortable::getContent) - .collect(Collectors.toList())); - - return result; + return (sorted.stream() + .map(RangeSortable::getContent) + .collect(Collectors.toList())); } /** @@ -240,7 +229,6 @@ public CitationGroup createCitationGroup(XTextDocument doc, NoDocumentException, WrappedTargetException, NotRemoveableException, - PropertyExistException, PropertyVetoException, IllegalTypeException { @@ -248,44 +236,38 @@ public CitationGroup createCitationGroup(XTextDocument doc, if (pageInfos.size() != citationKeys.size()) { throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); } - CitationGroup cg = backend.createCitationGroup(doc, - citationKeys, - pageInfos, - citationType, - position, - insertSpaceAfter); - - this.citationGroups.afterCreateCitationGroup(cg); - return cg; + CitationGroup group = backend.createCitationGroup(doc, + citationKeys, + pageInfos, + citationType, + position, + insertSpaceAfter); + + this.citationGroups.afterCreateCitationGroup(group); + return group; } /** - * Remove {@code cg} both from the document and notify {@code citationGroups} + * Remove {@code group} both from the document and notify {@code citationGroups} */ - public void removeCitationGroup(CitationGroup cg, XTextDocument doc) + public void removeCitationGroup(CitationGroup group, XTextDocument doc) throws WrappedTargetException, NoDocumentException, - NoSuchElementException, - NotRemoveableException, - PropertyExistException, - IllegalTypeException { + NotRemoveableException { - backend.removeCitationGroup(cg, doc); - this.citationGroups.afterRemoveCitationGroup(cg); + backend.removeCitationGroup(group, doc); + this.citationGroups.afterRemoveCitationGroup(group); } public void removeCitationGroups(List cgs, XTextDocument doc) throws WrappedTargetException, NoDocumentException, - NoSuchElementException, - NotRemoveableException, - PropertyExistException, - IllegalTypeException { + NotRemoveableException { - for (CitationGroup cg : cgs) { - removeCitationGroup(cg, doc); + for (CitationGroup group : cgs) { + removeCitationGroup(group, doc); } } @@ -295,31 +277,30 @@ public void removeCitationGroups(List cgs, XTextDocument doc) * @return Optional.empty() if the reference mark is missing. * */ - public Optional getMarkRange(XTextDocument doc, CitationGroup cg) + public Optional getMarkRange(XTextDocument doc, CitationGroup group) throws NoDocumentException, WrappedTargetException { - return backend.getMarkRange(cg, doc); + return backend.getMarkRange(group, doc); } - public XTextCursor getFillCursorForCitationGroup(XTextDocument doc, CitationGroup cg) + public XTextCursor getFillCursorForCitationGroup(XTextDocument doc, CitationGroup group) throws NoDocumentException, WrappedTargetException, CreationException { - return backend.getFillCursorForCitationGroup(cg, doc); + return backend.getFillCursorForCitationGroup(group, doc); } /** * Remove brackets added by getFillCursorForCitationGroup. */ - public void cleanFillCursorForCitationGroup(XTextDocument doc, CitationGroup cg) + public void cleanFillCursorForCitationGroup(XTextDocument doc, CitationGroup group) throws NoDocumentException, - WrappedTargetException, - CreationException { + WrappedTargetException { - backend.cleanFillCursorForCitationGroup(cg, doc); + backend.cleanFillCursorForCitationGroup(group, doc); } /** @@ -335,11 +316,11 @@ public List> citationRanges(XTextDocument List> result = new ArrayList<>(citationGroups.numberOfCitationGroups()); - for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { - XTextRange range = this.getMarkRange(doc, cg).orElseThrow(IllegalStateException::new); - String description = cg.cgid.citationGroupIdAsString(); + for (CitationGroup group : citationGroups.getCitationGroupsUnordered()) { + XTextRange range = this.getMarkRange(doc, group).orElseThrow(IllegalStateException::new); + String description = group.groupId.citationGroupIdAsString(); result.add(new RangeForOverlapCheck<>(range, - cg.cgid, + group.groupId, RangeForOverlapCheck.REFERENCE_MARK_KIND, description)); } @@ -364,10 +345,7 @@ public List> bibliographyRanges(XTextDocum return result; } - public List> viewCursorRanges(XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException { + public List> viewCursorRanges(XTextDocument doc) { List> result = new ArrayList<>(); @@ -394,10 +372,7 @@ public List> viewCursorRanges(XTextDocumen * ranges. */ public List> - footnoteMarkRanges(XTextDocument doc, List> citationRanges) - throws - NoDocumentException, - WrappedTargetException { + footnoteMarkRanges(XTextDocument doc, List> citationRanges) { // We partition by XText and use a single range from // each partition to get at the corresponding footnotemark range. @@ -432,7 +407,7 @@ public List> viewCursorRanges(XTextDocumen static String rangeOverlapsToMessage(List>> overlaps) { - if (overlaps.size() == 0) { + if (overlaps.isEmpty()) { return "(*no overlaps*)"; } @@ -443,9 +418,9 @@ static String rangeOverlapsToMessage(List Localization.lang("Found identical ranges"); - case OVERLAP -> Localization.lang("Found overlapping ranges"); - case TOUCH -> Localization.lang("Found touching ranges"); + case EQUAL_RANGE -> Localization.lang("Found identical ranges"); + case OVERLAP -> Localization.lang("Found overlapping ranges"); + case TOUCH -> Localization.lang("Found touching ranges"); }); msg.append(": "); msg.append(listOfRanges); @@ -483,7 +458,7 @@ static String rangeOverlapsToMessage(List checkRangeOverlaps(XTextDocument doc, List>> overlaps = RangeOverlapWithin.findOverlappingRanges(doc, ranges, requireSeparation, reportAtMost); - if (overlaps.size() == 0) { + if (overlaps.isEmpty()) { return OOVoidResult.ok(); } return OOVoidResult.error(new JabRefException("Found overlapping or touching ranges", @@ -552,7 +527,6 @@ public OOVoidResult checkRangeOverlaps(XTextDocument doc, */ public List getCitationEntries(XTextDocument doc) throws - UnknownPropertyException, WrappedTargetException, NoDocumentException { return this.backend.getCitationEntries(doc, citationGroups); @@ -560,13 +534,9 @@ public List getCitationEntries(XTextDocument doc) public void applyCitationEntries(XTextDocument doc, List citationEntries) throws - UnknownPropertyException, - NotRemoveableException, - PropertyExistException, PropertyVetoException, IllegalTypeException, IllegalArgumentException, - NoDocumentException, WrappedTargetException { this.backend.applyCitationEntries(doc, citationEntries); } @@ -574,13 +544,12 @@ public void applyCitationEntries(XTextDocument doc, List citation public void imposeGlobalOrder(XTextDocument doc, FunctionalTextViewCursor fcursor) throws WrappedTargetException, - NoDocumentException, - JabRefException { + NoDocumentException { boolean mapFootnotesToFootnoteMarks = true; List sortedCitationGroups = getVisuallySortedCitationGroups(doc, mapFootnotesToFootnoteMarks, fcursor); - List sortedCitationGroupIds = OOListUtil.map(sortedCitationGroups, cg -> cg.cgid); + List sortedCitationGroupIds = OOListUtil.map(sortedCitationGroups, group -> group.groupId); citationGroups.setGlobalOrder(sortedCitationGroupIds); } } 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 2d0de320ca6..f7b3d14def6 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java @@ -12,9 +12,6 @@ import org.jabref.model.openoffice.uno.UnoBookmark; import org.jabref.model.openoffice.uno.UnoTextSection; -import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; @@ -28,12 +25,15 @@ public class UpdateBibliography { private static final String BIB_SECTION_NAME = "JR_bib"; private static final String BIB_SECTION_END_NAME = "JR_bib_end"; + private UpdateBibliography() { + /**/ + } + public static Optional getBibliographyRange(XTextDocument doc) throws NoDocumentException, WrappedTargetException { - Optional sectionRange = UnoTextSection.getAnchor(doc, BIB_SECTION_NAME); - return sectionRange; + return UnoTextSection.getAnchor(doc, BIB_SECTION_NAME); } /** @@ -45,11 +45,8 @@ public static void rebuildBibTextSection(XTextDocument doc, OOBibStyle style, boolean alwaysAddCitedOnPages) throws - NoSuchElementException, WrappedTargetException, CreationException, - PropertyVetoException, - UnknownPropertyException, NoDocumentException { clearBibTextSectionContent2(doc); @@ -116,9 +113,6 @@ private static void populateBibTextSection(XTextDocument doc, CreationException, IllegalArgumentException, NoDocumentException, - NoSuchElementException, - PropertyVetoException, - UnknownPropertyException, WrappedTargetException { XTextRange sectionRange = getBibliographyRange(doc).orElseThrow(IllegalStateException::new); @@ -134,7 +128,7 @@ private static void populateBibTextSection(XTextDocument doc, OOTextIntoOO.write(doc, cursor, bibliographyText); cursor.collapseToEnd(); - // remove the inital empty paragraph from the section. + // remove the initial empty paragraph from the section. sectionRange = getBibliographyRange(doc).orElseThrow(IllegalStateException::new); XTextCursor initialParagraph = doc.getText().createTextCursorByRange(sectionRange); initialParagraph.collapseToStart(); diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java index a3363938797..55f04775094 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java @@ -4,7 +4,6 @@ import java.util.Objects; import java.util.Optional; -import org.jabref.logic.JabRefException; import org.jabref.logic.openoffice.style.OOBibStyle; import org.jabref.model.openoffice.ootext.OOText; import org.jabref.model.openoffice.ootext.OOTextIntoOO; @@ -16,10 +15,7 @@ import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; -import com.sun.star.beans.PropertyExistException; import com.sun.star.beans.PropertyVetoException; -import com.sun.star.beans.UnknownPropertyException; -import com.sun.star.container.NoSuchElementException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextCursor; import com.sun.star.text.XTextDocument; @@ -33,6 +29,10 @@ public class UpdateCitationMarkers { private static final Logger LOGGER = LoggerFactory.getLogger(UpdateCitationMarkers.class); + private UpdateCitationMarkers() { + /**/ + } + /** * Visit each reference mark in referenceMarkNames, overwrite its * text content. @@ -48,33 +48,29 @@ public class UpdateCitationMarkers { public static void applyNewCitationMarkers(XTextDocument doc, OOFrontend fr, OOBibStyle style) throws NoDocumentException, - UnknownPropertyException, CreationException, - WrappedTargetException, - PropertyVetoException, - NoSuchElementException, - JabRefException { + WrappedTargetException { CitationGroups citationGroups = fr.citationGroups; - for (CitationGroup cg : citationGroups.getCitationGroupsUnordered()) { + for (CitationGroup group : citationGroups.getCitationGroupsUnordered()) { - boolean withText = (cg.citationType != CitationType.INVISIBLE_CIT); - Optional marker = cg.getCitationMarker(); + boolean withText = (group.citationType != CitationType.INVISIBLE_CIT); + Optional marker = group.getCitationMarker(); if (!marker.isPresent()) { LOGGER.warn("applyNewCitationMarkers: no marker for {}", - cg.cgid.citationGroupIdAsString()); + group.groupId.citationGroupIdAsString()); continue; } if (withText && marker.isPresent()) { - XTextCursor cursor = fr.getFillCursorForCitationGroup(doc, cg); + XTextCursor cursor = fr.getFillCursorForCitationGroup(doc, group); fillCitationMarkInCursor(doc, cursor, marker.get(), withText, style); - fr.cleanFillCursorForCitationGroup(doc, cg); + fr.cleanFillCursorForCitationGroup(doc, group); } } @@ -85,11 +81,8 @@ public static void fillCitationMarkInCursor(XTextDocument doc, OOText citationText, boolean withText, OOBibStyle style) - throws - UnknownPropertyException, - PropertyVetoException, + throws WrappedTargetException, - NoSuchElementException, CreationException, IllegalArgumentException { @@ -135,37 +128,33 @@ public static void createAndFillCitationGroup(OOFrontend fr, OOBibStyle style, boolean insertSpaceAfter) throws - UnknownPropertyException, NotRemoveableException, - PropertyExistException, - PropertyVetoException, WrappedTargetException, PropertyVetoException, IllegalArgumentException, CreationException, NoDocumentException, - IllegalTypeException, - NoSuchElementException { + IllegalTypeException { Objects.requireNonNull(pageInfos); if (pageInfos.size() != citationKeys.size()) { throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); } - CitationGroup cg = fr.createCitationGroup(doc, - citationKeys, - pageInfos, - citationType, - position, - insertSpaceAfter); + CitationGroup group = fr.createCitationGroup(doc, + citationKeys, + pageInfos, + citationType, + position, + insertSpaceAfter); final boolean withText = citationType.withText(); if (withText) { - XTextCursor c2 = fr.getFillCursorForCitationGroup(doc, cg); + XTextCursor fillCursor = fr.getFillCursorForCitationGroup(doc, group); - UpdateCitationMarkers.fillCitationMarkInCursor(doc, c2, citationText, withText, style); + UpdateCitationMarkers.fillCitationMarkInCursor(doc, fillCursor, citationText, withText, style); - fr.cleanFillCursorForCitationGroup(doc, cg); + fr.cleanFillCursorForCitationGroup(doc, group); } position.collapseToEnd(); } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java b/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java index 6c22c8abb09..4bc3fac6191 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java @@ -168,12 +168,12 @@ private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey ck) { List citationGroups = new ArrayList<>(); for (CitationPath p : ck.getCitationPaths()) { - CitationGroupId cgid = p.group; - Optional cg = cgs.getCitationGroup(cgid); - if (cg.isEmpty()) { + CitationGroupId groupId = p.group; + Optional group = cgs.getCitationGroup(groupId); + if (group.isEmpty()) { throw new IllegalStateException(); } - citationGroups.add(cg.get()); + citationGroups.add(group.get()); } // sort the citationGroups according to their indexInGlobalOrder @@ -184,11 +184,11 @@ private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey ck) { }); int i = 0; - for (CitationGroup cg : citationGroups) { + for (CitationGroup group : citationGroups) { if (i > 0) { sb.append(", "); } - String markName = cg.getReferenceMarkNameForLinking().orElseThrow(IllegalStateException::new); + String markName = group.getReferenceMarkNameForLinking().orElseThrow(IllegalStateException::new); OOText xref = OOFormat.formatReferenceToPageNumberOfReferenceMark(markName); sb.append(xref.toString()); i++; diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java index 896e747913f..1aaeb538930 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java @@ -64,6 +64,9 @@ private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroup String citationKey = citedKey.citationKey; List clashingKeys = normCitMarkerToClachingKeys.putIfAbsent(normCitMarker, new ArrayList<>(1)); + if (clashingKeys == null) { + clashingKeys = normCitMarkerToClachingKeys.get(normCitMarker); + } if (!clashingKeys.contains(citationKey)) { // First appearance of citationKey, add to list. clashingKeys.add(citationKey); @@ -107,8 +110,8 @@ private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroup */ private static void setIsFirstAppearanceOfSourceInCitations(CitationGroups cgs) { Set seenBefore = new HashSet<>(); - for (CitationGroup cg : cgs.getCitationGroupsInGlobalOrder()) { - for (Citation cit : cg.getCitationsInLocalOrder()) { + for (CitationGroup group : cgs.getCitationGroupsInGlobalOrder()) { + for (Citation cit : group.getCitationsInLocalOrder()) { String currentKey = cit.citationKey; if (!seenBefore.contains(currentKey)) { cit.setIsFirstAppearanceOfSource(true); @@ -142,17 +145,17 @@ static void produceCitationMarkers(CitationGroups cgs, OOBibStyle style) { // Mark first appearance of each citationKey setIsFirstAppearanceOfSourceInCitations(cgs); - for (CitationGroup cg : cgs.getCitationGroupsInGlobalOrder()) { + for (CitationGroup group : cgs.getCitationGroupsInGlobalOrder()) { - final boolean inParenthesis = (cg.citationType == CitationType.AUTHORYEAR_PAR); + final boolean inParenthesis = (group.citationType == CitationType.AUTHORYEAR_PAR); final NonUniqueCitationMarker strictlyUnique = NonUniqueCitationMarker.THROWS; - List cits = cg.getCitationsInLocalOrder(); + List cits = group.getCitationsInLocalOrder(); List citationMarkerEntries = OOListUtil.map(cits, e -> e); OOText citMarker = style.createCitationMarker(citationMarkerEntries, inParenthesis, strictlyUnique); - cg.setCitationMarker(Optional.of(citMarker)); + group.setCitationMarker(Optional.of(citMarker)); } } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java index 9789d6c6caa..5329d9ca021 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java @@ -24,12 +24,12 @@ static void produceCitationMarkers(CitationGroups cgs, OOBibStyle style) { cgs.createPlainBibliographySortedByComparator(OOProcess.AUTHOR_YEAR_TITLE_COMPARATOR); - for (CitationGroup cg : cgs.getCitationGroupsInGlobalOrder()) { + for (CitationGroup group : cgs.getCitationGroupsInGlobalOrder()) { String citMarker = style.getCitationGroupMarkupBefore() - + String.join(",", OOListUtil.map(cg.getCitationsInLocalOrder(), Citation::getCitationKey)) + + String.join(",", OOListUtil.map(group.getCitationsInLocalOrder(), Citation::getCitationKey)) + style.getCitationGroupMarkupAfter(); - cg.setCitationMarker(Optional.of(OOText.fromString(citMarker))); + group.setCitationMarker(Optional.of(OOText.fromString(citMarker))); } } } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java index 589ebfb7a48..deddab66cca 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java @@ -37,10 +37,10 @@ static void produceCitationMarkers(CitationGroups cgs, OOBibStyle style) { cgs.createNumberedBibliographySortedByComparator(OOProcess.AUTHOR_YEAR_TITLE_COMPARATOR); } - for (CitationGroup cg : cgs.getCitationGroupsInGlobalOrder()) { - List cits = OOListUtil.map(cg.getCitationsInLocalOrder(), e -> e); + for (CitationGroup group : cgs.getCitationGroupsInGlobalOrder()) { + List cits = OOListUtil.map(group.getCitationsInLocalOrder(), e -> e); OOText citMarker = style.getNumCitationMarker2(cits); - cg.setCitationMarker(Optional.of(citMarker)); + group.setCitationMarker(Optional.of(citMarker)); } } diff --git a/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java index aa09f36edef..63981ceba70 100644 --- a/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java +++ b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java @@ -10,23 +10,32 @@ import com.sun.star.text.XTextDocument; import com.sun.star.text.XTextRange; +/** + * NamedRange (with NamedRangeManager) attempts to provide a common interface for working with + * reference mark based and bookmark based text ranges to be used as locations to fill with citation + * markers. LibreOffice supports name-based lookup and listing names for both (hence the name). + * + * Note: currently only implemented for refence marks (in NamedRangeReferenceMark and + * NamedRangeManagerReferenceMark). + * + */ public interface NamedRange { - String nrGetRangeName(); + String getRangeName(); /** * @return Optional.empty if the mark is missing from the document. */ - Optional nrGetMarkRange(XTextDocument doc) + Optional getMarkRange(XTextDocument doc) throws NoDocumentException, WrappedTargetException; /** * Cursor for the reference marks as is, not prepared for filling, but does not need - * nrCleanFillCursor either. + * cleanFillCursor either. */ - Optional nrGetRawCursor(XTextDocument doc) + Optional getRawCursor(XTextDocument doc) throws NoDocumentException, WrappedTargetException; @@ -34,9 +43,9 @@ Optional nrGetRawCursor(XTextDocument doc) /** * Get a cursor for filling in text. * - * Must be followed by nrCleanFillCursor() + * Must be followed by cleanFillCursor() */ - XTextCursor nrGetFillCursor(XTextDocument doc) + XTextCursor getFillCursor(XTextDocument doc) throws NoDocumentException, WrappedTargetException, @@ -47,7 +56,7 @@ XTextCursor nrGetFillCursor(XTextDocument doc) * single character, leave the left bracket. * */ - void nrCleanFillCursor(XTextDocument doc) + void cleanFillCursor(XTextDocument doc) throws NoDocumentException, WrappedTargetException; @@ -55,7 +64,7 @@ void nrCleanFillCursor(XTextDocument doc) /** * Note: create is in NamedRangeManager */ - void nrRemoveFromDocument(XTextDocument doc) + void removeFromDocument(XTextDocument doc) throws WrappedTargetException, NoDocumentException; diff --git a/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java b/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java index 536871b5c34..9bbcc752350 100644 --- a/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java +++ b/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java @@ -12,19 +12,19 @@ public interface NamedRangeManager { - NamedRange nrmCreate(XTextDocument doc, - String markName, - XTextCursor position, - boolean insertSpaceAfter, - boolean withoutBrackets) + NamedRange createNamedRange(XTextDocument doc, + String markName, + XTextCursor position, + boolean insertSpaceAfter, + boolean withoutBrackets) throws CreationException; - List nrmGetUsedNames(XTextDocument doc) + List getUsedNames(XTextDocument doc) throws NoDocumentException; - Optional nrmGetFromDocument(XTextDocument doc, String markName) + Optional getNamedRangeFromDocument(XTextDocument doc, String markName) throws NoDocumentException, WrappedTargetException; diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java index 6e61faed147..909b088b5b3 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java @@ -189,135 +189,135 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) // Handle tags: switch (tagName) { - case "b": - formatStack.pushLayer(setCharWeight(FontWeight.BOLD)); - expectEnd.push("/" + tagName); - break; - case "i": - case "em": - formatStack.pushLayer(setCharPosture(FontSlant.ITALIC)); - expectEnd.push("/" + tagName); - break; - case "smallcaps": - formatStack.pushLayer(setCharCaseMap(CaseMap.SMALLCAPS)); - expectEnd.push("/" + tagName); - break; - case "sup": - formatStack.pushLayer(setSuperScript(formatStack)); - expectEnd.push("/" + tagName); - break; - case "sub": - formatStack.pushLayer(setSubScript(formatStack)); - expectEnd.push("/" + tagName); - break; - case "u": - formatStack.pushLayer(setCharUnderline(FontUnderline.SINGLE)); - expectEnd.push("/" + tagName); - break; - case "s": - formatStack.pushLayer(setCharStrikeout(FontStrikeout.SINGLE)); - expectEnd.push("/" + tagName); - break; - case "/p": - // nop - break; - case "p": - insertParagraphBreak(text, cursor); - cursor.collapseToEnd(); - for (OOPair pair : attributes) { - String key = pair.a; - String value = pair.b; - switch (key) { - case "oo:ParaStyleName": - //

- if (StringUtil.isNullOrEmpty(value)) { - LOGGER.debug(String.format("oo:ParaStyleName inherited")); - } else { - if (setParagraphStyle(cursor, value)) { - // Presumably tested already: - LOGGER.debug(String.format("oo:ParaStyleName=\"%s\" failed", value)); - } + case "b": + formatStack.pushLayer(setCharWeight(FontWeight.BOLD)); + expectEnd.push("/" + tagName); + break; + case "i": + case "em": + formatStack.pushLayer(setCharPosture(FontSlant.ITALIC)); + expectEnd.push("/" + tagName); + break; + case "smallcaps": + formatStack.pushLayer(setCharCaseMap(CaseMap.SMALLCAPS)); + expectEnd.push("/" + tagName); + break; + case "sup": + formatStack.pushLayer(setSuperScript(formatStack)); + expectEnd.push("/" + tagName); + break; + case "sub": + formatStack.pushLayer(setSubScript(formatStack)); + expectEnd.push("/" + tagName); + break; + case "u": + formatStack.pushLayer(setCharUnderline(FontUnderline.SINGLE)); + expectEnd.push("/" + tagName); + break; + case "s": + formatStack.pushLayer(setCharStrikeout(FontStrikeout.SINGLE)); + expectEnd.push("/" + tagName); + break; + case "/p": + // nop + break; + case "p": + insertParagraphBreak(text, cursor); + cursor.collapseToEnd(); + for (OOPair pair : attributes) { + String key = pair.a; + String value = pair.b; + switch (key) { + case "oo:ParaStyleName": + //

+ if (StringUtil.isNullOrEmpty(value)) { + LOGGER.debug(String.format("oo:ParaStyleName inherited")); + } else { + if (setParagraphStyle(cursor, value)) { + // Presumably tested already: + LOGGER.debug(String.format("oo:ParaStyleName=\"%s\" failed", value)); + } + } + break; + default: + LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); + break; } - break; - default: - LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); - break; } - } - break; - case "oo:referenceToPageNumberOfReferenceMark": - for (OOPair pair : attributes) { - String key = pair.a; - String value = pair.b; - switch (key) { - case "target": - UnoCrossRef.insertReferenceToPageNumberOfReferenceMark(doc, value, cursor); - break; - default: - LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); - break; + break; + case "oo:referenceToPageNumberOfReferenceMark": + for (OOPair pair : attributes) { + String key = pair.a; + String value = pair.b; + switch (key) { + case "target": + UnoCrossRef.insertReferenceToPageNumberOfReferenceMark(doc, value, cursor); + break; + default: + LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); + break; + } } - } - break; - case "tt": - // Note: "Example" names a character style in LibreOffice. - formatStack.pushLayer(setCharStyleName("Example")); - expectEnd.push("/" + tagName); - break; - case "span": - List> settings = new ArrayList<>(); - for (OOPair pair : attributes) { - String key = pair.a; - String value = pair.b; - switch (key) { - case "oo:CharStyleName": - // - settings.addAll(setCharStyleName(value)); - break; - case "lang": - // - // - settings.addAll(setCharLocale(value)); - break; - case "style": - // HTML-style small-caps - if ("font-variant: small-caps".equals(value)) { - settings.addAll(setCharCaseMap(CaseMap.SMALLCAPS)); - break; + break; + case "tt": + // Note: "Example" names a character style in LibreOffice. + formatStack.pushLayer(setCharStyleName("Example")); + expectEnd.push("/" + tagName); + break; + case "span": + List> settings = new ArrayList<>(); + for (OOPair pair : attributes) { + String key = pair.a; + String value = pair.b; + switch (key) { + case "oo:CharStyleName": + // + settings.addAll(setCharStyleName(value)); + break; + case "lang": + // + // + settings.addAll(setCharLocale(value)); + break; + case "style": + // HTML-style small-caps + if ("font-variant: small-caps".equals(value)) { + settings.addAll(setCharCaseMap(CaseMap.SMALLCAPS)); + break; + } + LOGGER.warn(String.format("Unexpected value %s for attribute '%s' for <%s>", + value, key, tagName)); + break; + default: + LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); + break; } - LOGGER.warn(String.format("Unexpected value %s for attribute '%s' for <%s>", - value, key, tagName)); - break; - default: - LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); - break; } - } - formatStack.pushLayer(settings); - expectEnd.push("/" + tagName); - break; - case "/b": - case "/i": - case "/em": - case "/tt": - case "/smallcaps": - case "/sup": - case "/sub": - case "/u": - case "/s": - case "/span": - formatStack.popLayer(); - String expected = expectEnd.pop(); - if (!tagName.equals(expected)) { - LOGGER.warn(String.format("expected '<%s>', found '<%s>' after '%s'", - expected, - tagName, - currentSubstring)); - } - break; - default: - LOGGER.warn(String.format("ignoring unknown tag '<%s>'", tagName)); - break; + formatStack.pushLayer(settings); + expectEnd.push("/" + tagName); + break; + case "/b": + case "/i": + case "/em": + case "/tt": + case "/smallcaps": + case "/sup": + case "/sub": + case "/u": + case "/s": + case "/span": + formatStack.popLayer(); + String expected = expectEnd.pop(); + if (!tagName.equals(expected)) { + LOGGER.warn(String.format("expected '<%s>', found '<%s>' after '%s'", + expected, + tagName, + currentSubstring)); + } + break; + default: + LOGGER.warn(String.format("ignoring unknown tag '<%s>'", tagName)); + break; } piv = tagMatcher.end(); diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java index 3b9021eb73f..90afb872d4f 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java @@ -19,7 +19,7 @@ public class CitationGroup { /* * Identifies this citation group. */ - public final CitationGroupId cgid; + public final CitationGroupId groupId; /* * The core data, stored in the document: @@ -60,12 +60,12 @@ public class CitationGroup { private Optional citationMarker; public CitationGroup(OODataModel dataModel, - CitationGroupId cgid, + CitationGroupId groupId, CitationType citationType, List citationsInStorageOrder, Optional referenceMarkNameForLinking) { this.dataModel = dataModel; - this.cgid = cgid; + this.groupId = groupId; this.citationType = citationType; this.citationsInStorageOrder = Collections.unmodifiableList(citationsInStorageOrder); this.localOrder = OOListUtil.makeIndices(citationsInStorageOrder.size()); diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java index 0bfe4a832d0..b03028b76ef 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java @@ -62,12 +62,12 @@ public void distributeToCitations(List where, T value) { for (CitationPath p : where) { - CitationGroup cg = citationGroupsUnordered.get(p.group); - if (cg == null) { + CitationGroup group = citationGroupsUnordered.get(p.group); + if (group == null) { LOGGER.warn("CitationGroups.distributeToCitations: group missing"); continue; } - Citation cit = cg.citationsInStorageOrder.get(p.storageIndexInGroup); + Citation cit = group.citationsInStorageOrder.get(p.storageIndexInGroup); fun.accept(new OOPair<>(cit, value)); } } @@ -96,8 +96,8 @@ public void lookupCitations(List databases) { // right thing. Seems to work. But what we gained from avoiding collect-and-distribute // may be lost in more complicated consistency checking in addPath. // - /// for (CitationGroup cg : getCitationGroupsUnordered()) { - /// for (Citation cit : cg.citationsInStorageOrder) { + /// for (CitationGroup group : getCitationGroupsUnordered()) { + /// for (Citation cit : group.citationsInStorageOrder) { /// cit.lookupInDatabases(databases); /// } /// } @@ -114,7 +114,7 @@ public List getCitationGroupsInGlobalOrder() { if (globalOrder.isEmpty()) { throw new IllegalStateException("getCitationGroupsInGlobalOrder: not ordered yet"); } - return OOListUtil.map(globalOrder.get(), cgid -> citationGroupsUnordered.get(cgid)); + return OOListUtil.map(globalOrder.get(), groupId -> citationGroupsUnordered.get(groupId)); } /** @@ -132,8 +132,8 @@ public void setGlobalOrder(List globalOrder) { // Propagate to each CitationGroup int i = 0; - for (CitationGroupId cgid : globalOrder) { - citationGroupsUnordered.get(cgid).setIndexInGlobalOrder(Optional.of(i)); + for (CitationGroupId groupId : globalOrder) { + citationGroupsUnordered.get(groupId).setIndexInGlobalOrder(Optional.of(i)); i++; } } @@ -146,8 +146,8 @@ public boolean hasGlobalOrder() { * Impose an order for citations within each group. */ public void imposeLocalOrder(Comparator entryComparator) { - for (CitationGroup cg : citationGroupsUnordered.values()) { - cg.imposeLocalOrder(entryComparator); + for (CitationGroup group : citationGroupsUnordered.values()) { + group.imposeLocalOrder(entryComparator); } } @@ -157,11 +157,11 @@ public void imposeLocalOrder(Comparator entryComparator) { */ public CitedKeys getCitedKeysUnordered() { LinkedHashMap res = new LinkedHashMap<>(); - for (CitationGroup cg : citationGroupsUnordered.values()) { + for (CitationGroup group : citationGroupsUnordered.values()) { int storageIndexInGroup = 0; - for (Citation cit : cg.citationsInStorageOrder) { + for (Citation cit : group.citationsInStorageOrder) { String key = cit.citationKey; - CitationPath path = new CitationPath(cg.cgid, storageIndexInGroup); + CitationPath path = new CitationPath(group.groupId, storageIndexInGroup); if (res.containsKey(key)) { res.get(key).addPath(path, cit); } else { @@ -181,11 +181,11 @@ public CitedKeys getCitedKeysSortedInOrderOfAppearance() { throw new IllegalStateException("getSortedCitedKeys: no globalOrder"); } LinkedHashMap res = new LinkedHashMap<>(); - for (CitationGroup cg : getCitationGroupsInGlobalOrder()) { - for (int i : cg.getLocalOrder()) { - Citation cit = cg.citationsInStorageOrder.get(i); + for (CitationGroup group : getCitationGroupsInGlobalOrder()) { + for (int i : group.getLocalOrder()) { + Citation cit = group.citationsInStorageOrder.get(i); String citationKey = cit.citationKey; - CitationPath path = new CitationPath(cg.cgid, i); + CitationPath path = new CitationPath(group.groupId, i); if (res.containsKey(citationKey)) { res.get(citationKey).addPath(path, cit); } else { @@ -257,17 +257,17 @@ public void createNumberedBibliographySortedByComparator(Comparator en * Query by CitationGroupId */ - public Optional getCitationGroup(CitationGroupId cgid) { - CitationGroup cg = citationGroupsUnordered.get(cgid); - return Optional.ofNullable(cg); + public Optional getCitationGroup(CitationGroupId groupId) { + CitationGroup group = citationGroupsUnordered.get(groupId); + return Optional.ofNullable(group); } /* * @return true if all citation groups have referenceMarkNameForLinking */ public boolean citationGroupsProvideReferenceMarkNameForLinking() { - for (CitationGroup cg : citationGroupsUnordered.values()) { - if (cg.getReferenceMarkNameForLinking().isEmpty()) { + for (CitationGroup group : citationGroupsUnordered.values()) { + if (group.getReferenceMarkNameForLinking().isEmpty()) { return false; } } @@ -278,16 +278,16 @@ public boolean citationGroupsProvideReferenceMarkNameForLinking() { * Callbacks. */ - public void afterCreateCitationGroup(CitationGroup cg) { - citationGroupsUnordered.put(cg.cgid, cg); + public void afterCreateCitationGroup(CitationGroup group) { + citationGroupsUnordered.put(group.groupId, group); globalOrder = Optional.empty(); bibliography = Optional.empty(); } - public void afterRemoveCitationGroup(CitationGroup cg) { - citationGroupsUnordered.remove(cg.cgid); - globalOrder.map(l -> l.remove(cg.cgid)); + public void afterRemoveCitationGroup(CitationGroup group) { + citationGroupsUnordered.remove(group.groupId); + globalOrder.map(l -> l.remove(group.groupId)); bibliography = Optional.empty(); } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationType.java b/src/main/java/org/jabref/model/openoffice/style/CitationType.java index 14189e903e3..567996ec56e 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationType.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationType.java @@ -11,8 +11,8 @@ public enum CitationType { public boolean inParenthesis() { return switch (this) { - case AUTHORYEAR_PAR, INVISIBLE_CIT -> true; - case AUTHORYEAR_INTEXT -> false; + case AUTHORYEAR_PAR, INVISIBLE_CIT -> true; + case AUTHORYEAR_INTEXT -> false; }; } From ec253d0a3c66c543f9af3b097f0442d20b1f7d9b Mon Sep 17 00:00:00 2001 From: Antal K Date: Mon, 23 Aug 2021 10:53:29 +0200 Subject: [PATCH 094/103] longer name --- .../org/jabref/gui/openoffice/ConnectionLostException.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/openoffice/ConnectionLostException.java b/src/main/java/org/jabref/gui/openoffice/ConnectionLostException.java index 36fc16e5e3f..df0264be0de 100644 --- a/src/main/java/org/jabref/gui/openoffice/ConnectionLostException.java +++ b/src/main/java/org/jabref/gui/openoffice/ConnectionLostException.java @@ -5,7 +5,7 @@ */ class ConnectionLostException extends RuntimeException { - public ConnectionLostException(String s) { - super(s); + public ConnectionLostException(String msg) { + super(msg); } } From 1f6700c3649f7b84ba9a9b780061ebc6c2da6090 Mon Sep 17 00:00:00 2001 From: Antal K Date: Mon, 23 Aug 2021 16:48:55 +0200 Subject: [PATCH 095/103] follow some PMD suggestions --- .../org/jabref/gui/openoffice/OOBibBase2.java | 57 ++++--- .../org/jabref/gui/openoffice/OOError.java | 24 +-- .../org/jabref/logic/openoffice/OOUtil.java | 15 +- .../logic/openoffice/action/EditInsert.java | 4 +- .../logic/openoffice/action/EditMerge.java | 20 +-- .../logic/openoffice/action/EditSeparate.java | 14 +- .../logic/openoffice/action/ExportCited.java | 4 +- .../openoffice/action/ManageCitations.java | 8 +- .../logic/openoffice/action/Update.java | 22 +-- .../logic/openoffice/backend/Backend52.java | 22 +-- .../logic/openoffice/backend/Codec52.java | 26 ++-- .../backend/NamedRangeReferenceMark.java | 27 ++-- .../frontend/UpdateBibliography.java | 8 +- .../frontend/UpdateCitationMarkers.java | 28 ++-- .../logic/openoffice/style/OOBibStyle.java | 140 +++++++++--------- .../style/OOBibStyleGetCitationMarker.java | 90 +++++------ .../style/OOBibStyleGetNumCitationMarker.java | 62 ++++---- .../style/OOFormatBibliography.java | 58 ++++---- .../style/OOProcessAuthorYearMarkers.java | 4 +- .../model/openoffice/CitationEntry.java | 8 +- .../openoffice/style/CitationGroupId.java | 8 +- .../openoffice/style/CitationGroups.java | 5 +- .../model/openoffice/style/CitedKeys.java | 6 +- .../model/openoffice/style/PageInfo.java | 2 +- .../model/openoffice/uno/UnoCursor.java | 4 +- .../jabref/model/openoffice/uno/UnoStyle.java | 4 +- .../jabref/model/openoffice/uno/UnoUndo.java | 12 +- .../uno/UnoUserDefinedProperty.java | 4 +- .../model/openoffice/util/OOListUtil.java | 16 +- 29 files changed, 346 insertions(+), 356 deletions(-) diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java index 9832adb991d..d8523f0cd77 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java @@ -151,12 +151,12 @@ public Optional getCurrentDocumentTitle() { * * ******************************************************/ - void showDialog(OOError ex) { - ex.showErrorDialog(dialogService); + void showDialog(OOError err) { + err.showErrorDialog(dialogService); } - void showDialog(String title, OOError ex) { - ex.setTitle(title).showErrorDialog(dialogService); + void showDialog(String title, OOError err) { + err.setTitle(title).showErrorDialog(dialogService); } OOVoidResult collectResults(String title, List> results) { @@ -185,8 +185,8 @@ boolean testDialog(String title, List> results) { @SafeVarargs final boolean testDialog(String title, OOVoidResult... results) { - List> rs = Arrays.asList(results); - return testDialog(collectResults(title, rs)); + List> resultList = Arrays.asList(results); + return testDialog(collectResults(title, resultList)); } /* @@ -232,16 +232,16 @@ OOResult getFunctionalTextViewCursor(XTextDoc return result.mapError(detail -> new OOError(title, messageOnFailureToObtain)); } - private static OOVoidResult checkRangeOverlaps(XTextDocument doc, OOFrontend fr) { + private static OOVoidResult checkRangeOverlaps(XTextDocument doc, OOFrontend frontend) { final String title = "checkRangeOverlaps"; boolean requireSeparation = false; int maxReportedOverlaps = 10; try { - return (fr.checkRangeOverlaps(doc, - new ArrayList<>(), - requireSeparation, - maxReportedOverlaps) - .mapError(OOError::from)); + return (frontend.checkRangeOverlaps(doc, + new ArrayList<>(), + requireSeparation, + maxReportedOverlaps) + .mapError(OOError::from)); } catch (NoDocumentException ex) { return OOVoidResult.error(OOError.from(ex).setTitle(title)); } catch (WrappedTargetException ex) { @@ -249,18 +249,18 @@ private static OOVoidResult checkRangeOverlaps(XTextDocument doc, OOFro } } - private static OOVoidResult checkRangeOverlapsWithCursor(XTextDocument doc, OOFrontend fr) { + private static OOVoidResult checkRangeOverlapsWithCursor(XTextDocument doc, OOFrontend frontend) { final String title = "checkRangeOverlapsWithCursor"; List> userRanges; - userRanges = fr.viewCursorRanges(doc); + userRanges = frontend.viewCursorRanges(doc); boolean requireSeparation = false; OOVoidResult res; try { - res = fr.checkRangeOverlapsWithCursor(doc, - userRanges, - requireSeparation); + res = frontend.checkRangeOverlapsWithCursor(doc, + userRanges, + requireSeparation); } catch (NoDocumentException ex) { return OOVoidResult.error(OOError.from(ex).setTitle(title)); } catch (WrappedTargetException ex) { @@ -588,18 +588,17 @@ public void guiActionInsertEntry(List entries, } XTextDocument doc = odoc.get(); - OOResult ofr = getFrontend(doc); - if (testDialog(title, ofr.asVoidResult())) { + OOResult frontend = getFrontend(doc); + if (testDialog(title, frontend.asVoidResult())) { return; } - OOFrontend fr = ofr.get(); OOResult cursor = getUserCursorForTextInsertion(doc, title); if (testDialog(title, cursor.asVoidResult())) { return; } - if (testDialog(title, checkRangeOverlapsWithCursor(doc, fr))) { + if (testDialog(title, checkRangeOverlapsWithCursor(doc, frontend.get()))) { return; } @@ -635,7 +634,7 @@ public void guiActionInsertEntry(List entries, UnoUndo.enterUndoContext(doc, "Insert citation"); EditInsert.insertCitationGroup(doc, - fr, + frontend.get(), cursor.get(), entries, database, @@ -695,8 +694,8 @@ public void guiActionMergeCitationGroups(List databases, OOBibStyle try { UnoUndo.enterUndoContext(doc, "Merge citations"); - OOFrontend fr = new OOFrontend(doc); - boolean madeModifications = EditMerge.mergeCitationGroups(doc, fr, style); + OOFrontend frontend = new OOFrontend(doc); + boolean madeModifications = EditMerge.mergeCitationGroups(doc, frontend, style); if (madeModifications) { UnoCrossRef.refresh(doc); Update.SyncOptions syncOptions = new Update.SyncOptions(databases); @@ -752,8 +751,8 @@ public void guiActionSeparateCitations(List databases, OOBibStyle s try { UnoUndo.enterUndoContext(doc, "Separate citations"); - OOFrontend fr = new OOFrontend(doc); - boolean madeModifications = EditSeparate.separateCitations(doc, fr, databases, style); + OOFrontend frontend = new OOFrontend(doc); + boolean madeModifications = EditSeparate.separateCitations(doc, frontend, databases, style); if (madeModifications) { UnoCrossRef.refresh(doc); Update.SyncOptions syncOptions = new Update.SyncOptions(databases); @@ -881,8 +880,8 @@ public void guiActionUpdateDocument(List databases, OOBibStyle styl return; } - OOFrontend fr = new OOFrontend(doc); - if (testDialog(title, checkRangeOverlaps(doc, fr))) { + OOFrontend frontend = new OOFrontend(doc); + if (testDialog(title, checkRangeOverlaps(doc, frontend))) { return; } @@ -895,7 +894,7 @@ public void guiActionUpdateDocument(List databases, OOBibStyle styl .setUpdateBibliography(true) .setAlwaysAddCitedOnPages(this.alwaysAddCitedOnPages); - unresolvedKeys = Update.synchronizeDocument(doc, fr, style, fcursor.get(), syncOptions); + unresolvedKeys = Update.synchronizeDocument(doc, frontend, style, fcursor.get(), syncOptions); } finally { UnoUndo.leaveUndoContext(doc); diff --git a/src/main/java/org/jabref/gui/openoffice/OOError.java b/src/main/java/org/jabref/gui/openoffice/OOError.java index 44e70b3e975..b296ffe30c0 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOError.java +++ b/src/main/java/org/jabref/gui/openoffice/OOError.java @@ -39,50 +39,50 @@ public void showErrorDialog(DialogService dialogService) { * Conversions from exception caught */ - public static OOError from(JabRefException ex) { + public static OOError from(JabRefException err) { return new OOError( Localization.lang("JabRefException"), - ex.getLocalizedMessage(), - ex); + err.getLocalizedMessage(), + err); } // For DisposedException - public static OOError from(DisposedException ex) { + public static OOError from(DisposedException err) { return new OOError( Localization.lang("Connection lost"), Localization.lang("Connection to OpenOffice/LibreOffice has been lost." + " Please make sure OpenOffice/LibreOffice is running," + " and try to reconnect."), - ex); + err); } // For NoDocumentException - public static OOError from(NoDocumentException ex) { + public static OOError from(NoDocumentException err) { return new OOError( Localization.lang("Not connected to document"), Localization.lang("Not connected to any Writer document." + " Please make sure a document is open," + " and use the 'Select Writer document' button" + " to connect to it."), - ex); + err); } // For NoDocumentFoundException - public static OOError from(NoDocumentFoundException ex) { + public static OOError from(NoDocumentFoundException err) { return new OOError( Localization.lang("No Writer documents found"), Localization.lang("Could not connect to any Writer document." + " Please make sure a document is open" + " before using the 'Select Writer document' button" + " to connect to it."), - ex); + err); } - public static OOError fromMisc(Exception ex) { + public static OOError fromMisc(Exception err) { return new OOError( "Exception", - ex.getMessage(), - ex); + err.getMessage(), + err); } /* diff --git a/src/main/java/org/jabref/logic/openoffice/OOUtil.java b/src/main/java/org/jabref/logic/openoffice/OOUtil.java index 9efab82773c..a5976cb3342 100644 --- a/src/main/java/org/jabref/logic/openoffice/OOUtil.java +++ b/src/main/java/org/jabref/logic/openoffice/OOUtil.java @@ -127,13 +127,13 @@ public static void insertOOFormattedTextAtCurrentLocation(XText text, XTextCurso List formatting = new ArrayList<>(); // We need to extract formatting. Use a simple regexp search iteration: int piv = 0; - Matcher m = OOUtil.HTML_TAG.matcher(lText); - while (m.find()) { - String currentSubstring = lText.substring(piv, m.start()); + Matcher matcher = OOUtil.HTML_TAG.matcher(lText); + while (matcher.find()) { + String currentSubstring = lText.substring(piv, matcher.start()); if (!currentSubstring.isEmpty()) { OOUtil.insertTextAtCurrentLocation(text, cursor, currentSubstring, formatting); } - String tag = m.group(); + String tag = matcher.group(); // Handle tags: if ("".equals(tag)) { formatting.add(Formatting.BOLD); @@ -169,7 +169,7 @@ public static void insertOOFormattedTextAtCurrentLocation(XText text, XTextCurso formatting.remove(Formatting.STRIKEOUT); } - piv = m.end(); + piv = matcher.end(); } if (piv < lText.length()) { @@ -276,10 +276,9 @@ public static void insertTextAtCurrentLocation(XText text, XTextCursor cursor, S cursor.collapseToEnd(); } - public static Object getProperty(Object o, String property) + public static Object getProperty(Object object, String property) throws UnknownPropertyException, WrappedTargetException { - XPropertySet props = UnoRuntime.queryInterface( - XPropertySet.class, o); + XPropertySet props = UnoRuntime.queryInterface(XPropertySet.class, object); return props.getPropertyValue(property); } } diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java index 81491bd8590..375d3c1637a 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java @@ -56,7 +56,7 @@ private static String insertEntryGetCitationKey(BibEntry entry) { * @param pageInfo A single pageInfo for a list of entries. This is what we get from the GUI. */ public static void insertCitationGroup(XTextDocument doc, - OOFrontend fr, + OOFrontend frontend, XTextCursor cursor, List entries, BibDatabase database, @@ -98,7 +98,7 @@ public static void insertCitationGroup(XTextDocument doc, try { UnoScreenRefresh.lockControllers(doc); - UpdateCitationMarkers.createAndFillCitationGroup(fr, + UpdateCitationMarkers.createAndFillCitationGroup(frontend, doc, citationKeys, pageInfos, diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java index 43bdcd59e2d..6fa19e2d344 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java @@ -40,7 +40,7 @@ private EditMerge() { /* * @return true if modified document */ - public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend fr, OOBibStyle style) + public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend frontend, OOBibStyle style) throws CreationException, IllegalArgumentException, @@ -50,12 +50,12 @@ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend fr, OOBi PropertyVetoException, WrappedTargetException { - boolean madeModifications = false; + boolean madeModifications; try { UnoScreenRefresh.lockControllers(doc); - List joinableGroups = EditMerge.scan(doc, fr); + List joinableGroups = EditMerge.scan(doc, frontend); for (JoinableGroupData joinableGroupData : joinableGroups) { @@ -66,9 +66,9 @@ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend fr, OOBi .collect(Collectors.toList())); CitationType citationType = cgs.get(0).citationType; - List> pageInfos = fr.backend.combinePageInfos(cgs); + List> pageInfos = frontend.backend.combinePageInfos(cgs); - fr.removeCitationGroups(cgs, doc); + frontend.removeCitationGroups(cgs, doc); XTextCursor textCursor = joinableGroupData.groupCursor; textCursor.setString(""); // Also remove the spaces between. @@ -76,7 +76,7 @@ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend fr, OOBi /* insertSpaceAfter: no, it is already there (or could be) */ boolean insertSpaceAfter = false; - UpdateCitationMarkers.createAndFillCitationGroup(fr, + UpdateCitationMarkers.createAndFillCitationGroup(frontend, doc, citationKeys, pageInfos, @@ -226,7 +226,7 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup group, XTe couldExpand = thisCharCursor.goRight((short) 1, true); String thisChar = thisCharCursor.getString(); thisCharCursor.collapseToEnd(); - if (thisChar.isEmpty() || thisChar.equals("\n") || !thisChar.trim().isEmpty()) { + if (thisChar.isEmpty() || "\n".equals(thisChar) || !thisChar.trim().isEmpty()) { couldExpand = false; if (!thisChar.isEmpty()) { thisCharCursor.goLeft((short) 1, false); @@ -290,13 +290,13 @@ private static void addToCurrentGroup(ScanState state, CitationGroup group, XTex /** * Scan the document for joinable groups. Return those found. */ - private static List scan(XTextDocument doc, OOFrontend fr) + private static List scan(XTextDocument doc, OOFrontend frontend) throws NoDocumentException, WrappedTargetException { List result = new ArrayList<>(); - List cgs = fr.getCitationGroupsSortedWithinPartitions(doc, false /* mapFootnotesToFootnoteMarks */); + List cgs = frontend.getCitationGroupsSortedWithinPartitions(doc, false /* mapFootnotesToFootnoteMarks */); if (cgs.isEmpty()) { return result; } @@ -305,7 +305,7 @@ private static List scan(XTextDocument doc, OOFrontend fr) for (CitationGroup group : cgs) { - XTextRange currentRange = (fr.getMarkRange(doc, group) + XTextRange currentRange = (frontend.getMarkRange(doc, group) .orElseThrow(IllegalStateException::new)); /* diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java index fba50a93c6e..409969b213f 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java @@ -29,7 +29,7 @@ private EditSeparate() { } public static boolean separateCitations(XTextDocument doc, - OOFrontend fr, + OOFrontend frontend, List databases, OOBibStyle style) throws @@ -47,17 +47,17 @@ public static boolean separateCitations(XTextDocument doc, // decide the visually last Citation in the group. Unless the // style changed since refresh this is the last on the screen // as well. - fr.citationGroups.lookupCitations(databases); - fr.citationGroups.imposeLocalOrder(OOProcess.comparatorForMulticite(style)); + frontend.citationGroups.lookupCitations(databases); + frontend.citationGroups.imposeLocalOrder(OOProcess.comparatorForMulticite(style)); - List cgs = fr.citationGroups.getCitationGroupsUnordered(); + List cgs = frontend.citationGroups.getCitationGroupsUnordered(); try { UnoScreenRefresh.lockControllers(doc); for (CitationGroup group : cgs) { - XTextRange range1 = (fr + XTextRange range1 = (frontend .getMarkRange(doc, group) .orElseThrow(IllegalStateException::new)); XTextCursor textCursor = range1.getText().createTextCursorByRange(range1); @@ -67,7 +67,7 @@ public static boolean separateCitations(XTextDocument doc, continue; } - fr.removeCitationGroup(group, doc); + frontend.removeCitationGroup(group, doc); // Now we own the content of cits // Create a citation group for each citation. @@ -76,7 +76,7 @@ public static boolean separateCitations(XTextDocument doc, boolean insertSpaceAfter = (i != last); Citation cit = cits.get(i); - UpdateCitationMarkers.createAndFillCitationGroup(fr, + UpdateCitationMarkers.createAndFillCitationGroup(frontend, doc, List.of(cit.citationKey), List.of(cit.getPageInfo()), diff --git a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java index 26ed654de21..ba806426051 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java +++ b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java @@ -51,8 +51,8 @@ public static GenerateDatabaseResult generateDatabase(XTextDocument doc, List unresolvedKeys = new ArrayList<>(); diff --git a/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java b/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java index 9782261f612..c8234df9ca0 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java +++ b/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java @@ -21,8 +21,8 @@ public static List getCitationEntries(XTextDocument doc) throws NoDocumentException, WrappedTargetException { - OOFrontend fr = new OOFrontend(doc); - return fr.getCitationEntries(doc); + OOFrontend frontend = new OOFrontend(doc); + return frontend.getCitationEntries(doc); } public static void applyCitationEntries(XTextDocument doc, List citationEntries) @@ -32,7 +32,7 @@ public static void applyCitationEntries(XTextDocument doc, List c IllegalTypeException, WrappedTargetException, IllegalArgumentException { - OOFrontend fr = new OOFrontend(doc); - fr.applyCitationEntries(doc, citationEntries); + OOFrontend frontend = new OOFrontend(doc); + frontend.applyCitationEntries(doc, citationEntries); } } diff --git a/src/main/java/org/jabref/logic/openoffice/action/Update.java b/src/main/java/org/jabref/logic/openoffice/action/Update.java index 49f79d6d2e7..ba840e88b70 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/Update.java +++ b/src/main/java/org/jabref/logic/openoffice/action/Update.java @@ -29,7 +29,7 @@ private Update() { * @return the list of unresolved citation keys */ private static List updateDocument(XTextDocument doc, - OOFrontend fr, + OOFrontend frontend, List databases, OOBibStyle style, FunctionalTextViewCursor fcursor, @@ -43,25 +43,25 @@ private static List updateDocument(XTextDocument doc, final boolean useLockControllers = true; - fr.imposeGlobalOrder(doc, fcursor); - OOProcess.produceCitationMarkers(fr.citationGroups, databases, style); + frontend.imposeGlobalOrder(doc, fcursor); + OOProcess.produceCitationMarkers(frontend.citationGroups, databases, style); try { if (useLockControllers) { UnoScreenRefresh.lockControllers(doc); } - UpdateCitationMarkers.applyNewCitationMarkers(doc, fr, style); + UpdateCitationMarkers.applyNewCitationMarkers(doc, frontend, style); if (doUpdateBibliography) { UpdateBibliography.rebuildBibTextSection(doc, - fr, - fr.citationGroups.getBibliography().get(), + frontend, + frontend.citationGroups.getBibliography().get(), style, alwaysAddCitedOnPages); } - return fr.citationGroups.getUnresolvedKeys(); + return frontend.citationGroups.getUnresolvedKeys(); } finally { if (useLockControllers && UnoScreenRefresh.hasControllersLocked(doc)) { UnoScreenRefresh.unlockControllers(doc); @@ -93,7 +93,7 @@ public SyncOptions setAlwaysAddCitedOnPages(boolean value) { } public static List synchronizeDocument(XTextDocument doc, - OOFrontend fr, + OOFrontend frontend, OOBibStyle style, FunctionalTextViewCursor fcursor, SyncOptions syncOptions) @@ -104,7 +104,7 @@ public static List synchronizeDocument(XTextDocument doc, com.sun.star.lang.IllegalArgumentException { return Update.updateDocument(doc, - fr, + frontend, syncOptions.databases, style, fcursor, @@ -125,9 +125,9 @@ public static List resyncDocument(XTextDocument doc, WrappedTargetException, com.sun.star.lang.IllegalArgumentException { - OOFrontend fr = new OOFrontend(doc); + OOFrontend frontend = new OOFrontend(doc); - return Update.synchronizeDocument(doc, fr, style, fcursor, syncOptions); + return Update.synchronizeDocument(doc, frontend, style, fcursor, syncOptions); } } diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java index 0016e5e4510..4a0d8d05e0e 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java @@ -196,17 +196,6 @@ public CitationGroup createCitationGroup(XTextDocument doc, throw new IllegalArgumentException(); } - /* - * Backend52 uses reference marks to (1) mark the location of the citation in the text and (2) to encode - * the citation keys and citation type in the name of the reference mark. The name of the reference mark - * has to be unique in the document. - */ - String markName = Codec52.getUniqueMarkName(new HashSet<>(citationStorageManager.getUsedNames(doc)), - citationKeys, - citationType); - - CitationGroupId groupId = new CitationGroupId(markName); - final int numberOfCitations = citationKeys.size(); final int last = numberOfCitations - 1; @@ -236,6 +225,17 @@ public CitationGroup createCitationGroup(XTextDocument doc, } } + /* + * Backend52 uses reference marks to (1) mark the location of the citation in the text and (2) to encode + * the citation keys and citation type in the name of the reference mark. The name of the reference mark + * has to be unique in the document. + */ + final String markName = Codec52.getUniqueMarkName(new HashSet<>(citationStorageManager.getUsedNames(doc)), + citationKeys, + citationType); + + final CitationGroupId groupId = new CitationGroupId(markName); + /* * Apply to document */ diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java index f567a3e459e..45f3bd3ca04 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java @@ -32,16 +32,16 @@ private Codec52() { */ public static class ParsedMarkName { /** "", "0", "1" ... */ - public final String i; + public final String index; /** in-text-citation type */ public final CitationType citationType; /** Citation keys embedded in the reference mark. */ public final List citationKeys; - ParsedMarkName(String i, CitationType citationType, List citationKeys) { - Objects.requireNonNull(i); + ParsedMarkName(String index, CitationType citationType, List citationKeys) { + Objects.requireNonNull(index); Objects.requireNonNull(citationKeys); - this.i = i; + this.index = index; this.citationType = citationType; this.citationKeys = citationKeys; } @@ -50,8 +50,8 @@ public static class ParsedMarkName { /** * Integer representation was written into the document in JabRef52, keep it for compatibility. */ - private static CitationType citationTypeFromInt(int i) { - return switch (i) { + private static CitationType citationTypeFromInt(int code) { + return switch (code) { case 1 -> CitationType.AUTHORYEAR_PAR; case 2 -> CitationType.AUTHORYEAR_INTEXT; case 3 -> CitationType.INVISIBLE_CIT; @@ -59,8 +59,8 @@ private static CitationType citationTypeFromInt(int i) { }; } - private static int citationTypeToInt(CitationType i) { - return switch (i) { + private static int citationTypeToInt(CitationType type) { + return switch (type) { case AUTHORYEAR_PAR -> 1; case AUTHORYEAR_INTEXT -> 2; case INVISIBLE_CIT -> 3; @@ -86,12 +86,12 @@ public static String getUniqueMarkName(Set usedNames, String citationKeysPart = String.join(",", citationKeys); - int i = 0; + int index = 0; int citTypeCode = citationTypeToInt(citationType); String name = BIB_CITATION + '_' + citTypeCode + '_' + citationKeysPart; while (usedNames.contains(name)) { - name = BIB_CITATION + i + '_' + citTypeCode + '_' + citationKeysPart; - i++; + name = BIB_CITATION + index + '_' + citTypeCode + '_' + citationKeysPart; + index++; } return name; } @@ -110,10 +110,10 @@ public static Optional parseMarkName(String refMarkName) { } List keys = Arrays.asList(citeMatcher.group(3).split(",")); - String i = citeMatcher.group(1); + String index = citeMatcher.group(1); int citTypeCode = Integer.parseInt(citeMatcher.group(2)); CitationType citationType = citationTypeFromInt(citTypeCode); - return (Optional.of(new Codec52.ParsedMarkName(i, citationType, keys))); + return (Optional.of(new Codec52.ParsedMarkName(index, citationType, keys))); } /** 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 cfabb1e2de0..324b984377c 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java @@ -35,14 +35,14 @@ class NamedRangeReferenceMark implements NamedRange { private static final Logger LOGGER = LoggerFactory.getLogger(NamedRangeReferenceMark.class); - private String id; /* reference mark name */ + private String rangeId; /* reference mark name */ - private NamedRangeReferenceMark(String id) { - this.id = id; + private NamedRangeReferenceMark(String rangeId) { + this.rangeId = rangeId; } String getId() { - return id; + return rangeId; } /** @@ -156,7 +156,7 @@ public void removeFromDocument(XTextDocument doc) @Override public String getRangeName() { - return id; + return rangeId; } /** @@ -217,8 +217,6 @@ public XTextCursor getFillCursor(XTextDocument doc) String name = this.getRangeName(); - final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; - final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; final boolean debugThisFun = false; XTextCursor full = null; @@ -279,6 +277,8 @@ public XTextCursor getFillCursor(XTextDocument doc) beta.goRight((short) (fullText.length() - 2), true); LOGGER.debug("getFillCursor: beta(1) covers '{}'", beta.getString()); + final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; + final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; final short rightLength = (short) right.length(); if (fullText.startsWith(left) && fullText.endsWith(right)) { beta.setString(""); @@ -345,7 +345,6 @@ public XTextCursor getFillCursor(XTextDocument doc) */ public static void checkFillCursor(XTextCursor cursor) { final String left = REFERENCE_MARK_LEFT_BRACKET; - final String right = REFERENCE_MARK_RIGHT_BRACKET; XTextCursor alpha = cursor.getText().createTextCursorByRange(cursor); alpha.collapseToStart(); @@ -364,6 +363,7 @@ public static void checkFillCursor(XTextCursor cursor) { } } + final String right = REFERENCE_MARK_RIGHT_BRACKET; final short rightLength = (short) right.length(); if (rightLength > 0) { omega.goRight(rightLength, true); @@ -395,27 +395,26 @@ public void cleanFillCursor(XTextDocument doc) // removeBracketsFromEmpty is intended to force removal if we are working on an "Empty citation" (INVISIBLE_CIT). final boolean removeBracketsFromEmpty = false; - final String left = REFERENCE_MARK_LEFT_BRACKET; - final String right = REFERENCE_MARK_RIGHT_BRACKET; - final short leftLength = (short) left.length(); - final short rightLength = (short) right.length(); - String name = this.getRangeName(); XTextCursor full = this.getRawCursor(doc).orElseThrow(IllegalStateException::new); final String fullText = full.getString(); - final int fullTextLength = fullText.length(); + final String left = REFERENCE_MARK_LEFT_BRACKET; if (!fullText.startsWith(left)) { String msg = String.format("cleanFillCursor: (%s) does not start with REFERENCE_MARK_LEFT_BRACKET", name); throw new IllegalStateException(msg); } + final String right = REFERENCE_MARK_RIGHT_BRACKET; if (!fullText.endsWith(right)) { String msg = String.format("cleanFillCursor: (%s) does not end with REFERENCE_MARK_RIGHT_BRACKET", name); throw new IllegalStateException(msg); } + final int fullTextLength = fullText.length(); + final short leftLength = (short) left.length(); + final short rightLength = (short) right.length(); final int contentLength = (fullTextLength - (leftLength + rightLength)); if (contentLength < 0) { String msg = String.format("cleanFillCursor: length(%s) < 0", name); 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 f7b3d14def6..ebda8359ba5 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java @@ -40,7 +40,7 @@ public static Optional getBibliographyRange(XTextDocument doc) * Rebuilds the bibliography. */ public static void rebuildBibTextSection(XTextDocument doc, - OOFrontend fr, + OOFrontend frontend, CitedKeys bibliography, OOBibStyle style, boolean alwaysAddCitedOnPages) @@ -52,7 +52,7 @@ public static void rebuildBibTextSection(XTextDocument doc, clearBibTextSectionContent2(doc); populateBibTextSection(doc, - fr, + frontend, bibliography, style, alwaysAddCitedOnPages); @@ -105,7 +105,7 @@ private static void clearBibTextSectionContent2(XTextDocument doc) * Assumes the section named BIB_SECTION_NAME exists. */ private static void populateBibTextSection(XTextDocument doc, - OOFrontend fr, + OOFrontend frontend, CitedKeys bibliography, OOBibStyle style, boolean alwaysAddCitedOnPages) @@ -121,7 +121,7 @@ private static void populateBibTextSection(XTextDocument doc, // emit the title of the bibliography OOTextIntoOO.removeDirectFormatting(cursor); - OOText bibliographyText = OOFormatBibliography.formatBibliography(fr.citationGroups, + OOText bibliographyText = OOFormatBibliography.formatBibliography(frontend.citationGroups, bibliography, style, alwaysAddCitedOnPages); diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java index 55f04775094..834fce1d0ce 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java @@ -40,18 +40,18 @@ private UpdateCitationMarkers() { * After each fillCitationMarkInCursor call check if we lost the * BIB_SECTION_NAME bookmark and recreate it if we did. * - * @param fr + * @param frontend * * @param style Bibliography style to use. * */ - public static void applyNewCitationMarkers(XTextDocument doc, OOFrontend fr, OOBibStyle style) + public static void applyNewCitationMarkers(XTextDocument doc, OOFrontend frontend, OOBibStyle style) throws NoDocumentException, CreationException, WrappedTargetException { - CitationGroups citationGroups = fr.citationGroups; + CitationGroups citationGroups = frontend.citationGroups; for (CitationGroup group : citationGroups.getCitationGroupsUnordered()) { @@ -66,11 +66,11 @@ public static void applyNewCitationMarkers(XTextDocument doc, OOFrontend fr, OOB if (withText && marker.isPresent()) { - XTextCursor cursor = fr.getFillCursorForCitationGroup(doc, group); + XTextCursor cursor = frontend.getFillCursorForCitationGroup(doc, group); fillCitationMarkInCursor(doc, cursor, marker.get(), withText, style); - fr.cleanFillCursorForCitationGroup(doc, group); + frontend.cleanFillCursorForCitationGroup(doc, group); } } @@ -118,7 +118,7 @@ public static void fillCitationMarkInCursor(XTextDocument doc, * coming after. But is not wanted when we recreate a * reference mark. */ - public static void createAndFillCitationGroup(OOFrontend fr, + public static void createAndFillCitationGroup(OOFrontend frontend, XTextDocument doc, List citationKeys, List> pageInfos, @@ -140,21 +140,21 @@ public static void createAndFillCitationGroup(OOFrontend fr, if (pageInfos.size() != citationKeys.size()) { throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); } - CitationGroup group = fr.createCitationGroup(doc, - citationKeys, - pageInfos, - citationType, - position, - insertSpaceAfter); + CitationGroup group = frontend.createCitationGroup(doc, + citationKeys, + pageInfos, + citationType, + position, + insertSpaceAfter); final boolean withText = citationType.withText(); if (withText) { - XTextCursor fillCursor = fr.getFillCursorForCitationGroup(doc, group); + XTextCursor fillCursor = frontend.getFillCursorForCitationGroup(doc, group); UpdateCitationMarkers.fillCitationMarkInCursor(doc, fillCursor, citationText, withText, style); - fr.cleanFillCursorForCitationGroup(doc, group); + frontend.cleanFillCursorForCitationGroup(doc, group); } position.collapseToEnd(); } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index 082d94a7fdf..5108c94c8b3 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -291,20 +291,20 @@ private boolean isUpToDate() { } } - private void readFormatFile(Reader in) throws IOException { + private void readFormatFile(Reader input) throws IOException { // First read all the contents of the file: - StringBuilder sb = new StringBuilder(); - int c; - while ((c = in.read()) != -1) { - sb.append((char) c); + StringBuilder stringBuilder = new StringBuilder(); + int chr; + while ((chr = input.read()) != -1) { + stringBuilder.append((char) chr); } // Store a local copy for viewing - localCopy = sb.toString(); + localCopy = stringBuilder.toString(); // Break into separate lines: - String[] lines = sb.toString().split("\n"); + String[] lines = stringBuilder.toString().split("\n"); BibStyleMode mode = BibStyleMode.NONE; for (String line1 : lines) { @@ -386,11 +386,12 @@ private void handleStructureLine(String line) { if ((index > 0) && (index < (line.length() - 1))) { try { - String formatString = line.substring(index + 1); + final String typeName = line.substring(0, index); + final String formatString = line.substring(index + 1); Layout layout = new LayoutHelper(new StringReader(formatString), this.prefs).getLayoutFromText(); - EntryType type = EntryTypeFactory.parse(line.substring(0, index)); + EntryType type = EntryTypeFactory.parse(typeName); - if (!isDefaultLayoutPresent && line.substring(0, index).equals(OOBibStyle.DEFAULT_MARK)) { + if (!isDefaultLayoutPresent && OOBibStyle.DEFAULT_MARK.equals(typeName)) { isDefaultLayoutPresent = true; defaultBibLayout = layout; } else { @@ -437,11 +438,11 @@ private void handleJournalsLine(String line) { } public Layout getReferenceFormat(EntryType type) { - Layout l = bibLayout.get(type); - if (l == null) { + Layout layout = bibLayout.get(type); + if (layout == null) { return defaultBibLayout; } else { - return l; + return layout; } } @@ -464,7 +465,7 @@ public String getNumCitationMarker(List number, int minGroupingCount, b // Sort the numbers: List lNum = new ArrayList<>(number); Collections.sort(lNum); - StringBuilder sb = new StringBuilder(bracketBefore); + StringBuilder stringBuilder = new StringBuilder(bracketBefore); int combineFrom = -1; int written = 0; for (int i = 0; i < lNum.size(); i++) { @@ -476,9 +477,9 @@ public String getNumCitationMarker(List number, int minGroupingCount, b } else { // Add single entry: if (i > 0) { - sb.append(getStringCitProperty(CITATION_SEPARATOR)); + stringBuilder.append(getStringCitProperty(CITATION_SEPARATOR)); } - sb.append(lNum.get(i) > 0 ? String.valueOf(lNum.get(i)) : OOBibStyle.UNDEFINED_CITATION_MARKER); + stringBuilder.append(lNum.get(i) > 0 ? String.valueOf(lNum.get(i)) : OOBibStyle.UNDEFINED_CITATION_MARKER); written++; } } else { @@ -486,20 +487,20 @@ public String getNumCitationMarker(List number, int minGroupingCount, b // Check if it ends here: if ((i == (lNum.size() - 1)) || (lNum.get(i + 1) != (i1 + 1))) { if (written > 0) { - sb.append(getStringCitProperty(CITATION_SEPARATOR)); + stringBuilder.append(getStringCitProperty(CITATION_SEPARATOR)); } if ((minGroupingCount > 0) && (((i1 + 1) - combineFrom) >= minGroupingCount)) { - sb.append(combineFrom); - sb.append(getStringCitProperty(GROUPED_NUMBERS_SEPARATOR)); - sb.append(i1); + stringBuilder.append(combineFrom); + stringBuilder.append(getStringCitProperty(GROUPED_NUMBERS_SEPARATOR)); + stringBuilder.append(i1); written++; } else { // Either we should never group, or there aren't enough // entries in this case to group. Output all: for (int jj = combineFrom; jj <= i1; jj++) { - sb.append(jj); + stringBuilder.append(jj); if (jj < i1) { - sb.append(getStringCitProperty(CITATION_SEPARATOR)); + stringBuilder.append(getStringCitProperty(CITATION_SEPARATOR)); } written++; } @@ -509,8 +510,8 @@ public String getNumCitationMarker(List number, int minGroupingCount, b // If it doesn't end here, just keep iterating. } } - sb.append(bracketAfter); - return sb.toString(); + stringBuilder.append(bracketAfter); + return stringBuilder.toString(); } /* end_old */ @@ -591,13 +592,13 @@ public String getCitationMarker(List entries, Map entries, String[] uniquefiers, int from, int to) { String separator = getStringCitProperty(UNIQUEFIER_SEPARATOR); - StringBuilder sb = new StringBuilder(uniquefiers[from]); + StringBuilder stringBuilder = new StringBuilder(uniquefiers[from]); for (int i = from + 1; i <= to; i++) { - sb.append(separator); - sb.append(uniquefiers[i]); + stringBuilder.append(separator); + stringBuilder.append(uniquefiers[i]); entries.set(i, null); } - uniquefiers[from] = sb.toString(); + uniquefiers[from] = stringBuilder.toString(); } /* end_old */ @@ -622,7 +623,7 @@ private String getAuthorYearParenthesisMarker(List entries, Map entries, Map 0) { - sb.append(citationSeparator); + stringBuilder.append(citationSeparator); } BibDatabase currentDatabase = database.get(currentEntry); @@ -641,17 +642,17 @@ private String getAuthorYearParenthesisMarker(List entries, Map entries, Map entries, Map 0 ? unlimA : maxA; if (i > 0) { - sb.append(citationSeparator); + stringBuilder.append(citationSeparator); } String author = getCitationMarkerField(currentEntry, currentDatabase, authorField); String authorString = createAuthorList(author, maxAuthors, andString, yearSep); - sb.append(authorString); - sb.append(startBrace); + stringBuilder.append(authorString); + stringBuilder.append(startBrace); String year = getCitationMarkerField(currentEntry, currentDatabase, yearField); if (year != null) { - sb.append(year); + stringBuilder.append(year); } if ((uniquefiers != null) && (uniquefiers[i] != null)) { - sb.append(uniquefiers[i]); + stringBuilder.append(uniquefiers[i]); } - sb.append(endBrace); + stringBuilder.append(endBrace); } - return sb.toString(); + return stringBuilder.toString(); } /* end_old */ @@ -757,15 +758,15 @@ private String getCitationMarkerField(BibEntry entry, BibDatabase database, Stri * @return The author name, or an empty String if inapplicable. */ private String getAuthorLastName(AuthorList al, int number) { - StringBuilder sb = new StringBuilder(); + StringBuilder stringBuilder = new StringBuilder(); if (al.getNumberOfAuthors() > number) { Author a = al.getAuthor(number); - a.getVon().filter(von -> !von.isEmpty()).ifPresent(von -> sb.append(von).append(' ')); - sb.append(a.getLast().orElse("")); + a.getVon().filter(von -> !von.isEmpty()).ifPresent(von -> stringBuilder.append(von).append(' ')); + stringBuilder.append(a.getLast().orElse("")); } - return sb.toString(); + return stringBuilder.toString(); } /* end_old */ @@ -896,12 +897,12 @@ public int compareTo(OOBibStyle other) { } @Override - public boolean equals(Object o) { - if (this == o) { + public boolean equals(Object object) { + if (this == object) { return true; } - if (o instanceof OOBibStyle) { - OOBibStyle otherStyle = (OOBibStyle) o; + if (object instanceof OOBibStyle) { + OOBibStyle otherStyle = (OOBibStyle) object; return Objects.equals(path, otherStyle.path) && Objects.equals(name, otherStyle.name) && Objects.equals(citProperties, otherStyle.citProperties) @@ -923,28 +924,28 @@ private String createAuthorList(String author, int maxAuthors, String andString, String etAlString = getStringCitProperty(ET_AL_STRING); // The String to represent authors that are not mentioned, e.g. " et al." String authorSep = getStringCitProperty(AUTHOR_SEPARATOR); // The String to add between author names except the last two, e.g. ", ". String oxfordComma = getStringCitProperty(OXFORD_COMMA); // The String to put after the second to last author in case of three or more authors - StringBuilder sb = new StringBuilder(); + StringBuilder stringBuilder = new StringBuilder(); AuthorList al = AuthorList.parse(author); if (!al.isEmpty()) { - sb.append(getAuthorLastName(al, 0)); + stringBuilder.append(getAuthorLastName(al, 0)); } if ((al.getNumberOfAuthors() > 1) && ((al.getNumberOfAuthors() <= maxAuthors) || (maxAuthors < 0))) { int j = 1; while (j < (al.getNumberOfAuthors() - 1)) { - sb.append(authorSep); - sb.append(getAuthorLastName(al, j)); + stringBuilder.append(authorSep); + stringBuilder.append(getAuthorLastName(al, j)); j++; } if (al.getNumberOfAuthors() > 2) { - sb.append(oxfordComma); + stringBuilder.append(oxfordComma); } - sb.append(andString); - sb.append(getAuthorLastName(al, al.getNumberOfAuthors() - 1)); + stringBuilder.append(andString); + stringBuilder.append(getAuthorLastName(al, al.getNumberOfAuthors() - 1)); } else if (al.getNumberOfAuthors() > maxAuthors) { - sb.append(etAlString); + stringBuilder.append(etAlString); } - sb.append(yearSep); - return sb.toString(); + stringBuilder.append(yearSep); + return stringBuilder.toString(); } /* end_old */ @@ -1078,8 +1079,8 @@ public OOText getNumCitationMarkerForBibliography(CitationMarkerNumericBibEntry return OOBibStyleGetNumCitationMarker.getNumCitationMarkerForBibliography(this, entry); } - public OOText getNormalizedCitationMarker(CitationMarkerNormEntry ce) { - return OOBibStyleGetCitationMarker.getNormalizedCitationMarker(this, ce, Optional.empty()); + public OOText getNormalizedCitationMarker(CitationMarkerNormEntry entry) { + return OOBibStyleGetCitationMarker.getNormalizedCitationMarker(this, entry, Optional.empty()); } /** @@ -1158,10 +1159,6 @@ public String getGroupedNumbersSeparator() { return getStringCitProperty(OOBibStyle.GROUPED_NUMBERS_SEPARATOR); } - private boolean getBooleanProperty(String propName) { - return (Boolean) properties.get(propName); - } - private String getStringProperty(String propName) { return (String) properties.get(propName); } @@ -1308,12 +1305,9 @@ public OOText getFormattedBibliographyTitle() { OOBibStyle style = this; OOText title = style.getReferenceHeaderText(); String parStyle = style.getReferenceHeaderParagraphFormat(); - if (parStyle != null) { - title = OOFormat.paragraph(title, parStyle); - } else { - title = OOFormat.paragraph(title); - } - return title; + return (parStyle == null + ? OOFormat.paragraph(title) + : OOFormat.paragraph(title, parStyle)); } } 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 deb1a306913..2e5227d080e 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java @@ -38,21 +38,21 @@ private OOBibStyleGetCitationMarker() { * @return The author name, or an empty String if inapplicable. */ private static String getAuthorLastName(AuthorList authorList, int number) { - StringBuilder sb = new StringBuilder(); + StringBuilder stringBuilder = new StringBuilder(); if (authorList.getNumberOfAuthors() > number) { Author author = authorList.getAuthor(number); // "von " if von exists Optional von = author.getVon(); if (von.isPresent() && !von.get().isEmpty()) { - sb.append(von.get()); - sb.append(' '); + stringBuilder.append(von.get()); + stringBuilder.append(' '); } // last name if it exists - sb.append(author.getLast().orElse("")); + stringBuilder.append(author.getLast().orElse("")); } - return sb.toString(); + return stringBuilder.toString(); } private static String markupAuthorName(OOBibStyle style, String name) { @@ -127,7 +127,7 @@ private static String formatAuthorList(OOBibStyle style, // of three or more authors: (A, B[,] and C) String oxfordComma = style.getOxfordComma(); - StringBuilder sb = new StringBuilder(); + StringBuilder stringBuilder = new StringBuilder(); final int nAuthors = authorList.getNumberOfAuthors(); @@ -149,11 +149,11 @@ private static String formatAuthorList(OOBibStyle style, : Math.min(maxAuthorsBeforeEtAl, nAuthors)); if (nAuthorsToEmit >= 1) { - sb.append(style.getAuthorsPartMarkupBefore()); - sb.append(style.getAuthorNamesListMarkupBefore()); + stringBuilder.append(style.getAuthorsPartMarkupBefore()); + stringBuilder.append(style.getAuthorNamesListMarkupBefore()); // The first author String name = getAuthorLastName(authorList, 0); - sb.append(markupAuthorName(style, name)); + stringBuilder.append(markupAuthorName(style, name)); } if (nAuthors >= 2) { @@ -162,19 +162,19 @@ private static String formatAuthorList(OOBibStyle style, // Emit last names, except for the last author int j = 1; while (j < (nAuthors - 1)) { - sb.append(authorSep); + stringBuilder.append(authorSep); String name = getAuthorLastName(authorList, j); - sb.append(markupAuthorName(style, name)); + stringBuilder.append(markupAuthorName(style, name)); j++; } // oxfordComma if at least 3 authors if (nAuthors >= 3) { - sb.append(oxfordComma); + stringBuilder.append(oxfordComma); } // Emit " and "+"LastAuthor" - sb.append(andString); + stringBuilder.append(andString); String name = getAuthorLastName(authorList, nAuthors - 1); - sb.append(markupAuthorName(style, name)); + stringBuilder.append(markupAuthorName(style, name)); } else { // Emit last names up to nAuthorsToEmit. @@ -185,9 +185,9 @@ private static String formatAuthorList(OOBibStyle style, if (maxAuthorsBeforeEtAl > 1) { int j = 1; while (j < nAuthorsToEmit) { - sb.append(authorSep); + stringBuilder.append(authorSep); String name = getAuthorLastName(authorList, j); - sb.append(markupAuthorName(style, name)); + stringBuilder.append(markupAuthorName(style, name)); j++; } } @@ -195,15 +195,15 @@ private static String formatAuthorList(OOBibStyle style, } if (nAuthorsToEmit >= 1) { - sb.append(style.getAuthorNamesListMarkupAfter()); + stringBuilder.append(style.getAuthorNamesListMarkupAfter()); } if (nAuthors >= 2 && !emitAllAuthors) { - sb.append(etAlString); + stringBuilder.append(etAlString); } - sb.append(style.getAuthorsPartMarkupAfter()); - return sb.toString(); + stringBuilder.append(style.getAuthorsPartMarkupAfter()); + return stringBuilder.toString(); } /** @@ -279,15 +279,15 @@ private static String getCitationMarkerField(OOBibStyle style, return ""; } - FieldAndContent fc = optionalFieldAndContent.get(); - String result = style.getFieldFormatter().format(fc.content); + FieldAndContent fieldAndContent = optionalFieldAndContent.get(); + String result = style.getFieldFormatter().format(fieldAndContent.content); // If the field we found is mentioned in authorFieldNames and // content has a pair of braces around it, we add a pair of // braces around the result, so that AuthorList.parse does not split // the content. final OrFields fieldsToRebrace = style.getAuthorFieldNames(); - if (fieldsToRebrace.contains(fc.field) && StringUtil.isInCurlyBrackets(fc.content)) { + if (fieldsToRebrace.contains(fieldAndContent.field) && StringUtil.isInCurlyBrackets(fieldAndContent.content)) { result = "{" + result + "}"; } return result; @@ -406,11 +406,11 @@ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, String pageInfoSeparator = style.getPageInfoSeparator(); String uniquefierSeparator = style.getUniquefierSeparator(); - StringBuilder sb = new StringBuilder(); - sb.append(style.getCitationGroupMarkupBefore()); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(style.getCitationGroupMarkupBefore()); if (inParenthesis) { - sb.append(startBrace); // shared parenthesis + stringBuilder.append(startBrace); // shared parenthesis } for (int j = 0; j < entries.size(); j++) { @@ -422,19 +422,19 @@ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, // Just add our uniqueLetter String uniqueLetter = entry.getUniqueLetter().orElse(null); if (uniqueLetter != null) { - sb.append(uniquefierSeparator); - sb.append(uniqueLetter); + stringBuilder.append(uniquefierSeparator); + stringBuilder.append(uniqueLetter); } // And close the brace, if we are the last in the group. if (!inParenthesis && endingAGroup) { - sb.append(endBrace); + stringBuilder.append(endBrace); } continue; } if (j > 0) { - sb.append(citationSeparator); + stringBuilder.append(citationSeparator); } StringBuilder pageInfoPart = new StringBuilder(""); @@ -449,9 +449,9 @@ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, final boolean isUnresolved = entry.getLookupResult().isEmpty(); if (isUnresolved) { - sb.append(String.format("Unresolved(%s)", entry.getCitationKey())); + stringBuilder.append(String.format("Unresolved(%s)", entry.getCitationKey())); if (purpose != AuthorYearMarkerPurpose.NORMALIZED) { - sb.append(pageInfoPart); + stringBuilder.append(pageInfoPart); } } else { @@ -467,40 +467,40 @@ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, AuthorList authorList = getAuthorList(style, db); String authorString = formatAuthorList(style, authorList, maxAuthors, andString); - sb.append(authorString); - sb.append(yearSep); + stringBuilder.append(authorString); + stringBuilder.append(yearSep); if (!inParenthesis) { - sb.append(startBrace); // parenthesis before year + stringBuilder.append(startBrace); // parenthesis before year } String year = getCitationMarkerField(style, db, yearFieldNames); if (year != null) { - sb.append(year); + stringBuilder.append(year); } if (purpose != AuthorYearMarkerPurpose.NORMALIZED) { String uniqueLetter = entry.getUniqueLetter().orElse(null); if (uniqueLetter != null) { - sb.append(uniqueLetter); + stringBuilder.append(uniqueLetter); } } if (purpose != AuthorYearMarkerPurpose.NORMALIZED) { - sb.append(pageInfoPart); + stringBuilder.append(pageInfoPart); } if (!inParenthesis && endingAGroup) { - sb.append(endBrace); // parenthesis after year + stringBuilder.append(endBrace); // parenthesis after year } } } // for j if (inParenthesis) { - sb.append(endBrace); // shared parenthesis + stringBuilder.append(endBrace); // shared parenthesis } - sb.append(style.getCitationGroupMarkupAfter()); - return OOText.fromString(sb.toString()); + stringBuilder.append(style.getCitationGroupMarkupAfter()); + return OOText.fromString(stringBuilder.toString()); } /** @@ -638,9 +638,9 @@ static OOText getNormalizedCitationMarker(OOBibStyle style, int[] nAuthorsToEmitRevised = new int[nEntries]; for (int i = 0; i < nEntries; i++) { CitationMarkerEntry entry = citationMarkerEntries.get(i); - int n = calculateNAuthorsToEmit(style, entry); - nAuthorsToEmit[i] = n; - nAuthorsToEmitRevised[i] = n; + int nAuthors = calculateNAuthorsToEmit(style, entry); + nAuthorsToEmit[i] = nAuthors; + nAuthorsToEmitRevised[i] = nAuthors; } boolean[] startsNewGroup = new boolean[nEntries]; diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java index 5dce4e8caa1..60b5222cf5b 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java @@ -53,23 +53,23 @@ public static OOText getNumCitationMarkerForBibliography(OOBibStyle style, // prefer BRACKET_BEFORE_IN_LIST and BRACKET_AFTER_IN_LIST String bracketBefore = style.getBracketBeforeInListWithFallBack(); String bracketAfter = style.getBracketAfterInListWithFallBack(); - StringBuilder sb = new StringBuilder(); - sb.append(style.getCitationGroupMarkupBefore()); - sb.append(bracketBefore); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(style.getCitationGroupMarkupBefore()); + stringBuilder.append(bracketBefore); final Optional current = entry.getNumber(); - sb.append(current.isPresent() + stringBuilder.append(current.isPresent() ? String.valueOf(current.get()) : (OOBibStyle.UNDEFINED_CITATION_MARKER + entry.getCitationKey())); - sb.append(bracketAfter); - sb.append(style.getCitationGroupMarkupAfter()); - return OOText.fromString(sb.toString()); + stringBuilder.append(bracketAfter); + stringBuilder.append(style.getCitationGroupMarkupAfter()); + return OOText.fromString(stringBuilder.toString()); } /* * emitBlock : a helper for getNumCitationMarker2 * * Given a block containing either a single entry or two or more - * entries that are joinable into an "i-j" form, append to {@code sb} the + * entries that are joinable into an "i-j" form, append to {@code stringBuilder} the * formatted text. * * Assumes: @@ -91,7 +91,7 @@ public static OOText getNumCitationMarkerForBibliography(OOBibStyle style, private static void emitBlock(List block, OOBibStyle style, int minGroupingCount, - StringBuilder sb) { + StringBuilder stringBuilder) { final int blockSize = block.size(); if (blockSize == 0) { @@ -102,14 +102,14 @@ private static void emitBlock(List block, // Add single entry: CitationMarkerNumericEntry entry = block.get(0); final Optional num = entry.getNumber(); - sb.append(num.isEmpty() - ? (OOBibStyle.UNDEFINED_CITATION_MARKER + entry.getCitationKey()) - : String.valueOf(num.get())); + stringBuilder.append(num.isEmpty() + ? (OOBibStyle.UNDEFINED_CITATION_MARKER + entry.getCitationKey()) + : String.valueOf(num.get())); // Emit pageInfo Optional pageInfo = entry.getPageInfo(); if (pageInfo.isPresent()) { - sb.append(style.getPageInfoSeparator()); - sb.append(OOText.toString(pageInfo.get())); + stringBuilder.append(style.getPageInfoSeparator()); + stringBuilder.append(OOText.toString(pageInfo.get())); } return; } @@ -146,17 +146,17 @@ private static void emitBlock(List block, } // Emit: "first-last" - sb.append(first); - sb.append(style.getGroupedNumbersSeparator()); - sb.append(last); + stringBuilder.append(first); + stringBuilder.append(style.getGroupedNumbersSeparator()); + stringBuilder.append(last); } else { // Emit: first, first+1,..., last for (int j = 0; j < blockSize; j++) { if (j > 0) { - sb.append(style.getCitationSeparator()); + stringBuilder.append(style.getCitationSeparator()); } - sb.append(block.get(j).getNumber().get()); + stringBuilder.append(block.get(j).getNumber().get()); } } return; @@ -194,15 +194,15 @@ public static OOText getNumCitationMarker2(OOBibStyle style, final boolean joinIsDisabled = (minGroupingCount <= 0); final int nCitations = entries.size(); - String bracketBefore = style.getBracketBefore(); - String bracketAfter = style.getBracketAfter(); + final String bracketBefore = style.getBracketBefore(); + final String bracketAfter = style.getBracketAfter(); // Sort a copy of entries List sorted = OOListUtil.map(entries, e -> e); sorted.sort(OOBibStyleGetNumCitationMarker::compareCitationMarkerNumericEntry); // "[" - StringBuilder sb = new StringBuilder(bracketBefore); + StringBuilder stringBuilder = new StringBuilder(bracketBefore); /* * Original: @@ -248,12 +248,12 @@ public static OOText getNumCitationMarker2(OOBibStyle style, } } - if (nextBlock.size() > 0) { + if (!nextBlock.isEmpty()) { // emit current block if (blocksEmitted) { - sb.append(style.getCitationSeparator()); + stringBuilder.append(style.getCitationSeparator()); } - emitBlock(currentBlock, style, minGroupingCount, sb); + emitBlock(currentBlock, style, minGroupingCount, stringBuilder); blocksEmitted = true; currentBlock = nextBlock; nextBlock = new ArrayList<>(); @@ -261,21 +261,21 @@ public static OOText getNumCitationMarker2(OOBibStyle style, } - if (nextBlock.size() != 0) { + if (!nextBlock.isEmpty()) { throw new IllegalStateException("impossible: (nextBlock.size() != 0) after loop"); } - if (currentBlock.size() > 0) { + if (!currentBlock.isEmpty()) { // We are emitting a block if (blocksEmitted) { - sb.append(style.getCitationSeparator()); + stringBuilder.append(style.getCitationSeparator()); } - emitBlock(currentBlock, style, minGroupingCount, sb); + emitBlock(currentBlock, style, minGroupingCount, stringBuilder); } // Emit: "]" - sb.append(bracketAfter); - return OOText.fromString(sb.toString()); + stringBuilder.append(bracketAfter); + return OOText.fromString(stringBuilder.toString()); } } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java b/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java index 4bc3fac6191..ea311193068 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java @@ -49,8 +49,8 @@ public static OOText formatBibliographyBody(CitationGroups cgs, StringBuilder stringBuilder = new StringBuilder(); - for (CitedKey ck : bibliography.values()) { - OOText entryText = formatBibliographyEntry(cgs, ck, style, alwaysAddCitedOnPages); + for (CitedKey citedKey : bibliography.values()) { + OOText entryText = formatBibliographyEntry(cgs, citedKey, style, alwaysAddCitedOnPages); stringBuilder.append(entryText.toString()); } @@ -61,29 +61,29 @@ public static OOText formatBibliographyBody(CitationGroups cgs, * @return A paragraph. Includes label and "Cited on pages". */ public static OOText formatBibliographyEntry(CitationGroups cgs, - CitedKey ck, + CitedKey citedKey, OOBibStyle style, boolean alwaysAddCitedOnPages) { - StringBuilder sb = new StringBuilder(); + StringBuilder stringBuilder = new StringBuilder(); // insert marker "[1]" if (style.isNumberEntries()) { - sb.append(style.getNumCitationMarkerForBibliography(ck).toString()); + stringBuilder.append(style.getNumCitationMarkerForBibliography(citedKey).toString()); } else { // !style.isNumberEntries() : emit no prefix // Note: We might want [citationKey] prefix for style.isCitationKeyCiteMarkers(); } // Add entry body - sb.append(formatBibliographyEntryBody(ck, style).toString()); + stringBuilder.append(formatBibliographyEntryBody(citedKey, style).toString()); // Add "Cited on pages" - if (ck.getLookupResult().isEmpty() || alwaysAddCitedOnPages) { - sb.append(formatCitedOnPages(cgs, ck).toString()); + if (citedKey.getLookupResult().isEmpty() || alwaysAddCitedOnPages) { + stringBuilder.append(formatCitedOnPages(cgs, citedKey).toString()); } // Add paragraph - OOText entryText = OOText.fromString(sb.toString()); + OOText entryText = OOText.fromString(stringBuilder.toString()); String parStyle = style.getReferenceParagraphFormat(); return OOFormat.paragraph(entryText, parStyle); } @@ -91,20 +91,20 @@ public static OOText formatBibliographyEntry(CitationGroups cgs, /** * @return just the body of a bibliography entry. No label, "Cited on pages" or paragraph. */ - public static OOText formatBibliographyEntryBody(CitedKey ck, OOBibStyle style) { - if (ck.getLookupResult().isEmpty()) { + public static OOText formatBibliographyEntryBody(CitedKey citedKey, OOBibStyle style) { + if (citedKey.getLookupResult().isEmpty()) { // Unresolved entry - return OOText.fromString(String.format("Unresolved(%s)", ck.citationKey)); + return OOText.fromString(String.format("Unresolved(%s)", citedKey.citationKey)); } else { // Resolved entry, use the layout engine - BibEntry bibentry = ck.getLookupResult().get().entry; + BibEntry bibentry = citedKey.getLookupResult().get().entry; Layout layout = style.getReferenceFormat(bibentry.getType()); layout.setPostFormatter(POSTFORMATTER); return formatFullReferenceOfBibEntry(layout, bibentry, - ck.getLookupResult().get().database, - ck.getUniqueLetter().orElse(null)); + citedKey.getLookupResult().get().database, + citedKey.getUniqueLetter().orElse(null)); } } @@ -147,27 +147,27 @@ private static OOText formatFullReferenceOfBibEntry(Layout layout, } /** - * Format links to citations of the source (ck). + * Format links to citations of the source (citedKey). * * Requires reference marks for the citation groups. * * - The links are created as references that show page numbers of the reference marks. * - We do not control the text shown, that is provided by OpenOffice. */ - private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey ck) { + private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey citedKey) { if (!cgs.citationGroupsProvideReferenceMarkNameForLinking()) { return OOText.fromString(""); } - StringBuilder sb = new StringBuilder(); + StringBuilder stringBuilder = new StringBuilder(); - String prefix = String.format(" (%s: ", Localization.lang("Cited on pages")); - String suffix = ")"; - sb.append(prefix); + final String prefix = String.format(" (%s: ", Localization.lang("Cited on pages")); + final String suffix = ")"; + stringBuilder.append(prefix); List citationGroups = new ArrayList<>(); - for (CitationPath p : ck.getCitationPaths()) { + for (CitationPath p : citedKey.getCitationPaths()) { CitationGroupId groupId = p.group; Optional group = cgs.getCitationGroup(groupId); if (group.isEmpty()) { @@ -183,18 +183,18 @@ private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey ck) { return (aa.compareTo(bb)); }); - int i = 0; + int index = 0; for (CitationGroup group : citationGroups) { - if (i > 0) { - sb.append(", "); + if (index > 0) { + stringBuilder.append(", "); } String markName = group.getReferenceMarkNameForLinking().orElseThrow(IllegalStateException::new); OOText xref = OOFormat.formatReferenceToPageNumberOfReferenceMark(markName); - sb.append(xref.toString()); - i++; + stringBuilder.append(xref.toString()); + index++; } - sb.append(suffix); - return OOText.fromString(sb.toString()); + stringBuilder.append(suffix); + return OOText.fromString(stringBuilder.toString()); } } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java index 1aaeb538930..affbc7584ae 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java @@ -88,8 +88,8 @@ private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroup // according to their order in clashingKeys. int nextUniqueLetter = 'a'; for (String citationKey : clashingKeys) { - String ul = String.valueOf((char) nextUniqueLetter); - sortedCitedKeys.get(citationKey).setUniqueLetter(Optional.of(ul)); + String uniqueLetter = String.valueOf((char) nextUniqueLetter); + sortedCitedKeys.get(citationKey).setUniqueLetter(Optional.of(uniqueLetter)); nextUniqueLetter++; } } diff --git a/src/main/java/org/jabref/model/openoffice/CitationEntry.java b/src/main/java/org/jabref/model/openoffice/CitationEntry.java index 219e71eb0d1..0d702c860ab 100644 --- a/src/main/java/org/jabref/model/openoffice/CitationEntry.java +++ b/src/main/java/org/jabref/model/openoffice/CitationEntry.java @@ -37,12 +37,12 @@ public int compareTo(CitationEntry other) { } @Override - public boolean equals(Object o) { - if (this == o) { + public boolean equals(Object object) { + if (this == object) { return true; } - if (o instanceof CitationEntry) { - CitationEntry other = (CitationEntry) o; + if (object instanceof CitationEntry) { + CitationEntry other = (CitationEntry) object; return Objects.equals(this.refMarkName, other.refMarkName); } return false; diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java index 6ba6b760cb6..baaa931214c 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java @@ -4,15 +4,15 @@ * Identifies a citation group in a document. */ public class CitationGroupId { - String id; - public CitationGroupId(String id) { - this.id = id; + String groupId; + public CitationGroupId(String groupId) { + this.groupId = groupId; } /** * CitationEntry needs some string identifying the group that it can pass back later. */ public String citationGroupIdAsString() { - return id; + return groupId; } } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java index b03028b76ef..e5e642fa652 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java @@ -131,10 +131,9 @@ public void setGlobalOrder(List globalOrder) { this.globalOrder = Optional.of(globalOrder); // Propagate to each CitationGroup - int i = 0; - for (CitationGroupId groupId : globalOrder) { + for (int i = 0; i < globalOrder.size(); i++) { + CitationGroupId groupId = globalOrder.get(i); citationGroupsUnordered.get(groupId).setIndexInGlobalOrder(Optional.of(i)); - i++; } } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitedKeys.java b/src/main/java/org/jabref/model/openoffice/style/CitedKeys.java index 898fadbebe9..059c1b6123a 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitedKeys.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitedKeys.java @@ -45,11 +45,11 @@ void sortByComparator(Comparator entryComparator) { } void numberCitedKeysInCurrentOrder() { - int i = 1; + int index = 1; for (CitedKey ck : data.values()) { if (ck.getLookupResult().isPresent()) { - ck.setNumber(Optional.of(i)); - i++; + ck.setNumber(Optional.of(index)); + index++; } else { // Unresolved citations do not get a number. ck.setNumber(Optional.empty()); diff --git a/src/main/java/org/jabref/model/openoffice/style/PageInfo.java b/src/main/java/org/jabref/model/openoffice/style/PageInfo.java index ec3a8436dcf..1ff87569a3b 100644 --- a/src/main/java/org/jabref/model/openoffice/style/PageInfo.java +++ b/src/main/java/org/jabref/model/openoffice/style/PageInfo.java @@ -19,7 +19,7 @@ public static Optional normalizePageInfo(Optional optionalText) } String str = OOText.toString(optionalText.get()); String trimmed = str.trim(); - if (trimmed.equals("")) { + if ("".equals(trimmed)) { return Optional.empty(); } return Optional.of(OOText.fromString(trimmed)); diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java b/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java index 1770b6957c5..e761a56e12f 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java @@ -39,7 +39,7 @@ public static Optional getTextCursorOfTextContentAnchor(XTextConten return Optional.of(markAnchor.getText().createTextCursorByRange(markAnchor)); } - public static XTextCursor createTextCursorByRange(XTextRange r) { - return r.getText().createTextCursorByRange(r); + public static XTextCursor createTextCursorByRange(XTextRange range) { + return range.getText().createTextCursorByRange(range); } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java b/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java index dece8978713..cd4065ba8b3 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java @@ -25,10 +25,10 @@ private static Optional getStyleFromFamily(XTextDocument doc, String fam WrappedTargetException { XStyleFamiliesSupplier fss = UnoCast.cast(XStyleFamiliesSupplier.class, doc).get(); - XNameAccess fs = UnoCast.cast(XNameAccess.class, fss.getStyleFamilies()).get(); + XNameAccess families = UnoCast.cast(XNameAccess.class, fss.getStyleFamilies()).get(); XNameContainer xFamily; try { - xFamily = UnoCast.cast(XNameContainer.class, fs.getByName(familyName)).get(); + xFamily = UnoCast.cast(XNameContainer.class, families.getByName(familyName)).get(); } catch (NoSuchElementException ex) { String msg = String.format("Style family name '%s' is not recognized", familyName); throw new java.lang.IllegalArgumentException(msg, ex); diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java b/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java index b75bee17f3e..4f08bb0ed5c 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java @@ -25,17 +25,17 @@ public static Optional getXUndoManager(XTextDocument doc) { * document's undo stack is left in an inconsistent state. */ public static void enterUndoContext(XTextDocument doc, String title) { - Optional um = getXUndoManager(doc); - if (um.isPresent()) { - um.get().enterUndoContext(title); + Optional undoManager = getXUndoManager(doc); + if (undoManager.isPresent()) { + undoManager.get().enterUndoContext(title); } } public static void leaveUndoContext(XTextDocument doc) { - Optional um = getXUndoManager(doc); - if (um.isPresent()) { + Optional undoManager = getXUndoManager(doc); + if (undoManager.isPresent()) { try { - um.get().leaveUndoContext(); + undoManager.get().leaveUndoContext(); } catch (InvalidStateException ex) { throw new IllegalStateException("leaveUndoContext reported InvalidStateException"); } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java b/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java index 634edb0c57b..f5ec43f3211 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java @@ -61,8 +61,8 @@ public static Optional getStringValue(XTextDocument doc, String property throw new java.lang.IllegalArgumentException("getting UserDefinedProperties as XPropertySet failed"); } try { - String v = propertySet.get().getPropertyValue(property).toString(); - return Optional.ofNullable(v); + String value = propertySet.get().getPropertyValue(property).toString(); + return Optional.ofNullable(value); } catch (UnknownPropertyException ex) { return Optional.empty(); } diff --git a/src/main/java/org/jabref/model/openoffice/util/OOListUtil.java b/src/main/java/org/jabref/model/openoffice/util/OOListUtil.java index 1fe617ed99a..59295c798fe 100644 --- a/src/main/java/org/jabref/model/openoffice/util/OOListUtil.java +++ b/src/main/java/org/jabref/model/openoffice/util/OOListUtil.java @@ -13,19 +13,19 @@ public static List map(List list, Function fun) { return list.stream().map(e -> fun.apply(e)).collect(Collectors.toList()); } - /** Integers 0..(n-1) */ - public static List makeIndices(int n) { - return Stream.iterate(0, i -> i + 1).limit(n).collect(Collectors.toList()); + /** Integers 0..(len-1) */ + public static List makeIndices(int len) { + return Stream.iterate(0, i -> i + 1).limit(len).collect(Collectors.toList()); } /** Return indices so that list.get(indices.get(i)) is sorted. */ public static List order(List list, Comparator comparator) { - List ii = makeIndices(list.size()); - Collections.sort(ii, new Comparator() { - @Override public int compare(final Integer o1, final Integer o2) { - return comparator.compare((U) list.get(o1), (U) list.get(o2)); + List indices = makeIndices(list.size()); + Collections.sort(indices, new Comparator() { + @Override public int compare(final Integer a, final Integer b) { + return comparator.compare((U) list.get(a), (U) list.get(b)); } }); - return ii; + return indices; } } From f78298175140ba64e6e425d814703ea8c13b0bae Mon Sep 17 00:00:00 2001 From: Antal K Date: Mon, 23 Aug 2021 16:48:55 +0200 Subject: [PATCH 096/103] follow some PMD suggestions --- .../org/jabref/gui/openoffice/OOBibBase2.java | 57 ++++++------ .../org/jabref/gui/openoffice/OOError.java | 24 ++--- .../logic/openoffice/action/EditInsert.java | 4 +- .../logic/openoffice/action/EditMerge.java | 20 ++--- .../logic/openoffice/action/EditSeparate.java | 14 +-- .../logic/openoffice/action/ExportCited.java | 4 +- .../openoffice/action/ManageCitations.java | 8 +- .../logic/openoffice/action/Update.java | 22 ++--- .../logic/openoffice/backend/Backend52.java | 22 ++--- .../logic/openoffice/backend/Codec52.java | 26 +++--- .../backend/NamedRangeReferenceMark.java | 27 +++--- .../frontend/UpdateBibliography.java | 8 +- .../frontend/UpdateCitationMarkers.java | 28 +++--- .../logic/openoffice/style/OOBibStyle.java | 52 +++++------ .../style/OOBibStyleGetCitationMarker.java | 90 +++++++++---------- .../style/OOBibStyleGetNumCitationMarker.java | 62 ++++++------- .../style/OOFormatBibliography.java | 58 ++++++------ .../style/OOProcessAuthorYearMarkers.java | 4 +- .../model/openoffice/CitationEntry.java | 8 +- .../openoffice/style/CitationGroupId.java | 8 +- .../openoffice/style/CitationGroups.java | 5 +- .../model/openoffice/style/CitedKeys.java | 6 +- .../model/openoffice/style/PageInfo.java | 2 +- .../model/openoffice/uno/UnoCursor.java | 4 +- .../jabref/model/openoffice/uno/UnoStyle.java | 4 +- .../jabref/model/openoffice/uno/UnoUndo.java | 12 +-- .../uno/UnoUserDefinedProperty.java | 4 +- .../model/openoffice/util/OOListUtil.java | 16 ++-- 28 files changed, 295 insertions(+), 304 deletions(-) diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java index 9832adb991d..d8523f0cd77 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java @@ -151,12 +151,12 @@ public Optional getCurrentDocumentTitle() { * * ******************************************************/ - void showDialog(OOError ex) { - ex.showErrorDialog(dialogService); + void showDialog(OOError err) { + err.showErrorDialog(dialogService); } - void showDialog(String title, OOError ex) { - ex.setTitle(title).showErrorDialog(dialogService); + void showDialog(String title, OOError err) { + err.setTitle(title).showErrorDialog(dialogService); } OOVoidResult collectResults(String title, List> results) { @@ -185,8 +185,8 @@ boolean testDialog(String title, List> results) { @SafeVarargs final boolean testDialog(String title, OOVoidResult... results) { - List> rs = Arrays.asList(results); - return testDialog(collectResults(title, rs)); + List> resultList = Arrays.asList(results); + return testDialog(collectResults(title, resultList)); } /* @@ -232,16 +232,16 @@ OOResult getFunctionalTextViewCursor(XTextDoc return result.mapError(detail -> new OOError(title, messageOnFailureToObtain)); } - private static OOVoidResult checkRangeOverlaps(XTextDocument doc, OOFrontend fr) { + private static OOVoidResult checkRangeOverlaps(XTextDocument doc, OOFrontend frontend) { final String title = "checkRangeOverlaps"; boolean requireSeparation = false; int maxReportedOverlaps = 10; try { - return (fr.checkRangeOverlaps(doc, - new ArrayList<>(), - requireSeparation, - maxReportedOverlaps) - .mapError(OOError::from)); + return (frontend.checkRangeOverlaps(doc, + new ArrayList<>(), + requireSeparation, + maxReportedOverlaps) + .mapError(OOError::from)); } catch (NoDocumentException ex) { return OOVoidResult.error(OOError.from(ex).setTitle(title)); } catch (WrappedTargetException ex) { @@ -249,18 +249,18 @@ private static OOVoidResult checkRangeOverlaps(XTextDocument doc, OOFro } } - private static OOVoidResult checkRangeOverlapsWithCursor(XTextDocument doc, OOFrontend fr) { + private static OOVoidResult checkRangeOverlapsWithCursor(XTextDocument doc, OOFrontend frontend) { final String title = "checkRangeOverlapsWithCursor"; List> userRanges; - userRanges = fr.viewCursorRanges(doc); + userRanges = frontend.viewCursorRanges(doc); boolean requireSeparation = false; OOVoidResult res; try { - res = fr.checkRangeOverlapsWithCursor(doc, - userRanges, - requireSeparation); + res = frontend.checkRangeOverlapsWithCursor(doc, + userRanges, + requireSeparation); } catch (NoDocumentException ex) { return OOVoidResult.error(OOError.from(ex).setTitle(title)); } catch (WrappedTargetException ex) { @@ -588,18 +588,17 @@ public void guiActionInsertEntry(List entries, } XTextDocument doc = odoc.get(); - OOResult ofr = getFrontend(doc); - if (testDialog(title, ofr.asVoidResult())) { + OOResult frontend = getFrontend(doc); + if (testDialog(title, frontend.asVoidResult())) { return; } - OOFrontend fr = ofr.get(); OOResult cursor = getUserCursorForTextInsertion(doc, title); if (testDialog(title, cursor.asVoidResult())) { return; } - if (testDialog(title, checkRangeOverlapsWithCursor(doc, fr))) { + if (testDialog(title, checkRangeOverlapsWithCursor(doc, frontend.get()))) { return; } @@ -635,7 +634,7 @@ public void guiActionInsertEntry(List entries, UnoUndo.enterUndoContext(doc, "Insert citation"); EditInsert.insertCitationGroup(doc, - fr, + frontend.get(), cursor.get(), entries, database, @@ -695,8 +694,8 @@ public void guiActionMergeCitationGroups(List databases, OOBibStyle try { UnoUndo.enterUndoContext(doc, "Merge citations"); - OOFrontend fr = new OOFrontend(doc); - boolean madeModifications = EditMerge.mergeCitationGroups(doc, fr, style); + OOFrontend frontend = new OOFrontend(doc); + boolean madeModifications = EditMerge.mergeCitationGroups(doc, frontend, style); if (madeModifications) { UnoCrossRef.refresh(doc); Update.SyncOptions syncOptions = new Update.SyncOptions(databases); @@ -752,8 +751,8 @@ public void guiActionSeparateCitations(List databases, OOBibStyle s try { UnoUndo.enterUndoContext(doc, "Separate citations"); - OOFrontend fr = new OOFrontend(doc); - boolean madeModifications = EditSeparate.separateCitations(doc, fr, databases, style); + OOFrontend frontend = new OOFrontend(doc); + boolean madeModifications = EditSeparate.separateCitations(doc, frontend, databases, style); if (madeModifications) { UnoCrossRef.refresh(doc); Update.SyncOptions syncOptions = new Update.SyncOptions(databases); @@ -881,8 +880,8 @@ public void guiActionUpdateDocument(List databases, OOBibStyle styl return; } - OOFrontend fr = new OOFrontend(doc); - if (testDialog(title, checkRangeOverlaps(doc, fr))) { + OOFrontend frontend = new OOFrontend(doc); + if (testDialog(title, checkRangeOverlaps(doc, frontend))) { return; } @@ -895,7 +894,7 @@ public void guiActionUpdateDocument(List databases, OOBibStyle styl .setUpdateBibliography(true) .setAlwaysAddCitedOnPages(this.alwaysAddCitedOnPages); - unresolvedKeys = Update.synchronizeDocument(doc, fr, style, fcursor.get(), syncOptions); + unresolvedKeys = Update.synchronizeDocument(doc, frontend, style, fcursor.get(), syncOptions); } finally { UnoUndo.leaveUndoContext(doc); diff --git a/src/main/java/org/jabref/gui/openoffice/OOError.java b/src/main/java/org/jabref/gui/openoffice/OOError.java index 44e70b3e975..b296ffe30c0 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOError.java +++ b/src/main/java/org/jabref/gui/openoffice/OOError.java @@ -39,50 +39,50 @@ public void showErrorDialog(DialogService dialogService) { * Conversions from exception caught */ - public static OOError from(JabRefException ex) { + public static OOError from(JabRefException err) { return new OOError( Localization.lang("JabRefException"), - ex.getLocalizedMessage(), - ex); + err.getLocalizedMessage(), + err); } // For DisposedException - public static OOError from(DisposedException ex) { + public static OOError from(DisposedException err) { return new OOError( Localization.lang("Connection lost"), Localization.lang("Connection to OpenOffice/LibreOffice has been lost." + " Please make sure OpenOffice/LibreOffice is running," + " and try to reconnect."), - ex); + err); } // For NoDocumentException - public static OOError from(NoDocumentException ex) { + public static OOError from(NoDocumentException err) { return new OOError( Localization.lang("Not connected to document"), Localization.lang("Not connected to any Writer document." + " Please make sure a document is open," + " and use the 'Select Writer document' button" + " to connect to it."), - ex); + err); } // For NoDocumentFoundException - public static OOError from(NoDocumentFoundException ex) { + public static OOError from(NoDocumentFoundException err) { return new OOError( Localization.lang("No Writer documents found"), Localization.lang("Could not connect to any Writer document." + " Please make sure a document is open" + " before using the 'Select Writer document' button" + " to connect to it."), - ex); + err); } - public static OOError fromMisc(Exception ex) { + public static OOError fromMisc(Exception err) { return new OOError( "Exception", - ex.getMessage(), - ex); + err.getMessage(), + err); } /* diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java index 81491bd8590..375d3c1637a 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java @@ -56,7 +56,7 @@ private static String insertEntryGetCitationKey(BibEntry entry) { * @param pageInfo A single pageInfo for a list of entries. This is what we get from the GUI. */ public static void insertCitationGroup(XTextDocument doc, - OOFrontend fr, + OOFrontend frontend, XTextCursor cursor, List entries, BibDatabase database, @@ -98,7 +98,7 @@ public static void insertCitationGroup(XTextDocument doc, try { UnoScreenRefresh.lockControllers(doc); - UpdateCitationMarkers.createAndFillCitationGroup(fr, + UpdateCitationMarkers.createAndFillCitationGroup(frontend, doc, citationKeys, pageInfos, diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java index 43bdcd59e2d..6fa19e2d344 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java @@ -40,7 +40,7 @@ private EditMerge() { /* * @return true if modified document */ - public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend fr, OOBibStyle style) + public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend frontend, OOBibStyle style) throws CreationException, IllegalArgumentException, @@ -50,12 +50,12 @@ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend fr, OOBi PropertyVetoException, WrappedTargetException { - boolean madeModifications = false; + boolean madeModifications; try { UnoScreenRefresh.lockControllers(doc); - List joinableGroups = EditMerge.scan(doc, fr); + List joinableGroups = EditMerge.scan(doc, frontend); for (JoinableGroupData joinableGroupData : joinableGroups) { @@ -66,9 +66,9 @@ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend fr, OOBi .collect(Collectors.toList())); CitationType citationType = cgs.get(0).citationType; - List> pageInfos = fr.backend.combinePageInfos(cgs); + List> pageInfos = frontend.backend.combinePageInfos(cgs); - fr.removeCitationGroups(cgs, doc); + frontend.removeCitationGroups(cgs, doc); XTextCursor textCursor = joinableGroupData.groupCursor; textCursor.setString(""); // Also remove the spaces between. @@ -76,7 +76,7 @@ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend fr, OOBi /* insertSpaceAfter: no, it is already there (or could be) */ boolean insertSpaceAfter = false; - UpdateCitationMarkers.createAndFillCitationGroup(fr, + UpdateCitationMarkers.createAndFillCitationGroup(frontend, doc, citationKeys, pageInfos, @@ -226,7 +226,7 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup group, XTe couldExpand = thisCharCursor.goRight((short) 1, true); String thisChar = thisCharCursor.getString(); thisCharCursor.collapseToEnd(); - if (thisChar.isEmpty() || thisChar.equals("\n") || !thisChar.trim().isEmpty()) { + if (thisChar.isEmpty() || "\n".equals(thisChar) || !thisChar.trim().isEmpty()) { couldExpand = false; if (!thisChar.isEmpty()) { thisCharCursor.goLeft((short) 1, false); @@ -290,13 +290,13 @@ private static void addToCurrentGroup(ScanState state, CitationGroup group, XTex /** * Scan the document for joinable groups. Return those found. */ - private static List scan(XTextDocument doc, OOFrontend fr) + private static List scan(XTextDocument doc, OOFrontend frontend) throws NoDocumentException, WrappedTargetException { List result = new ArrayList<>(); - List cgs = fr.getCitationGroupsSortedWithinPartitions(doc, false /* mapFootnotesToFootnoteMarks */); + List cgs = frontend.getCitationGroupsSortedWithinPartitions(doc, false /* mapFootnotesToFootnoteMarks */); if (cgs.isEmpty()) { return result; } @@ -305,7 +305,7 @@ private static List scan(XTextDocument doc, OOFrontend fr) for (CitationGroup group : cgs) { - XTextRange currentRange = (fr.getMarkRange(doc, group) + XTextRange currentRange = (frontend.getMarkRange(doc, group) .orElseThrow(IllegalStateException::new)); /* diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java index fba50a93c6e..409969b213f 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java @@ -29,7 +29,7 @@ private EditSeparate() { } public static boolean separateCitations(XTextDocument doc, - OOFrontend fr, + OOFrontend frontend, List databases, OOBibStyle style) throws @@ -47,17 +47,17 @@ public static boolean separateCitations(XTextDocument doc, // decide the visually last Citation in the group. Unless the // style changed since refresh this is the last on the screen // as well. - fr.citationGroups.lookupCitations(databases); - fr.citationGroups.imposeLocalOrder(OOProcess.comparatorForMulticite(style)); + frontend.citationGroups.lookupCitations(databases); + frontend.citationGroups.imposeLocalOrder(OOProcess.comparatorForMulticite(style)); - List cgs = fr.citationGroups.getCitationGroupsUnordered(); + List cgs = frontend.citationGroups.getCitationGroupsUnordered(); try { UnoScreenRefresh.lockControllers(doc); for (CitationGroup group : cgs) { - XTextRange range1 = (fr + XTextRange range1 = (frontend .getMarkRange(doc, group) .orElseThrow(IllegalStateException::new)); XTextCursor textCursor = range1.getText().createTextCursorByRange(range1); @@ -67,7 +67,7 @@ public static boolean separateCitations(XTextDocument doc, continue; } - fr.removeCitationGroup(group, doc); + frontend.removeCitationGroup(group, doc); // Now we own the content of cits // Create a citation group for each citation. @@ -76,7 +76,7 @@ public static boolean separateCitations(XTextDocument doc, boolean insertSpaceAfter = (i != last); Citation cit = cits.get(i); - UpdateCitationMarkers.createAndFillCitationGroup(fr, + UpdateCitationMarkers.createAndFillCitationGroup(frontend, doc, List.of(cit.citationKey), List.of(cit.getPageInfo()), diff --git a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java index 26ed654de21..ba806426051 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java +++ b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java @@ -51,8 +51,8 @@ public static GenerateDatabaseResult generateDatabase(XTextDocument doc, List unresolvedKeys = new ArrayList<>(); diff --git a/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java b/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java index 9782261f612..c8234df9ca0 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java +++ b/src/main/java/org/jabref/logic/openoffice/action/ManageCitations.java @@ -21,8 +21,8 @@ public static List getCitationEntries(XTextDocument doc) throws NoDocumentException, WrappedTargetException { - OOFrontend fr = new OOFrontend(doc); - return fr.getCitationEntries(doc); + OOFrontend frontend = new OOFrontend(doc); + return frontend.getCitationEntries(doc); } public static void applyCitationEntries(XTextDocument doc, List citationEntries) @@ -32,7 +32,7 @@ public static void applyCitationEntries(XTextDocument doc, List c IllegalTypeException, WrappedTargetException, IllegalArgumentException { - OOFrontend fr = new OOFrontend(doc); - fr.applyCitationEntries(doc, citationEntries); + OOFrontend frontend = new OOFrontend(doc); + frontend.applyCitationEntries(doc, citationEntries); } } diff --git a/src/main/java/org/jabref/logic/openoffice/action/Update.java b/src/main/java/org/jabref/logic/openoffice/action/Update.java index 49f79d6d2e7..ba840e88b70 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/Update.java +++ b/src/main/java/org/jabref/logic/openoffice/action/Update.java @@ -29,7 +29,7 @@ private Update() { * @return the list of unresolved citation keys */ private static List updateDocument(XTextDocument doc, - OOFrontend fr, + OOFrontend frontend, List databases, OOBibStyle style, FunctionalTextViewCursor fcursor, @@ -43,25 +43,25 @@ private static List updateDocument(XTextDocument doc, final boolean useLockControllers = true; - fr.imposeGlobalOrder(doc, fcursor); - OOProcess.produceCitationMarkers(fr.citationGroups, databases, style); + frontend.imposeGlobalOrder(doc, fcursor); + OOProcess.produceCitationMarkers(frontend.citationGroups, databases, style); try { if (useLockControllers) { UnoScreenRefresh.lockControllers(doc); } - UpdateCitationMarkers.applyNewCitationMarkers(doc, fr, style); + UpdateCitationMarkers.applyNewCitationMarkers(doc, frontend, style); if (doUpdateBibliography) { UpdateBibliography.rebuildBibTextSection(doc, - fr, - fr.citationGroups.getBibliography().get(), + frontend, + frontend.citationGroups.getBibliography().get(), style, alwaysAddCitedOnPages); } - return fr.citationGroups.getUnresolvedKeys(); + return frontend.citationGroups.getUnresolvedKeys(); } finally { if (useLockControllers && UnoScreenRefresh.hasControllersLocked(doc)) { UnoScreenRefresh.unlockControllers(doc); @@ -93,7 +93,7 @@ public SyncOptions setAlwaysAddCitedOnPages(boolean value) { } public static List synchronizeDocument(XTextDocument doc, - OOFrontend fr, + OOFrontend frontend, OOBibStyle style, FunctionalTextViewCursor fcursor, SyncOptions syncOptions) @@ -104,7 +104,7 @@ public static List synchronizeDocument(XTextDocument doc, com.sun.star.lang.IllegalArgumentException { return Update.updateDocument(doc, - fr, + frontend, syncOptions.databases, style, fcursor, @@ -125,9 +125,9 @@ public static List resyncDocument(XTextDocument doc, WrappedTargetException, com.sun.star.lang.IllegalArgumentException { - OOFrontend fr = new OOFrontend(doc); + OOFrontend frontend = new OOFrontend(doc); - return Update.synchronizeDocument(doc, fr, style, fcursor, syncOptions); + return Update.synchronizeDocument(doc, frontend, style, fcursor, syncOptions); } } diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java index 0016e5e4510..4a0d8d05e0e 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java @@ -196,17 +196,6 @@ public CitationGroup createCitationGroup(XTextDocument doc, throw new IllegalArgumentException(); } - /* - * Backend52 uses reference marks to (1) mark the location of the citation in the text and (2) to encode - * the citation keys and citation type in the name of the reference mark. The name of the reference mark - * has to be unique in the document. - */ - String markName = Codec52.getUniqueMarkName(new HashSet<>(citationStorageManager.getUsedNames(doc)), - citationKeys, - citationType); - - CitationGroupId groupId = new CitationGroupId(markName); - final int numberOfCitations = citationKeys.size(); final int last = numberOfCitations - 1; @@ -236,6 +225,17 @@ public CitationGroup createCitationGroup(XTextDocument doc, } } + /* + * Backend52 uses reference marks to (1) mark the location of the citation in the text and (2) to encode + * the citation keys and citation type in the name of the reference mark. The name of the reference mark + * has to be unique in the document. + */ + final String markName = Codec52.getUniqueMarkName(new HashSet<>(citationStorageManager.getUsedNames(doc)), + citationKeys, + citationType); + + final CitationGroupId groupId = new CitationGroupId(markName); + /* * Apply to document */ diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java index f567a3e459e..45f3bd3ca04 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java @@ -32,16 +32,16 @@ private Codec52() { */ public static class ParsedMarkName { /** "", "0", "1" ... */ - public final String i; + public final String index; /** in-text-citation type */ public final CitationType citationType; /** Citation keys embedded in the reference mark. */ public final List citationKeys; - ParsedMarkName(String i, CitationType citationType, List citationKeys) { - Objects.requireNonNull(i); + ParsedMarkName(String index, CitationType citationType, List citationKeys) { + Objects.requireNonNull(index); Objects.requireNonNull(citationKeys); - this.i = i; + this.index = index; this.citationType = citationType; this.citationKeys = citationKeys; } @@ -50,8 +50,8 @@ public static class ParsedMarkName { /** * Integer representation was written into the document in JabRef52, keep it for compatibility. */ - private static CitationType citationTypeFromInt(int i) { - return switch (i) { + private static CitationType citationTypeFromInt(int code) { + return switch (code) { case 1 -> CitationType.AUTHORYEAR_PAR; case 2 -> CitationType.AUTHORYEAR_INTEXT; case 3 -> CitationType.INVISIBLE_CIT; @@ -59,8 +59,8 @@ private static CitationType citationTypeFromInt(int i) { }; } - private static int citationTypeToInt(CitationType i) { - return switch (i) { + private static int citationTypeToInt(CitationType type) { + return switch (type) { case AUTHORYEAR_PAR -> 1; case AUTHORYEAR_INTEXT -> 2; case INVISIBLE_CIT -> 3; @@ -86,12 +86,12 @@ public static String getUniqueMarkName(Set usedNames, String citationKeysPart = String.join(",", citationKeys); - int i = 0; + int index = 0; int citTypeCode = citationTypeToInt(citationType); String name = BIB_CITATION + '_' + citTypeCode + '_' + citationKeysPart; while (usedNames.contains(name)) { - name = BIB_CITATION + i + '_' + citTypeCode + '_' + citationKeysPart; - i++; + name = BIB_CITATION + index + '_' + citTypeCode + '_' + citationKeysPart; + index++; } return name; } @@ -110,10 +110,10 @@ public static Optional parseMarkName(String refMarkName) { } List keys = Arrays.asList(citeMatcher.group(3).split(",")); - String i = citeMatcher.group(1); + String index = citeMatcher.group(1); int citTypeCode = Integer.parseInt(citeMatcher.group(2)); CitationType citationType = citationTypeFromInt(citTypeCode); - return (Optional.of(new Codec52.ParsedMarkName(i, citationType, keys))); + return (Optional.of(new Codec52.ParsedMarkName(index, citationType, keys))); } /** 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 cfabb1e2de0..324b984377c 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java @@ -35,14 +35,14 @@ class NamedRangeReferenceMark implements NamedRange { private static final Logger LOGGER = LoggerFactory.getLogger(NamedRangeReferenceMark.class); - private String id; /* reference mark name */ + private String rangeId; /* reference mark name */ - private NamedRangeReferenceMark(String id) { - this.id = id; + private NamedRangeReferenceMark(String rangeId) { + this.rangeId = rangeId; } String getId() { - return id; + return rangeId; } /** @@ -156,7 +156,7 @@ public void removeFromDocument(XTextDocument doc) @Override public String getRangeName() { - return id; + return rangeId; } /** @@ -217,8 +217,6 @@ public XTextCursor getFillCursor(XTextDocument doc) String name = this.getRangeName(); - final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; - final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; final boolean debugThisFun = false; XTextCursor full = null; @@ -279,6 +277,8 @@ public XTextCursor getFillCursor(XTextDocument doc) beta.goRight((short) (fullText.length() - 2), true); LOGGER.debug("getFillCursor: beta(1) covers '{}'", beta.getString()); + final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; + final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; final short rightLength = (short) right.length(); if (fullText.startsWith(left) && fullText.endsWith(right)) { beta.setString(""); @@ -345,7 +345,6 @@ public XTextCursor getFillCursor(XTextDocument doc) */ public static void checkFillCursor(XTextCursor cursor) { final String left = REFERENCE_MARK_LEFT_BRACKET; - final String right = REFERENCE_MARK_RIGHT_BRACKET; XTextCursor alpha = cursor.getText().createTextCursorByRange(cursor); alpha.collapseToStart(); @@ -364,6 +363,7 @@ public static void checkFillCursor(XTextCursor cursor) { } } + final String right = REFERENCE_MARK_RIGHT_BRACKET; final short rightLength = (short) right.length(); if (rightLength > 0) { omega.goRight(rightLength, true); @@ -395,27 +395,26 @@ public void cleanFillCursor(XTextDocument doc) // removeBracketsFromEmpty is intended to force removal if we are working on an "Empty citation" (INVISIBLE_CIT). final boolean removeBracketsFromEmpty = false; - final String left = REFERENCE_MARK_LEFT_BRACKET; - final String right = REFERENCE_MARK_RIGHT_BRACKET; - final short leftLength = (short) left.length(); - final short rightLength = (short) right.length(); - String name = this.getRangeName(); XTextCursor full = this.getRawCursor(doc).orElseThrow(IllegalStateException::new); final String fullText = full.getString(); - final int fullTextLength = fullText.length(); + final String left = REFERENCE_MARK_LEFT_BRACKET; if (!fullText.startsWith(left)) { String msg = String.format("cleanFillCursor: (%s) does not start with REFERENCE_MARK_LEFT_BRACKET", name); throw new IllegalStateException(msg); } + final String right = REFERENCE_MARK_RIGHT_BRACKET; if (!fullText.endsWith(right)) { String msg = String.format("cleanFillCursor: (%s) does not end with REFERENCE_MARK_RIGHT_BRACKET", name); throw new IllegalStateException(msg); } + final int fullTextLength = fullText.length(); + final short leftLength = (short) left.length(); + final short rightLength = (short) right.length(); final int contentLength = (fullTextLength - (leftLength + rightLength)); if (contentLength < 0) { String msg = String.format("cleanFillCursor: length(%s) < 0", name); 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 f7b3d14def6..ebda8359ba5 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java @@ -40,7 +40,7 @@ public static Optional getBibliographyRange(XTextDocument doc) * Rebuilds the bibliography. */ public static void rebuildBibTextSection(XTextDocument doc, - OOFrontend fr, + OOFrontend frontend, CitedKeys bibliography, OOBibStyle style, boolean alwaysAddCitedOnPages) @@ -52,7 +52,7 @@ public static void rebuildBibTextSection(XTextDocument doc, clearBibTextSectionContent2(doc); populateBibTextSection(doc, - fr, + frontend, bibliography, style, alwaysAddCitedOnPages); @@ -105,7 +105,7 @@ private static void clearBibTextSectionContent2(XTextDocument doc) * Assumes the section named BIB_SECTION_NAME exists. */ private static void populateBibTextSection(XTextDocument doc, - OOFrontend fr, + OOFrontend frontend, CitedKeys bibliography, OOBibStyle style, boolean alwaysAddCitedOnPages) @@ -121,7 +121,7 @@ private static void populateBibTextSection(XTextDocument doc, // emit the title of the bibliography OOTextIntoOO.removeDirectFormatting(cursor); - OOText bibliographyText = OOFormatBibliography.formatBibliography(fr.citationGroups, + OOText bibliographyText = OOFormatBibliography.formatBibliography(frontend.citationGroups, bibliography, style, alwaysAddCitedOnPages); diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java index 55f04775094..834fce1d0ce 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java @@ -40,18 +40,18 @@ private UpdateCitationMarkers() { * After each fillCitationMarkInCursor call check if we lost the * BIB_SECTION_NAME bookmark and recreate it if we did. * - * @param fr + * @param frontend * * @param style Bibliography style to use. * */ - public static void applyNewCitationMarkers(XTextDocument doc, OOFrontend fr, OOBibStyle style) + public static void applyNewCitationMarkers(XTextDocument doc, OOFrontend frontend, OOBibStyle style) throws NoDocumentException, CreationException, WrappedTargetException { - CitationGroups citationGroups = fr.citationGroups; + CitationGroups citationGroups = frontend.citationGroups; for (CitationGroup group : citationGroups.getCitationGroupsUnordered()) { @@ -66,11 +66,11 @@ public static void applyNewCitationMarkers(XTextDocument doc, OOFrontend fr, OOB if (withText && marker.isPresent()) { - XTextCursor cursor = fr.getFillCursorForCitationGroup(doc, group); + XTextCursor cursor = frontend.getFillCursorForCitationGroup(doc, group); fillCitationMarkInCursor(doc, cursor, marker.get(), withText, style); - fr.cleanFillCursorForCitationGroup(doc, group); + frontend.cleanFillCursorForCitationGroup(doc, group); } } @@ -118,7 +118,7 @@ public static void fillCitationMarkInCursor(XTextDocument doc, * coming after. But is not wanted when we recreate a * reference mark. */ - public static void createAndFillCitationGroup(OOFrontend fr, + public static void createAndFillCitationGroup(OOFrontend frontend, XTextDocument doc, List citationKeys, List> pageInfos, @@ -140,21 +140,21 @@ public static void createAndFillCitationGroup(OOFrontend fr, if (pageInfos.size() != citationKeys.size()) { throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); } - CitationGroup group = fr.createCitationGroup(doc, - citationKeys, - pageInfos, - citationType, - position, - insertSpaceAfter); + CitationGroup group = frontend.createCitationGroup(doc, + citationKeys, + pageInfos, + citationType, + position, + insertSpaceAfter); final boolean withText = citationType.withText(); if (withText) { - XTextCursor fillCursor = fr.getFillCursorForCitationGroup(doc, group); + XTextCursor fillCursor = frontend.getFillCursorForCitationGroup(doc, group); UpdateCitationMarkers.fillCitationMarkInCursor(doc, fillCursor, citationText, withText, style); - fr.cleanFillCursorForCitationGroup(doc, group); + frontend.cleanFillCursorForCitationGroup(doc, group); } position.collapseToEnd(); } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index b155dd44dc7..195ddc25410 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -284,20 +284,20 @@ private boolean isUpToDate() { } } - private void readFormatFile(Reader in) throws IOException { + private void readFormatFile(Reader input) throws IOException { // First read all the contents of the file: - StringBuilder sb = new StringBuilder(); - int c; - while ((c = in.read()) != -1) { - sb.append((char) c); + StringBuilder stringBuilder = new StringBuilder(); + int chr; + while ((chr = input.read()) != -1) { + stringBuilder.append((char) chr); } // Store a local copy for viewing - localCopy = sb.toString(); + localCopy = stringBuilder.toString(); // Break into separate lines: - String[] lines = sb.toString().split("\n"); + String[] lines = stringBuilder.toString().split("\n"); BibStyleMode mode = BibStyleMode.NONE; for (String line1 : lines) { @@ -379,11 +379,12 @@ private void handleStructureLine(String line) { if ((index > 0) && (index < (line.length() - 1))) { try { - String formatString = line.substring(index + 1); + final String typeName = line.substring(0, index); + final String formatString = line.substring(index + 1); Layout layout = new LayoutHelper(new StringReader(formatString), this.prefs).getLayoutFromText(); - EntryType type = EntryTypeFactory.parse(line.substring(0, index)); + EntryType type = EntryTypeFactory.parse(typeName); - if (!isDefaultLayoutPresent && line.substring(0, index).equals(OOBibStyle.DEFAULT_MARK)) { + if (!isDefaultLayoutPresent && OOBibStyle.DEFAULT_MARK.equals(typeName)) { isDefaultLayoutPresent = true; defaultBibLayout = layout; } else { @@ -430,11 +431,11 @@ private void handleJournalsLine(String line) { } public Layout getReferenceFormat(EntryType type) { - Layout l = bibLayout.get(type); - if (l == null) { + Layout layout = bibLayout.get(type); + if (layout == null) { return defaultBibLayout; } else { - return l; + return layout; } } @@ -544,12 +545,12 @@ public int compareTo(OOBibStyle other) { } @Override - public boolean equals(Object o) { - if (this == o) { + public boolean equals(Object object) { + if (this == object) { return true; } - if (o instanceof OOBibStyle) { - OOBibStyle otherStyle = (OOBibStyle) o; + if (object instanceof OOBibStyle) { + OOBibStyle otherStyle = (OOBibStyle) object; return Objects.equals(path, otherStyle.path) && Objects.equals(name, otherStyle.name) && Objects.equals(citProperties, otherStyle.citProperties) @@ -693,8 +694,8 @@ public OOText getNumCitationMarkerForBibliography(CitationMarkerNumericBibEntry return OOBibStyleGetNumCitationMarker.getNumCitationMarkerForBibliography(this, entry); } - public OOText getNormalizedCitationMarker(CitationMarkerNormEntry ce) { - return OOBibStyleGetCitationMarker.getNormalizedCitationMarker(this, ce, Optional.empty()); + public OOText getNormalizedCitationMarker(CitationMarkerNormEntry entry) { + return OOBibStyleGetCitationMarker.getNormalizedCitationMarker(this, entry, Optional.empty()); } /** @@ -773,10 +774,6 @@ public String getGroupedNumbersSeparator() { return getStringCitProperty(OOBibStyle.GROUPED_NUMBERS_SEPARATOR); } - private boolean getBooleanProperty(String propName) { - return (Boolean) properties.get(propName); - } - private String getStringProperty(String propName) { return (String) properties.get(propName); } @@ -923,12 +920,9 @@ public OOText getFormattedBibliographyTitle() { OOBibStyle style = this; OOText title = style.getReferenceHeaderText(); String parStyle = style.getReferenceHeaderParagraphFormat(); - if (parStyle != null) { - title = OOFormat.paragraph(title, parStyle); - } else { - title = OOFormat.paragraph(title); - } - return title; + return (parStyle == null + ? OOFormat.paragraph(title) + : OOFormat.paragraph(title, parStyle)); } } 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 deb1a306913..2e5227d080e 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java @@ -38,21 +38,21 @@ private OOBibStyleGetCitationMarker() { * @return The author name, or an empty String if inapplicable. */ private static String getAuthorLastName(AuthorList authorList, int number) { - StringBuilder sb = new StringBuilder(); + StringBuilder stringBuilder = new StringBuilder(); if (authorList.getNumberOfAuthors() > number) { Author author = authorList.getAuthor(number); // "von " if von exists Optional von = author.getVon(); if (von.isPresent() && !von.get().isEmpty()) { - sb.append(von.get()); - sb.append(' '); + stringBuilder.append(von.get()); + stringBuilder.append(' '); } // last name if it exists - sb.append(author.getLast().orElse("")); + stringBuilder.append(author.getLast().orElse("")); } - return sb.toString(); + return stringBuilder.toString(); } private static String markupAuthorName(OOBibStyle style, String name) { @@ -127,7 +127,7 @@ private static String formatAuthorList(OOBibStyle style, // of three or more authors: (A, B[,] and C) String oxfordComma = style.getOxfordComma(); - StringBuilder sb = new StringBuilder(); + StringBuilder stringBuilder = new StringBuilder(); final int nAuthors = authorList.getNumberOfAuthors(); @@ -149,11 +149,11 @@ private static String formatAuthorList(OOBibStyle style, : Math.min(maxAuthorsBeforeEtAl, nAuthors)); if (nAuthorsToEmit >= 1) { - sb.append(style.getAuthorsPartMarkupBefore()); - sb.append(style.getAuthorNamesListMarkupBefore()); + stringBuilder.append(style.getAuthorsPartMarkupBefore()); + stringBuilder.append(style.getAuthorNamesListMarkupBefore()); // The first author String name = getAuthorLastName(authorList, 0); - sb.append(markupAuthorName(style, name)); + stringBuilder.append(markupAuthorName(style, name)); } if (nAuthors >= 2) { @@ -162,19 +162,19 @@ private static String formatAuthorList(OOBibStyle style, // Emit last names, except for the last author int j = 1; while (j < (nAuthors - 1)) { - sb.append(authorSep); + stringBuilder.append(authorSep); String name = getAuthorLastName(authorList, j); - sb.append(markupAuthorName(style, name)); + stringBuilder.append(markupAuthorName(style, name)); j++; } // oxfordComma if at least 3 authors if (nAuthors >= 3) { - sb.append(oxfordComma); + stringBuilder.append(oxfordComma); } // Emit " and "+"LastAuthor" - sb.append(andString); + stringBuilder.append(andString); String name = getAuthorLastName(authorList, nAuthors - 1); - sb.append(markupAuthorName(style, name)); + stringBuilder.append(markupAuthorName(style, name)); } else { // Emit last names up to nAuthorsToEmit. @@ -185,9 +185,9 @@ private static String formatAuthorList(OOBibStyle style, if (maxAuthorsBeforeEtAl > 1) { int j = 1; while (j < nAuthorsToEmit) { - sb.append(authorSep); + stringBuilder.append(authorSep); String name = getAuthorLastName(authorList, j); - sb.append(markupAuthorName(style, name)); + stringBuilder.append(markupAuthorName(style, name)); j++; } } @@ -195,15 +195,15 @@ private static String formatAuthorList(OOBibStyle style, } if (nAuthorsToEmit >= 1) { - sb.append(style.getAuthorNamesListMarkupAfter()); + stringBuilder.append(style.getAuthorNamesListMarkupAfter()); } if (nAuthors >= 2 && !emitAllAuthors) { - sb.append(etAlString); + stringBuilder.append(etAlString); } - sb.append(style.getAuthorsPartMarkupAfter()); - return sb.toString(); + stringBuilder.append(style.getAuthorsPartMarkupAfter()); + return stringBuilder.toString(); } /** @@ -279,15 +279,15 @@ private static String getCitationMarkerField(OOBibStyle style, return ""; } - FieldAndContent fc = optionalFieldAndContent.get(); - String result = style.getFieldFormatter().format(fc.content); + FieldAndContent fieldAndContent = optionalFieldAndContent.get(); + String result = style.getFieldFormatter().format(fieldAndContent.content); // If the field we found is mentioned in authorFieldNames and // content has a pair of braces around it, we add a pair of // braces around the result, so that AuthorList.parse does not split // the content. final OrFields fieldsToRebrace = style.getAuthorFieldNames(); - if (fieldsToRebrace.contains(fc.field) && StringUtil.isInCurlyBrackets(fc.content)) { + if (fieldsToRebrace.contains(fieldAndContent.field) && StringUtil.isInCurlyBrackets(fieldAndContent.content)) { result = "{" + result + "}"; } return result; @@ -406,11 +406,11 @@ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, String pageInfoSeparator = style.getPageInfoSeparator(); String uniquefierSeparator = style.getUniquefierSeparator(); - StringBuilder sb = new StringBuilder(); - sb.append(style.getCitationGroupMarkupBefore()); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(style.getCitationGroupMarkupBefore()); if (inParenthesis) { - sb.append(startBrace); // shared parenthesis + stringBuilder.append(startBrace); // shared parenthesis } for (int j = 0; j < entries.size(); j++) { @@ -422,19 +422,19 @@ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, // Just add our uniqueLetter String uniqueLetter = entry.getUniqueLetter().orElse(null); if (uniqueLetter != null) { - sb.append(uniquefierSeparator); - sb.append(uniqueLetter); + stringBuilder.append(uniquefierSeparator); + stringBuilder.append(uniqueLetter); } // And close the brace, if we are the last in the group. if (!inParenthesis && endingAGroup) { - sb.append(endBrace); + stringBuilder.append(endBrace); } continue; } if (j > 0) { - sb.append(citationSeparator); + stringBuilder.append(citationSeparator); } StringBuilder pageInfoPart = new StringBuilder(""); @@ -449,9 +449,9 @@ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, final boolean isUnresolved = entry.getLookupResult().isEmpty(); if (isUnresolved) { - sb.append(String.format("Unresolved(%s)", entry.getCitationKey())); + stringBuilder.append(String.format("Unresolved(%s)", entry.getCitationKey())); if (purpose != AuthorYearMarkerPurpose.NORMALIZED) { - sb.append(pageInfoPart); + stringBuilder.append(pageInfoPart); } } else { @@ -467,40 +467,40 @@ private static OOText getAuthorYearParenthesisMarker2(OOBibStyle style, AuthorList authorList = getAuthorList(style, db); String authorString = formatAuthorList(style, authorList, maxAuthors, andString); - sb.append(authorString); - sb.append(yearSep); + stringBuilder.append(authorString); + stringBuilder.append(yearSep); if (!inParenthesis) { - sb.append(startBrace); // parenthesis before year + stringBuilder.append(startBrace); // parenthesis before year } String year = getCitationMarkerField(style, db, yearFieldNames); if (year != null) { - sb.append(year); + stringBuilder.append(year); } if (purpose != AuthorYearMarkerPurpose.NORMALIZED) { String uniqueLetter = entry.getUniqueLetter().orElse(null); if (uniqueLetter != null) { - sb.append(uniqueLetter); + stringBuilder.append(uniqueLetter); } } if (purpose != AuthorYearMarkerPurpose.NORMALIZED) { - sb.append(pageInfoPart); + stringBuilder.append(pageInfoPart); } if (!inParenthesis && endingAGroup) { - sb.append(endBrace); // parenthesis after year + stringBuilder.append(endBrace); // parenthesis after year } } } // for j if (inParenthesis) { - sb.append(endBrace); // shared parenthesis + stringBuilder.append(endBrace); // shared parenthesis } - sb.append(style.getCitationGroupMarkupAfter()); - return OOText.fromString(sb.toString()); + stringBuilder.append(style.getCitationGroupMarkupAfter()); + return OOText.fromString(stringBuilder.toString()); } /** @@ -638,9 +638,9 @@ static OOText getNormalizedCitationMarker(OOBibStyle style, int[] nAuthorsToEmitRevised = new int[nEntries]; for (int i = 0; i < nEntries; i++) { CitationMarkerEntry entry = citationMarkerEntries.get(i); - int n = calculateNAuthorsToEmit(style, entry); - nAuthorsToEmit[i] = n; - nAuthorsToEmitRevised[i] = n; + int nAuthors = calculateNAuthorsToEmit(style, entry); + nAuthorsToEmit[i] = nAuthors; + nAuthorsToEmitRevised[i] = nAuthors; } boolean[] startsNewGroup = new boolean[nEntries]; diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java index 5dce4e8caa1..60b5222cf5b 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java @@ -53,23 +53,23 @@ public static OOText getNumCitationMarkerForBibliography(OOBibStyle style, // prefer BRACKET_BEFORE_IN_LIST and BRACKET_AFTER_IN_LIST String bracketBefore = style.getBracketBeforeInListWithFallBack(); String bracketAfter = style.getBracketAfterInListWithFallBack(); - StringBuilder sb = new StringBuilder(); - sb.append(style.getCitationGroupMarkupBefore()); - sb.append(bracketBefore); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(style.getCitationGroupMarkupBefore()); + stringBuilder.append(bracketBefore); final Optional current = entry.getNumber(); - sb.append(current.isPresent() + stringBuilder.append(current.isPresent() ? String.valueOf(current.get()) : (OOBibStyle.UNDEFINED_CITATION_MARKER + entry.getCitationKey())); - sb.append(bracketAfter); - sb.append(style.getCitationGroupMarkupAfter()); - return OOText.fromString(sb.toString()); + stringBuilder.append(bracketAfter); + stringBuilder.append(style.getCitationGroupMarkupAfter()); + return OOText.fromString(stringBuilder.toString()); } /* * emitBlock : a helper for getNumCitationMarker2 * * Given a block containing either a single entry or two or more - * entries that are joinable into an "i-j" form, append to {@code sb} the + * entries that are joinable into an "i-j" form, append to {@code stringBuilder} the * formatted text. * * Assumes: @@ -91,7 +91,7 @@ public static OOText getNumCitationMarkerForBibliography(OOBibStyle style, private static void emitBlock(List block, OOBibStyle style, int minGroupingCount, - StringBuilder sb) { + StringBuilder stringBuilder) { final int blockSize = block.size(); if (blockSize == 0) { @@ -102,14 +102,14 @@ private static void emitBlock(List block, // Add single entry: CitationMarkerNumericEntry entry = block.get(0); final Optional num = entry.getNumber(); - sb.append(num.isEmpty() - ? (OOBibStyle.UNDEFINED_CITATION_MARKER + entry.getCitationKey()) - : String.valueOf(num.get())); + stringBuilder.append(num.isEmpty() + ? (OOBibStyle.UNDEFINED_CITATION_MARKER + entry.getCitationKey()) + : String.valueOf(num.get())); // Emit pageInfo Optional pageInfo = entry.getPageInfo(); if (pageInfo.isPresent()) { - sb.append(style.getPageInfoSeparator()); - sb.append(OOText.toString(pageInfo.get())); + stringBuilder.append(style.getPageInfoSeparator()); + stringBuilder.append(OOText.toString(pageInfo.get())); } return; } @@ -146,17 +146,17 @@ private static void emitBlock(List block, } // Emit: "first-last" - sb.append(first); - sb.append(style.getGroupedNumbersSeparator()); - sb.append(last); + stringBuilder.append(first); + stringBuilder.append(style.getGroupedNumbersSeparator()); + stringBuilder.append(last); } else { // Emit: first, first+1,..., last for (int j = 0; j < blockSize; j++) { if (j > 0) { - sb.append(style.getCitationSeparator()); + stringBuilder.append(style.getCitationSeparator()); } - sb.append(block.get(j).getNumber().get()); + stringBuilder.append(block.get(j).getNumber().get()); } } return; @@ -194,15 +194,15 @@ public static OOText getNumCitationMarker2(OOBibStyle style, final boolean joinIsDisabled = (minGroupingCount <= 0); final int nCitations = entries.size(); - String bracketBefore = style.getBracketBefore(); - String bracketAfter = style.getBracketAfter(); + final String bracketBefore = style.getBracketBefore(); + final String bracketAfter = style.getBracketAfter(); // Sort a copy of entries List sorted = OOListUtil.map(entries, e -> e); sorted.sort(OOBibStyleGetNumCitationMarker::compareCitationMarkerNumericEntry); // "[" - StringBuilder sb = new StringBuilder(bracketBefore); + StringBuilder stringBuilder = new StringBuilder(bracketBefore); /* * Original: @@ -248,12 +248,12 @@ public static OOText getNumCitationMarker2(OOBibStyle style, } } - if (nextBlock.size() > 0) { + if (!nextBlock.isEmpty()) { // emit current block if (blocksEmitted) { - sb.append(style.getCitationSeparator()); + stringBuilder.append(style.getCitationSeparator()); } - emitBlock(currentBlock, style, minGroupingCount, sb); + emitBlock(currentBlock, style, minGroupingCount, stringBuilder); blocksEmitted = true; currentBlock = nextBlock; nextBlock = new ArrayList<>(); @@ -261,21 +261,21 @@ public static OOText getNumCitationMarker2(OOBibStyle style, } - if (nextBlock.size() != 0) { + if (!nextBlock.isEmpty()) { throw new IllegalStateException("impossible: (nextBlock.size() != 0) after loop"); } - if (currentBlock.size() > 0) { + if (!currentBlock.isEmpty()) { // We are emitting a block if (blocksEmitted) { - sb.append(style.getCitationSeparator()); + stringBuilder.append(style.getCitationSeparator()); } - emitBlock(currentBlock, style, minGroupingCount, sb); + emitBlock(currentBlock, style, minGroupingCount, stringBuilder); } // Emit: "]" - sb.append(bracketAfter); - return OOText.fromString(sb.toString()); + stringBuilder.append(bracketAfter); + return OOText.fromString(stringBuilder.toString()); } } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java b/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java index 4bc3fac6191..ea311193068 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java @@ -49,8 +49,8 @@ public static OOText formatBibliographyBody(CitationGroups cgs, StringBuilder stringBuilder = new StringBuilder(); - for (CitedKey ck : bibliography.values()) { - OOText entryText = formatBibliographyEntry(cgs, ck, style, alwaysAddCitedOnPages); + for (CitedKey citedKey : bibliography.values()) { + OOText entryText = formatBibliographyEntry(cgs, citedKey, style, alwaysAddCitedOnPages); stringBuilder.append(entryText.toString()); } @@ -61,29 +61,29 @@ public static OOText formatBibliographyBody(CitationGroups cgs, * @return A paragraph. Includes label and "Cited on pages". */ public static OOText formatBibliographyEntry(CitationGroups cgs, - CitedKey ck, + CitedKey citedKey, OOBibStyle style, boolean alwaysAddCitedOnPages) { - StringBuilder sb = new StringBuilder(); + StringBuilder stringBuilder = new StringBuilder(); // insert marker "[1]" if (style.isNumberEntries()) { - sb.append(style.getNumCitationMarkerForBibliography(ck).toString()); + stringBuilder.append(style.getNumCitationMarkerForBibliography(citedKey).toString()); } else { // !style.isNumberEntries() : emit no prefix // Note: We might want [citationKey] prefix for style.isCitationKeyCiteMarkers(); } // Add entry body - sb.append(formatBibliographyEntryBody(ck, style).toString()); + stringBuilder.append(formatBibliographyEntryBody(citedKey, style).toString()); // Add "Cited on pages" - if (ck.getLookupResult().isEmpty() || alwaysAddCitedOnPages) { - sb.append(formatCitedOnPages(cgs, ck).toString()); + if (citedKey.getLookupResult().isEmpty() || alwaysAddCitedOnPages) { + stringBuilder.append(formatCitedOnPages(cgs, citedKey).toString()); } // Add paragraph - OOText entryText = OOText.fromString(sb.toString()); + OOText entryText = OOText.fromString(stringBuilder.toString()); String parStyle = style.getReferenceParagraphFormat(); return OOFormat.paragraph(entryText, parStyle); } @@ -91,20 +91,20 @@ public static OOText formatBibliographyEntry(CitationGroups cgs, /** * @return just the body of a bibliography entry. No label, "Cited on pages" or paragraph. */ - public static OOText formatBibliographyEntryBody(CitedKey ck, OOBibStyle style) { - if (ck.getLookupResult().isEmpty()) { + public static OOText formatBibliographyEntryBody(CitedKey citedKey, OOBibStyle style) { + if (citedKey.getLookupResult().isEmpty()) { // Unresolved entry - return OOText.fromString(String.format("Unresolved(%s)", ck.citationKey)); + return OOText.fromString(String.format("Unresolved(%s)", citedKey.citationKey)); } else { // Resolved entry, use the layout engine - BibEntry bibentry = ck.getLookupResult().get().entry; + BibEntry bibentry = citedKey.getLookupResult().get().entry; Layout layout = style.getReferenceFormat(bibentry.getType()); layout.setPostFormatter(POSTFORMATTER); return formatFullReferenceOfBibEntry(layout, bibentry, - ck.getLookupResult().get().database, - ck.getUniqueLetter().orElse(null)); + citedKey.getLookupResult().get().database, + citedKey.getUniqueLetter().orElse(null)); } } @@ -147,27 +147,27 @@ private static OOText formatFullReferenceOfBibEntry(Layout layout, } /** - * Format links to citations of the source (ck). + * Format links to citations of the source (citedKey). * * Requires reference marks for the citation groups. * * - The links are created as references that show page numbers of the reference marks. * - We do not control the text shown, that is provided by OpenOffice. */ - private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey ck) { + private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey citedKey) { if (!cgs.citationGroupsProvideReferenceMarkNameForLinking()) { return OOText.fromString(""); } - StringBuilder sb = new StringBuilder(); + StringBuilder stringBuilder = new StringBuilder(); - String prefix = String.format(" (%s: ", Localization.lang("Cited on pages")); - String suffix = ")"; - sb.append(prefix); + final String prefix = String.format(" (%s: ", Localization.lang("Cited on pages")); + final String suffix = ")"; + stringBuilder.append(prefix); List citationGroups = new ArrayList<>(); - for (CitationPath p : ck.getCitationPaths()) { + for (CitationPath p : citedKey.getCitationPaths()) { CitationGroupId groupId = p.group; Optional group = cgs.getCitationGroup(groupId); if (group.isEmpty()) { @@ -183,18 +183,18 @@ private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey ck) { return (aa.compareTo(bb)); }); - int i = 0; + int index = 0; for (CitationGroup group : citationGroups) { - if (i > 0) { - sb.append(", "); + if (index > 0) { + stringBuilder.append(", "); } String markName = group.getReferenceMarkNameForLinking().orElseThrow(IllegalStateException::new); OOText xref = OOFormat.formatReferenceToPageNumberOfReferenceMark(markName); - sb.append(xref.toString()); - i++; + stringBuilder.append(xref.toString()); + index++; } - sb.append(suffix); - return OOText.fromString(sb.toString()); + stringBuilder.append(suffix); + return OOText.fromString(stringBuilder.toString()); } } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java index 1aaeb538930..affbc7584ae 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java @@ -88,8 +88,8 @@ private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroup // according to their order in clashingKeys. int nextUniqueLetter = 'a'; for (String citationKey : clashingKeys) { - String ul = String.valueOf((char) nextUniqueLetter); - sortedCitedKeys.get(citationKey).setUniqueLetter(Optional.of(ul)); + String uniqueLetter = String.valueOf((char) nextUniqueLetter); + sortedCitedKeys.get(citationKey).setUniqueLetter(Optional.of(uniqueLetter)); nextUniqueLetter++; } } diff --git a/src/main/java/org/jabref/model/openoffice/CitationEntry.java b/src/main/java/org/jabref/model/openoffice/CitationEntry.java index 219e71eb0d1..0d702c860ab 100644 --- a/src/main/java/org/jabref/model/openoffice/CitationEntry.java +++ b/src/main/java/org/jabref/model/openoffice/CitationEntry.java @@ -37,12 +37,12 @@ public int compareTo(CitationEntry other) { } @Override - public boolean equals(Object o) { - if (this == o) { + public boolean equals(Object object) { + if (this == object) { return true; } - if (o instanceof CitationEntry) { - CitationEntry other = (CitationEntry) o; + if (object instanceof CitationEntry) { + CitationEntry other = (CitationEntry) object; return Objects.equals(this.refMarkName, other.refMarkName); } return false; diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java index 6ba6b760cb6..baaa931214c 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java @@ -4,15 +4,15 @@ * Identifies a citation group in a document. */ public class CitationGroupId { - String id; - public CitationGroupId(String id) { - this.id = id; + String groupId; + public CitationGroupId(String groupId) { + this.groupId = groupId; } /** * CitationEntry needs some string identifying the group that it can pass back later. */ public String citationGroupIdAsString() { - return id; + return groupId; } } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java index b03028b76ef..e5e642fa652 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java @@ -131,10 +131,9 @@ public void setGlobalOrder(List globalOrder) { this.globalOrder = Optional.of(globalOrder); // Propagate to each CitationGroup - int i = 0; - for (CitationGroupId groupId : globalOrder) { + for (int i = 0; i < globalOrder.size(); i++) { + CitationGroupId groupId = globalOrder.get(i); citationGroupsUnordered.get(groupId).setIndexInGlobalOrder(Optional.of(i)); - i++; } } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitedKeys.java b/src/main/java/org/jabref/model/openoffice/style/CitedKeys.java index 898fadbebe9..059c1b6123a 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitedKeys.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitedKeys.java @@ -45,11 +45,11 @@ void sortByComparator(Comparator entryComparator) { } void numberCitedKeysInCurrentOrder() { - int i = 1; + int index = 1; for (CitedKey ck : data.values()) { if (ck.getLookupResult().isPresent()) { - ck.setNumber(Optional.of(i)); - i++; + ck.setNumber(Optional.of(index)); + index++; } else { // Unresolved citations do not get a number. ck.setNumber(Optional.empty()); diff --git a/src/main/java/org/jabref/model/openoffice/style/PageInfo.java b/src/main/java/org/jabref/model/openoffice/style/PageInfo.java index ec3a8436dcf..1ff87569a3b 100644 --- a/src/main/java/org/jabref/model/openoffice/style/PageInfo.java +++ b/src/main/java/org/jabref/model/openoffice/style/PageInfo.java @@ -19,7 +19,7 @@ public static Optional normalizePageInfo(Optional optionalText) } String str = OOText.toString(optionalText.get()); String trimmed = str.trim(); - if (trimmed.equals("")) { + if ("".equals(trimmed)) { return Optional.empty(); } return Optional.of(OOText.fromString(trimmed)); diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java b/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java index 1770b6957c5..e761a56e12f 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java @@ -39,7 +39,7 @@ public static Optional getTextCursorOfTextContentAnchor(XTextConten return Optional.of(markAnchor.getText().createTextCursorByRange(markAnchor)); } - public static XTextCursor createTextCursorByRange(XTextRange r) { - return r.getText().createTextCursorByRange(r); + public static XTextCursor createTextCursorByRange(XTextRange range) { + return range.getText().createTextCursorByRange(range); } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java b/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java index dece8978713..cd4065ba8b3 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java @@ -25,10 +25,10 @@ private static Optional getStyleFromFamily(XTextDocument doc, String fam WrappedTargetException { XStyleFamiliesSupplier fss = UnoCast.cast(XStyleFamiliesSupplier.class, doc).get(); - XNameAccess fs = UnoCast.cast(XNameAccess.class, fss.getStyleFamilies()).get(); + XNameAccess families = UnoCast.cast(XNameAccess.class, fss.getStyleFamilies()).get(); XNameContainer xFamily; try { - xFamily = UnoCast.cast(XNameContainer.class, fs.getByName(familyName)).get(); + xFamily = UnoCast.cast(XNameContainer.class, families.getByName(familyName)).get(); } catch (NoSuchElementException ex) { String msg = String.format("Style family name '%s' is not recognized", familyName); throw new java.lang.IllegalArgumentException(msg, ex); diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java b/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java index b75bee17f3e..4f08bb0ed5c 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java @@ -25,17 +25,17 @@ public static Optional getXUndoManager(XTextDocument doc) { * document's undo stack is left in an inconsistent state. */ public static void enterUndoContext(XTextDocument doc, String title) { - Optional um = getXUndoManager(doc); - if (um.isPresent()) { - um.get().enterUndoContext(title); + Optional undoManager = getXUndoManager(doc); + if (undoManager.isPresent()) { + undoManager.get().enterUndoContext(title); } } public static void leaveUndoContext(XTextDocument doc) { - Optional um = getXUndoManager(doc); - if (um.isPresent()) { + Optional undoManager = getXUndoManager(doc); + if (undoManager.isPresent()) { try { - um.get().leaveUndoContext(); + undoManager.get().leaveUndoContext(); } catch (InvalidStateException ex) { throw new IllegalStateException("leaveUndoContext reported InvalidStateException"); } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java b/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java index 634edb0c57b..f5ec43f3211 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java @@ -61,8 +61,8 @@ public static Optional getStringValue(XTextDocument doc, String property throw new java.lang.IllegalArgumentException("getting UserDefinedProperties as XPropertySet failed"); } try { - String v = propertySet.get().getPropertyValue(property).toString(); - return Optional.ofNullable(v); + String value = propertySet.get().getPropertyValue(property).toString(); + return Optional.ofNullable(value); } catch (UnknownPropertyException ex) { return Optional.empty(); } diff --git a/src/main/java/org/jabref/model/openoffice/util/OOListUtil.java b/src/main/java/org/jabref/model/openoffice/util/OOListUtil.java index 1fe617ed99a..59295c798fe 100644 --- a/src/main/java/org/jabref/model/openoffice/util/OOListUtil.java +++ b/src/main/java/org/jabref/model/openoffice/util/OOListUtil.java @@ -13,19 +13,19 @@ public static List map(List list, Function fun) { return list.stream().map(e -> fun.apply(e)).collect(Collectors.toList()); } - /** Integers 0..(n-1) */ - public static List makeIndices(int n) { - return Stream.iterate(0, i -> i + 1).limit(n).collect(Collectors.toList()); + /** Integers 0..(len-1) */ + public static List makeIndices(int len) { + return Stream.iterate(0, i -> i + 1).limit(len).collect(Collectors.toList()); } /** Return indices so that list.get(indices.get(i)) is sorted. */ public static List order(List list, Comparator comparator) { - List ii = makeIndices(list.size()); - Collections.sort(ii, new Comparator() { - @Override public int compare(final Integer o1, final Integer o2) { - return comparator.compare((U) list.get(o1), (U) list.get(o2)); + List indices = makeIndices(list.size()); + Collections.sort(indices, new Comparator() { + @Override public int compare(final Integer a, final Integer b) { + return comparator.compare((U) list.get(a), (U) list.get(b)); } }); - return ii; + return indices; } } From fd8584be79ae945699f5f75685ecba4a02364fc6 Mon Sep 17 00:00:00 2001 From: Antal K Date: Tue, 9 Nov 2021 12:20:28 +0100 Subject: [PATCH 097/103] apply suggested changes --- .../logic/openoffice/action/EditInsert.java | 25 +++++++++-------- .../logic/openoffice/action/EditMerge.java | 28 +++++++++---------- .../logic/openoffice/action/EditSeparate.java | 22 +++++++-------- .../logic/openoffice/action/ExportCited.java | 14 +++++----- .../logic/openoffice/action/Update.java | 8 +++--- 5 files changed, 50 insertions(+), 47 deletions(-) diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java index 375d3c1637a..0004d3fe6db 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java @@ -20,6 +20,7 @@ import org.jabref.model.openoffice.uno.NoDocumentException; import org.jabref.model.openoffice.uno.UnoScreenRefresh; import org.jabref.model.openoffice.util.OOListUtil; +import org.jabref.model.strings.StringUtil; import com.sun.star.beans.IllegalTypeException; import com.sun.star.beans.NotRemoveableException; @@ -73,11 +74,11 @@ public static void insertCitationGroup(XTextDocument doc, List citationKeys = OOListUtil.map(entries, EditInsert::insertEntryGetCitationKey); - final int nEntries = entries.size(); - List> pageInfos = OODataModel.fakePageInfos(pageInfo, nEntries); + final int totalEntries = entries.size(); + List> pageInfos = OODataModel.fakePageInfos(pageInfo, totalEntries); - List citations = new ArrayList<>(nEntries); - for (int i = 0; i < nEntries; i++) { + List citations = new ArrayList<>(totalEntries); + for (int i = 0; i < totalEntries; i++) { Citation cit = new Citation(citationKeys.get(i)); cit.lookupInDatabases(Collections.singletonList(database)); cit.setPageInfo(pageInfos.get(i)); @@ -85,14 +86,16 @@ public static void insertCitationGroup(XTextDocument doc, } // The text we insert - OOText citeText = - (style.isNumberEntries() - ? OOText.fromString("[-]") // A dash only. Only refresh later. - : style.createCitationMarker(citations, - citationType.inParenthesis(), - NonUniqueCitationMarker.FORGIVEN)); + OOText citeText = null; + if (style.isNumberEntries()) { + citeText = OOText.fromString("[-]"); // A dash only. Only refresh later. + } else { + citeText = style.createCitationMarker(citations, + citationType.inParenthesis(), + NonUniqueCitationMarker.FORGIVEN); + } - if ("".equals(OOText.toString(citeText))) { + if (StringUtil.isBlank(OOText.toString(citeText))) { citeText = OOText.fromString("[?]"); } diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java index 6fa19e2d344..f91e8aec93d 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java @@ -59,16 +59,16 @@ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend frontend for (JoinableGroupData joinableGroupData : joinableGroups) { - List cgs = joinableGroupData.group; + List groups = joinableGroupData.group; - List newCitations = (cgs.stream() + List newCitations = (groups.stream() .flatMap(group -> group.citationsInStorageOrder.stream()) .collect(Collectors.toList())); - CitationType citationType = cgs.get(0).citationType; - List> pageInfos = frontend.backend.combinePageInfos(cgs); + CitationType citationType = groups.get(0).citationType; + List> pageInfos = frontend.backend.combinePageInfos(groups); - frontend.removeCitationGroups(cgs, doc); + frontend.removeCitationGroups(groups, doc); XTextCursor textCursor = joinableGroupData.groupCursor; textCursor.setString(""); // Also remove the spaces between. @@ -206,8 +206,8 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup group, XTe // assume: currentGroupCursor.getEnd() == cursorBetween.getEnd() if (UnoTextRange.compareEnds(state.cursorBetween, state.currentGroupCursor) != 0) { - String msg = ("MergeCitationGroups: cursorBetween.end != currentGroupCursor.end"); - throw new IllegalStateException(msg); + LOGGER.warn("MergeCitationGroups: cursorBetween.end != currentGroupCursor.end"); + throw new IllegalStateException("MergeCitationGroups failed"); } /* @@ -238,8 +238,8 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup group, XTe // These two should move in sync: if (UnoTextRange.compareEnds(state.cursorBetween, state.currentGroupCursor) != 0) { - String msg = ("MergeCitationGroups: cursorBetween.end != currentGroupCursor.end (during expand)"); - throw new IllegalStateException(msg); + LOGGER.warn("MergeCitationGroups: cursorBetween.end != currentGroupCursor.end (during expand)"); + throw new IllegalStateException("MergeCitationGroups failed"); } } @@ -278,8 +278,8 @@ private static void addToCurrentGroup(ScanState state, CitationGroup group, XTex state.currentGroupCursor.goRight((short) (currentRange.getString().length()), true); if (UnoTextRange.compareEnds(state.cursorBetween, state.currentGroupCursor) != 0) { - String msg = ("MergeCitationGroups: cursorBetween.end != currentGroupCursor.end"); - throw new IllegalStateException(msg); + LOGGER.warn("MergeCitationGroups: cursorBetween.end != currentGroupCursor.end"); + throw new IllegalStateException("MergeCitationGroups failed"); } /* Store data about last entry in currentGroup */ @@ -296,14 +296,14 @@ private static List scan(XTextDocument doc, OOFrontend fronte WrappedTargetException { List result = new ArrayList<>(); - List cgs = frontend.getCitationGroupsSortedWithinPartitions(doc, false /* mapFootnotesToFootnoteMarks */); - if (cgs.isEmpty()) { + List groups = frontend.getCitationGroupsSortedWithinPartitions(doc, false /* mapFootnotesToFootnoteMarks */); + if (groups.isEmpty()) { return result; } ScanState state = new ScanState(); - for (CitationGroup group : cgs) { + for (CitationGroup group : groups) { XTextRange currentRange = (frontend.getMarkRange(doc, group) .orElseThrow(IllegalStateException::new)); diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java index 409969b213f..66630a6f8d0 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java @@ -50,38 +50,38 @@ public static boolean separateCitations(XTextDocument doc, frontend.citationGroups.lookupCitations(databases); frontend.citationGroups.imposeLocalOrder(OOProcess.comparatorForMulticite(style)); - List cgs = frontend.citationGroups.getCitationGroupsUnordered(); + List groups = frontend.citationGroups.getCitationGroupsUnordered(); try { UnoScreenRefresh.lockControllers(doc); - for (CitationGroup group : cgs) { + for (CitationGroup group : groups) { XTextRange range1 = (frontend .getMarkRange(doc, group) .orElseThrow(IllegalStateException::new)); XTextCursor textCursor = range1.getText().createTextCursorByRange(range1); - List cits = group.citationsInStorageOrder; - if (cits.size() <= 1) { + List citations = group.citationsInStorageOrder; + if (citations.size() <= 1) { continue; } frontend.removeCitationGroup(group, doc); - // Now we own the content of cits + // Now we own the content of citations // Create a citation group for each citation. - final int last = cits.size() - 1; - for (int i = 0; i < cits.size(); i++) { + final int last = citations.size() - 1; + for (int i = 0; i < citations.size(); i++) { boolean insertSpaceAfter = (i != last); - Citation cit = cits.get(i); + Citation citation = citations.get(i); UpdateCitationMarkers.createAndFillCitationGroup(frontend, doc, - List.of(cit.citationKey), - List.of(cit.getPageInfo()), + List.of(citation.citationKey), + List.of(citation.getPageInfo()), group.citationType, - OOText.fromString(cit.citationKey), + OOText.fromString(citation.citationKey), textCursor, style, insertSpaceAfter); diff --git a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java index ba806426051..c38cd4fd4cc 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java +++ b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java @@ -52,8 +52,8 @@ public static GenerateDatabaseResult generateDatabase(XTextDocument doc, List unresolvedKeys = new ArrayList<>(); BibDatabase resultDatabase = new BibDatabase(); @@ -61,13 +61,13 @@ public static GenerateDatabaseResult generateDatabase(XTextDocument doc, List entriesToInsert = new ArrayList<>(); Set seen = new HashSet<>(); // Only add crossReference once. - for (CitedKey ck : cks.values()) { - if (ck.getLookupResult().isEmpty()) { - unresolvedKeys.add(ck.citationKey); + for (CitedKey citation : citationKeys.values()) { + if (citation.getLookupResult().isEmpty()) { + unresolvedKeys.add(citation.citationKey); continue; } else { - BibEntry entry = ck.getLookupResult().get().entry; - BibDatabase loopDatabase = ck.getLookupResult().get().database; + BibEntry entry = citation.getLookupResult().get().entry; + BibDatabase loopDatabase = citation.getLookupResult().get().database; // If entry found BibEntry clonedEntry = (BibEntry) entry.clone(); diff --git a/src/main/java/org/jabref/logic/openoffice/action/Update.java b/src/main/java/org/jabref/logic/openoffice/action/Update.java index ba840e88b70..80263833aec 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/Update.java +++ b/src/main/java/org/jabref/logic/openoffice/action/Update.java @@ -21,6 +21,8 @@ */ public class Update { + static final boolean USE_LOCK_CONTROLLERS = true; + private Update() { /**/ } @@ -41,13 +43,11 @@ private static List updateDocument(XTextDocument doc, WrappedTargetException, com.sun.star.lang.IllegalArgumentException { - final boolean useLockControllers = true; - frontend.imposeGlobalOrder(doc, fcursor); OOProcess.produceCitationMarkers(frontend.citationGroups, databases, style); try { - if (useLockControllers) { + if (USE_LOCK_CONTROLLERS) { UnoScreenRefresh.lockControllers(doc); } @@ -63,7 +63,7 @@ private static List updateDocument(XTextDocument doc, return frontend.citationGroups.getUnresolvedKeys(); } finally { - if (useLockControllers && UnoScreenRefresh.hasControllersLocked(doc)) { + if (USE_LOCK_CONTROLLERS && UnoScreenRefresh.hasControllersLocked(doc)) { UnoScreenRefresh.unlockControllers(doc); } } From 059e1d9a2e071c882d0c957846359735707a9ac8 Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Date: Wed, 16 Feb 2022 01:34:07 +0100 Subject: [PATCH 098/103] fixed merge errors --- .../gui/openoffice/OpenOfficePanel.java | 39 +++++++------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java index fee820af2fe..e1127163fb3 100644 --- a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java +++ b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java @@ -1,7 +1,6 @@ package org.jabref.gui.openoffice; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -175,9 +174,7 @@ private void initPanel() { manualConnect.setOnAction(e -> connectManually()); selectDocument.setTooltip(new Tooltip(Localization.lang("Select which open Writer document to work on"))); - selectDocument.setOnAction(e -> { - ooBase.guiActionSelectDocument(false); - }); + selectDocument.setOnAction(e -> ooBase.guiActionSelectDocument(false)); setStyleFile.setMaxWidth(Double.MAX_VALUE); setStyleFile.setOnAction(event -> @@ -218,15 +215,11 @@ private void initPanel() { merge.setMaxWidth(Double.MAX_VALUE); merge.setTooltip(new Tooltip(Localization.lang("Combine pairs of citations that are separated by spaces only"))); - merge.setOnAction(e -> { - ooBase.guiActionMergeCitationGroups(getBaseList(), style); - }); + merge.setOnAction(e -> ooBase.guiActionMergeCitationGroups(getBaseList(), style)); unmerge.setMaxWidth(Double.MAX_VALUE); unmerge.setTooltip(new Tooltip(Localization.lang("Separate merged citations"))); - unmerge.setOnAction(e -> { - ooBase.guiActionSeparateCitations(getBaseList(), style); - }); + unmerge.setOnAction(e -> ooBase.guiActionSeparateCitations(getBaseList(), style)); ContextMenu settingsMenu = createSettingsPopup(); settingsB.setMaxWidth(Double.MAX_VALUE); @@ -419,8 +412,7 @@ protected OOBibBase2 call() throws Exception { taskExecutor.execute(connectTask); } - private OOBibBase2 createBibBase(Path loPath) throws IOException, InvocationTargetException, IllegalAccessException, - BootstrapException, CreationException, ClassNotFoundException { + private OOBibBase2 createBibBase(Path loPath) throws BootstrapException, CreationException { return new OOBibBase2(loPath, dialogService); } @@ -442,39 +434,39 @@ private static CitationType citationTypeFromOptions(boolean withText, boolean in } private void pushEntries(CitationType citationType, boolean addPageInfo) { - final String title = Localization.lang("Error pushing entries"); + final String errorDialogTitle = Localization.lang("Error pushing entries"); - LibraryTab libraryTab = frame.getCurrentLibraryTab(); - if (libraryTab == null) { + if (stateManager.getActiveDatabase().isEmpty() + || stateManager.getActiveDatabase().get().getDatabase() == null) { OOError.noDataBaseIsOpenForCiting() - .setTitle(title) - .showErrorDialog(dialogService); + .setTitle(errorDialogTitle) + .showErrorDialog(dialogService); return; } - final BibDatabase database = libraryTab.getDatabase(); + final BibDatabase database = stateManager.getActiveDatabase().get().getDatabase(); if (database == null) { OOError.noDataBaseIsOpenForCiting() - .setTitle(title) + .setTitle(errorDialogTitle) .showErrorDialog(dialogService); return; } - List entries = libraryTab.getSelectedEntries(); + List entries = stateManager.getSelectedEntries(); if (entries.isEmpty()) { OOError.noEntriesSelectedForCitation() - .setTitle(title) + .setTitle(errorDialogTitle) .showErrorDialog(dialogService); return; } - if (getOrUpdateTheStyle(title)) { + if (getOrUpdateTheStyle(errorDialogTitle)) { return; } String pageInfo = null; if (addPageInfo) { - Boolean inParenthesis = citationType.inParenthesis(); + Boolean inParenthesis; boolean withText = citationType.withText(); Optional citeDialogViewModel = dialogService.showCustomDialogAndWait(new AdvancedCiteDialogView()); @@ -497,7 +489,6 @@ private void pushEntries(CitationType citationType, boolean addPageInfo) { return; } - Optional syncOptions = (ooPrefs.getSyncWhenCiting() ? Optional.of(new Update.SyncOptions(getBaseList())) From 1e377283995985d67954308ea84691f960aafa2d Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Date: Wed, 16 Feb 2022 01:36:52 +0100 Subject: [PATCH 099/103] reformatted --- .../gui/openoffice/OpenOfficePanel.java | 68 +++++++++---------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java index e1127163fb3..7bada666050 100644 --- a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java +++ b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java @@ -159,8 +159,8 @@ private boolean getOrUpdateTheStyle(String title) { } catch (IOException ex) { LOGGER.warn("Unable to reload style file '" + style.getPath() + "'", ex); String msg = (Localization.lang("Unable to reload style file") - + "'" + style.getPath() + "'" - + "\n" + ex.getMessage()); + + "'" + style.getPath() + "'" + + "\n" + ex.getMessage()); new OOError(title, msg, ex).showErrorDialog(dialogService); return FAIL; } @@ -227,10 +227,10 @@ private void initPanel() { settingsB.setOnAction(e -> settingsMenu.show(settingsB, Side.BOTTOM, 0, 0)); manageCitations.setMaxWidth(Double.MAX_VALUE); manageCitations.setOnAction(e -> { - ManageCitationsDialogView dialog = new ManageCitationsDialogView(ooBase); - if (dialog.isOkToShowThisDialog()) { - dialogService.showCustomDialogAndWait(dialog); - } + ManageCitationsDialogView dialog = new ManageCitationsDialogView(ooBase); + if (dialog.isOkToShowThisDialog()) { + dialogService.showCustomDialogAndWait(dialog); + } }); exportCitations.setMaxWidth(Double.MAX_VALUE); @@ -329,7 +329,6 @@ private void connectManually() { connect(); } else { dialogService.showErrorDialogAndWait(Localization.lang("Could not connect to running OpenOffice/LibreOffice."), Localization.lang("If connecting manually, please verify program and library paths.")); - } }) .executeWith(taskExecutor); @@ -393,16 +392,16 @@ protected OOBibBase2 call() throws Exception { LOGGER.warn("Could not connect to running OpenOffice/LibreOffice", ex); dialogService.showErrorDialogAndWait(Localization.lang("Unable to connect. One possible reason is that JabRef " - + "and OpenOffice/LibreOffice are not both running in either 32 bit mode or 64 bit mode.")); + + "and OpenOffice/LibreOffice are not both running in either 32 bit mode or 64 bit mode.")); } else if (ex instanceof IOException) { LOGGER.warn("Could not connect to running OpenOffice/LibreOffice", ex); dialogService.showErrorDialogAndWait(Localization.lang("Could not connect to running OpenOffice/LibreOffice."), - Localization.lang("Could not connect to running OpenOffice/LibreOffice.") - + "\n" - + Localization.lang("Make sure you have installed OpenOffice/LibreOffice with Java support.") + "\n" - + Localization.lang("If connecting manually, please verify program and library paths.") + "\n" + "\n" + Localization.lang("Error message:"), - ex); + Localization.lang("Could not connect to running OpenOffice/LibreOffice.") + + "\n" + + Localization.lang("Make sure you have installed OpenOffice/LibreOffice with Java support.") + "\n" + + Localization.lang("If connecting manually, please verify program and library paths.") + "\n" + "\n" + Localization.lang("Error message:"), + ex); } else { dialogService.showErrorDialogAndWait(Localization.lang("Autodetection failed"), Localization.lang("Autodetection failed"), ex); } @@ -417,12 +416,10 @@ private OOBibBase2 createBibBase(Path loPath) throws BootstrapException, Creatio } /** - * Given the withText and inParenthesis options, - * return the corresponding citationType. + * Given the withText and inParenthesis options, return the corresponding citationType. * - * @param withText False means invisible citation (no text). - * @param inParenthesis True means "(Au and Thor 2000)". - * False means "Au and Thor (2000)". + * @param withText False means invisible citation (no text). + * @param inParenthesis True means "(Au and Thor 2000)". False means "Au and Thor (2000)". */ private static CitationType citationTypeFromOptions(boolean withText, boolean inParenthesis) { if (!withText) { @@ -447,16 +444,16 @@ private void pushEntries(CitationType citationType, boolean addPageInfo) { final BibDatabase database = stateManager.getActiveDatabase().get().getDatabase(); if (database == null) { OOError.noDataBaseIsOpenForCiting() - .setTitle(errorDialogTitle) - .showErrorDialog(dialogService); + .setTitle(errorDialogTitle) + .showErrorDialog(dialogService); return; } List entries = stateManager.getSelectedEntries(); if (entries.isEmpty()) { OOError.noEntriesSelectedForCitation() - .setTitle(errorDialogTitle) - .showErrorDialog(dialogService); + .setTitle(errorDialogTitle) + .showErrorDialog(dialogService); return; } @@ -466,7 +463,6 @@ private void pushEntries(CitationType citationType, boolean addPageInfo) { String pageInfo = null; if (addPageInfo) { - Boolean inParenthesis; boolean withText = citationType.withText(); Optional citeDialogViewModel = dialogService.showCustomDialogAndWait(new AdvancedCiteDialogView()); @@ -476,8 +472,7 @@ private void pushEntries(CitationType citationType, boolean addPageInfo) { if (!model.pageInfoProperty().getValue().isEmpty()) { pageInfo = model.pageInfoProperty().getValue(); } - inParenthesis = model.citeInParProperty().getValue(); - citationType = citationTypeFromOptions(withText, inParenthesis); + citationType = citationTypeFromOptions(withText, model.citeInParProperty().getValue()); } else { // user canceled return; @@ -490,16 +485,11 @@ private void pushEntries(CitationType citationType, boolean addPageInfo) { } Optional syncOptions = - (ooPrefs.getSyncWhenCiting() - ? Optional.of(new Update.SyncOptions(getBaseList())) - : Optional.empty()); - - ooBase.guiActionInsertEntry(entries, - database, - style, - citationType, - pageInfo, - syncOptions); + (ooPrefs.getSyncWhenCiting() + ? Optional.of(new Update.SyncOptions(getBaseList())) + : Optional.empty()); + + ooBase.guiActionInsertEntry(entries, database, style, citationType, pageInfo, syncOptions); } /** @@ -593,7 +583,13 @@ private ContextMenu createSettingsPopup() { preferencesService.setOpenOfficePreferences(ooPrefs); }); - contextMenu.getItems().addAll(autoSync, new SeparatorMenuItem(), useActiveBase, useAllBases, new SeparatorMenuItem(), clearConnectionSettings); + contextMenu.getItems().addAll( + autoSync, + new SeparatorMenuItem(), + useActiveBase, + useAllBases, + new SeparatorMenuItem(), + clearConnectionSettings); return contextMenu; } From 7d391d3114e1f3764af111e7ff6b47da7752a2bf Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Date: Wed, 23 Feb 2022 00:29:56 +0100 Subject: [PATCH 100/103] autoreformatted all oo packages, smaller rewordings, few ide suggestions --- .../openoffice/AdvancedCiteDialogView.java | 1 + .../DetectOpenOfficeInstallation.java | 14 +- .../openoffice/ManageCitationsDialogView.java | 12 +- .../ManageCitationsDialogViewModel.java | 4 +- .../{OOBibBase2.java => OOBibBase.java} | 410 ++++++++---------- .../gui/openoffice/OOBibBaseConnect.java | 91 ++-- .../org/jabref/gui/openoffice/OOError.java | 88 ++-- .../gui/openoffice/OpenOfficePanel.java | 102 +++-- .../gui/openoffice/StyleSelectDialogView.java | 1 + .../openoffice/OpenOfficeFileSearch.java | 5 +- .../logic/openoffice/action/EditInsert.java | 48 +- .../logic/openoffice/action/EditMerge.java | 88 ++-- .../logic/openoffice/action/EditSeparate.java | 37 +- .../logic/openoffice/action/ExportCited.java | 24 +- .../openoffice/action/ManageCitations.java | 19 +- .../logic/openoffice/action/Update.java | 51 ++- .../logic/openoffice/backend/Backend52.java | 210 +++++---- .../logic/openoffice/backend/Codec52.java | 41 +- .../logic/openoffice/backend/GetContext.java | 25 +- .../NamedRangeManagerReferenceMark.java | 14 +- .../backend/NamedRangeReferenceMark.java | 120 +++-- .../logic/openoffice/frontend/OOFrontend.java | 339 +++++++-------- .../frontend/RangeForOverlapCheck.java | 15 +- .../frontend/UpdateBibliography.java | 63 ++- .../frontend/UpdateCitationMarkers.java | 77 ++-- .../model/openoffice/backend/NamedRange.java | 53 +-- .../openoffice/backend/NamedRangeManager.java | 14 +- .../model/openoffice/ootext/OOFormat.java | 37 +- .../model/openoffice/ootext/OOText.java | 13 +- .../model/openoffice/ootext/OOTextIntoOO.java | 279 ++++++------ .../rangesort/FunctionalTextViewCursor.java | 10 +- .../openoffice/rangesort/RangeOverlap.java | 2 +- .../rangesort/RangeOverlapBetween.java | 17 +- .../rangesort/RangeOverlapKind.java | 12 +- .../rangesort/RangeOverlapWithin.java | 53 +-- .../model/openoffice/rangesort/RangeSort.java | 17 +- .../openoffice/rangesort/RangeSortVisual.java | 47 +- .../openoffice/rangesort/RangeSortable.java | 7 +- .../model/openoffice/style/Citation.java | 52 ++- .../model/openoffice/style/CitationGroup.java | 5 +- .../openoffice/style/CitationGroupId.java | 1 + .../openoffice/style/CitationGroups.java | 26 +- .../style/CitationLookupResult.java | 16 +- .../openoffice/style/CitationMarkerEntry.java | 6 +- .../style/CitationMarkerNormEntry.java | 12 +- .../model/openoffice/style/CitationPath.java | 3 +- .../model/openoffice/style/CitedKey.java | 19 +- .../openoffice/style/ComparableCitation.java | 3 +- .../style/NonUniqueCitationMarker.java | 11 +- .../model/openoffice/style/OODataModel.java | 12 +- .../model/openoffice/style/PageInfo.java | 3 +- .../openoffice/uno/CreationException.java | 6 +- .../model/openoffice/uno/UnoBookmark.java | 39 +- .../jabref/model/openoffice/uno/UnoCast.java | 3 +- .../model/openoffice/uno/UnoCrossRef.java | 22 +- .../model/openoffice/uno/UnoCursor.java | 8 +- .../model/openoffice/uno/UnoNameAccess.java | 7 +- .../jabref/model/openoffice/uno/UnoNamed.java | 34 +- .../model/openoffice/uno/UnoProperties.java | 19 +- .../model/openoffice/uno/UnoRedlines.java | 6 +- .../openoffice/uno/UnoReferenceMark.java | 61 ++- .../openoffice/uno/UnoScreenRefresh.java | 12 +- .../model/openoffice/uno/UnoSelection.java | 66 +-- .../jabref/model/openoffice/uno/UnoStyle.java | 27 +- .../model/openoffice/uno/UnoTextDocument.java | 23 +- .../model/openoffice/uno/UnoTextRange.java | 27 +- .../model/openoffice/uno/UnoTextSection.java | 35 +- .../jabref/model/openoffice/uno/UnoUndo.java | 13 +- .../uno/UnoUserDefinedProperty.java | 55 ++- .../model/openoffice/util/OOListUtil.java | 17 +- .../jabref/model/openoffice/util/OOPair.java | 1 + .../model/openoffice/util/OOResult.java | 9 +- .../model/openoffice/util/OOTuple3.java | 8 +- 73 files changed, 1415 insertions(+), 1712 deletions(-) rename src/main/java/org/jabref/gui/openoffice/{OOBibBase2.java => OOBibBase.java} (67%) diff --git a/src/main/java/org/jabref/gui/openoffice/AdvancedCiteDialogView.java b/src/main/java/org/jabref/gui/openoffice/AdvancedCiteDialogView.java index f11e8ab90ae..e30eec67c3d 100644 --- a/src/main/java/org/jabref/gui/openoffice/AdvancedCiteDialogView.java +++ b/src/main/java/org/jabref/gui/openoffice/AdvancedCiteDialogView.java @@ -24,6 +24,7 @@ public AdvancedCiteDialogView() { ViewLoader.view(this) .load() .setAsDialogPane(this); + setResultConverter(btn -> { if (btn == ButtonType.OK) { return viewModel; diff --git a/src/main/java/org/jabref/gui/openoffice/DetectOpenOfficeInstallation.java b/src/main/java/org/jabref/gui/openoffice/DetectOpenOfficeInstallation.java index 8141d5c7141..7e80d9c269a 100644 --- a/src/main/java/org/jabref/gui/openoffice/DetectOpenOfficeInstallation.java +++ b/src/main/java/org/jabref/gui/openoffice/DetectOpenOfficeInstallation.java @@ -21,18 +21,18 @@ */ public class DetectOpenOfficeInstallation { - private final OpenOfficePreferences ooPrefs; + private final OpenOfficePreferences openOfficePreferences; private final DialogService dialogService; private final PreferencesService preferencesService; public DetectOpenOfficeInstallation(PreferencesService preferencesService, DialogService dialogService) { this.preferencesService = preferencesService; this.dialogService = dialogService; - this.ooPrefs = preferencesService.getOpenOfficePreferences(); + this.openOfficePreferences = preferencesService.getOpenOfficePreferences(); } public boolean isExecutablePathDefined() { - return checkAutoDetectedPaths(ooPrefs); + return checkAutoDetectedPaths(openOfficePreferences); } public Optional selectInstallationPath() { @@ -71,8 +71,8 @@ public boolean setOpenOfficePreferences(Path installDir) { } if (execPath.isPresent()) { - ooPrefs.setExecutablePath(execPath.get().toString()); - preferencesService.setOpenOfficePreferences(ooPrefs); + openOfficePreferences.setExecutablePath(execPath.get().toString()); + preferencesService.setOpenOfficePreferences(openOfficePreferences); return true; } @@ -91,9 +91,7 @@ public Optional chooseAmongInstallations(List installDirs) { String content = Localization.lang("Found more than one OpenOffice/LibreOffice executable.") + "\n" + Localization.lang("Please choose which one to connect to:"); - Optional selectedPath = dialogService.showChoiceDialogAndWait(Localization.lang("Choose OpenOffice/LibreOffice executable"), + return dialogService.showChoiceDialogAndWait(Localization.lang("Choose OpenOffice/LibreOffice executable"), content, Localization.lang("Use selected instance"), installDirs); - - return selectedPath; } } diff --git a/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogView.java b/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogView.java index 872d1f8adc0..d954dc55667 100644 --- a/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogView.java +++ b/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogView.java @@ -25,7 +25,7 @@ public class ManageCitationsDialogView extends BaseDialog { private static final String HTML_BOLD_END_TAG = ""; private static final String HTML_BOLD_START_TAG = ""; - private final OOBibBase2 ooBase; + private final OOBibBase ooBase; @FXML private TableView citationsTableView; @FXML private TableColumn citation; @@ -35,7 +35,7 @@ public class ManageCitationsDialogView extends BaseDialog { private ManageCitationsDialogViewModel viewModel; - public ManageCitationsDialogView(OOBibBase2 ooBase) { + public ManageCitationsDialogView(OOBibBase ooBase) { this.ooBase = ooBase; ViewLoader.view(this) @@ -67,9 +67,8 @@ private void initialize() { citationsTableView.itemsProperty().bindBidirectional(viewModel.citationsProperty()); - extraInfo.setOnEditCommit((CellEditEvent cell) -> { - cell.getRowValue().setExtraInfo(cell.getNewValue()); - }); + extraInfo.setOnEditCommit((CellEditEvent cell) -> + cell.getRowValue().setExtraInfo(cell.getNewValue())); extraInfo.setCellFactory(TextFieldTableCell.forTableColumn()); } @@ -84,8 +83,7 @@ private Node getText(String citationContext) { inBetweenText.setStyle("-fx-font-weight: bold"); Text endText = new Text(end); - FlowPane flow = new FlowPane(startText, inBetweenText, endText); - return flow; + return new FlowPane(startText, inBetweenText, endText); } public boolean isOkToShowThisDialog() { diff --git a/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java b/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java index b854a445fa9..3736cb3243c 100644 --- a/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java +++ b/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java @@ -15,10 +15,10 @@ public class ManageCitationsDialogViewModel { public final boolean failedToGetCitationEntries; private final ListProperty citations = new SimpleListProperty<>(FXCollections.observableArrayList()); - private final OOBibBase2 ooBase; + private final OOBibBase ooBase; private final DialogService dialogService; - public ManageCitationsDialogViewModel(OOBibBase2 ooBase, DialogService dialogService) { + public ManageCitationsDialogViewModel(OOBibBase ooBase, DialogService dialogService) { this.ooBase = ooBase; this.dialogService = dialogService; diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase.java similarity index 67% rename from src/main/java/org/jabref/gui/openoffice/OOBibBase2.java rename to src/main/java/org/jabref/gui/openoffice/OOBibBase.java index d8523f0cd77..06a6091452b 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase2.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBase.java @@ -51,12 +51,11 @@ import org.slf4j.LoggerFactory; /** - * Class for manipulating the Bibliography of the currently started - * document in OpenOffice. + * Class for manipulating the Bibliography of the currently started document in OpenOffice. */ -class OOBibBase2 { +class OOBibBase { - private static final Logger LOGGER = LoggerFactory.getLogger(OOBibBase2.class); + private static final Logger LOGGER = LoggerFactory.getLogger(OOBibBase.class); /* variables */ private final DialogService dialogService; @@ -77,10 +76,10 @@ class OOBibBase2 { /* * Constructor */ - public OOBibBase2(Path loPath, DialogService dialogService) - throws - BootstrapException, - CreationException { + public OOBibBase(Path loPath, DialogService dialogService) + throws + BootstrapException, + CreationException { this.dialogService = dialogService; this.connection = new OOBibBaseConnect(loPath, dialogService); @@ -95,30 +94,27 @@ public void guiActionSelectDocument(boolean autoSelectForSingle) { try { this.connection.selectDocument(autoSelectForSingle); - } catch (NoDocumentFoundException ex) { OOError.from(ex).showErrorDialog(dialogService); } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (WrappedTargetException - | IndexOutOfBoundsException - | NoSuchElementException ex) { + | IndexOutOfBoundsException + | NoSuchElementException ex) { LOGGER.warn("Problem connecting", ex); OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); } if (this.isConnectedToDocument()) { dialogService.notify(Localization.lang("Connected to document") + ": " - + this.getCurrentDocumentTitle().orElse("")); + + this.getCurrentDocumentTitle().orElse("")); } } /** * A simple test for document availability. - * - * See also `isDocumentConnectionMissing` for a test - * actually attempting to use the connection. - * + *

+ * See also `isDocumentConnectionMissing` for a test actually attempting to use the connection. */ public boolean isConnectedToDocument() { return this.connection.isConnectedToDocument(); @@ -139,7 +135,7 @@ public OOResult getXTextDocument() { } /** - * The title of the current document, or Optional.empty() + * The title of the current document, or Optional.empty() */ public Optional getCurrentDocumentTitle() { return this.connection.getCurrentDocumentTitle(); @@ -161,9 +157,9 @@ void showDialog(String title, OOError err) { OOVoidResult collectResults(String title, List> results) { String msg = (results.stream() - .filter(OOVoidResult::isError) - .map(e -> e.getError().getLocalizedMessage()) - .collect(Collectors.joining("\n\n"))); + .filter(OOVoidResult::isError) + .map(e -> e.getError().getLocalizedMessage()) + .collect(Collectors.joining("\n\n"))); if (msg.isEmpty()) { return OOVoidResult.ok(); } else { @@ -205,10 +201,10 @@ OOResult getUserCursorForTextInsertion(XTextDocument doc, cursor.getStart(); } catch (com.sun.star.uno.RuntimeException ex) { String msg = - Localization.lang("Please move the cursor" - + " to the location for the new citation.") - + "\n" - + Localization.lang("I cannot insert to the cursors current location."); + Localization.lang("Please move the cursor" + + " to the location for the new citation.") + + "\n" + + Localization.lang("I cannot insert to the cursors current location."); return OOResult.error(new OOError(title, msg, ex)); } return OOResult.ok(cursor); @@ -220,11 +216,11 @@ OOResult getUserCursorForTextInsertion(XTextDocument doc, OOResult getFunctionalTextViewCursor(XTextDocument doc, String title) { String messageOnFailureToObtain = - Localization.lang("Please move the cursor into the document text.") - + "\n" - + Localization.lang("To get the visual positions of your citations" - + " I need to move the cursor around," - + " but could not get it."); + Localization.lang("Please move the cursor into the document text.") + + "\n" + + Localization.lang("To get the visual positions of your citations" + + " I need to move the cursor around," + + " but could not get it."); OOResult result = FunctionalTextViewCursor.get(doc); if (result.isError()) { LOGGER.warn(result.getError()); @@ -238,10 +234,10 @@ private static OOVoidResult checkRangeOverlaps(XTextDocument doc, OOFro int maxReportedOverlaps = 10; try { return (frontend.checkRangeOverlaps(doc, - new ArrayList<>(), - requireSeparation, - maxReportedOverlaps) - .mapError(OOError::from)); + new ArrayList<>(), + requireSeparation, + maxReportedOverlaps) + .mapError(OOError::from)); } catch (NoDocumentException ex) { return OOVoidResult.error(OOError.from(ex).setTitle(title)); } catch (WrappedTargetException ex) { @@ -259,8 +255,8 @@ private static OOVoidResult checkRangeOverlapsWithCursor(XTextDocument OOVoidResult res; try { res = frontend.checkRangeOverlapsWithCursor(doc, - userRanges, - requireSeparation); + userRanges, + requireSeparation); } catch (NoDocumentException ex) { return OOVoidResult.error(OOError.from(ex).setTitle(title)); } catch (WrappedTargetException ex) { @@ -270,8 +266,8 @@ private static OOVoidResult checkRangeOverlapsWithCursor(XTextDocument if (res.isError()) { final String xtitle = Localization.lang("The cursor is in protected area."); return OOVoidResult.error(new OOError(xtitle, - xtitle + "\n" - + res.getError().getLocalizedMessage() + "\n")); + xtitle + "\n" + + res.getError().getLocalizedMessage() + "\n")); } return res.mapError(OOError::from); } @@ -292,15 +288,15 @@ private static OOVoidResult checkIfOpenOfficeIsRecordingChanges(XTextDo String msg = ""; if (recordingChanges) { msg += Localization.lang("Cannot work with" - + " [Edit]/[Track Changes]/[Record] turned on."); + + " [Edit]/[Track Changes]/[Record] turned on."); } if (nRedlines > 0) { if (recordingChanges) { msg += "\n"; } msg += Localization.lang("Changes by JabRef" - + " could result in unexpected interactions with" - + " recorded changes."); + + " could result in unexpected interactions with" + + " recorded changes."); msg += "\n"; msg += Localization.lang("Use [Edit]/[Track Changes]/[Manage] to resolve them first."); } @@ -308,7 +304,7 @@ private static OOVoidResult checkIfOpenOfficeIsRecordingChanges(XTextDo } } catch (WrappedTargetException ex) { String msg = Localization.lang("Error while checking if Writer" - + " is recording changes or has recorded changes."); + + " is recording changes or has recorded changes."); return OOVoidResult.error(new OOError(title, msg, ex)); } return OOVoidResult.ok(); @@ -329,13 +325,13 @@ OOResult getFrontend(XTextDocument doc) { } catch (NoDocumentException ex) { return OOResult.error(OOError.from(ex).setTitle(title)); } catch (WrappedTargetException - | RuntimeException ex) { + | RuntimeException ex) { return OOResult.error(OOError.fromMisc(ex).setTitle(title)); } } OOVoidResult databaseIsRequired(List databases, - Supplier fun) { + Supplier fun) { if (databases == null || databases.isEmpty()) { return OOVoidResult.error(fun.get()); } else { @@ -344,7 +340,7 @@ OOVoidResult databaseIsRequired(List databases, } OOVoidResult selectedBibEntryIsRequired(List entries, - Supplier fun) { + Supplier fun) { if (entries == null || entries.isEmpty()) { return OOVoidResult.error(fun.get()); } else { @@ -360,58 +356,52 @@ private OOVoidResult checkStyleExistsInTheDocument(String familyName, XTextDocument doc, String labelInJstyleFile, String pathToStyleFile) - throws - WrappedTargetException { + throws + WrappedTargetException { Optional internalName = UnoStyle.getInternalNameOfStyle(doc, familyName, styleName); if (internalName.isEmpty()) { String msg = - switch (familyName) { - case UnoStyle.PARAGRAPH_STYLES -> - Localization.lang("The %0 paragraph style '%1' is missing from the document", - labelInJstyleFile, - styleName); - case UnoStyle.CHARACTER_STYLES -> - Localization.lang("The %0 character style '%1' is missing from the document", - labelInJstyleFile, - styleName); - default -> - throw new IllegalArgumentException("Expected " + UnoStyle.CHARACTER_STYLES - + " or " + UnoStyle.PARAGRAPH_STYLES - + " for familyName"); - } - + "\n" - + Localization.lang("Please create it in the document or change in the file:") - + "\n" - + pathToStyleFile; - return OOVoidResult.error(new OOError("StyleIsNotKnown", msg)); + switch (familyName) { + case UnoStyle.PARAGRAPH_STYLES -> Localization.lang("The %0 paragraph style '%1' is missing from the document", + labelInJstyleFile, + styleName); + case UnoStyle.CHARACTER_STYLES -> Localization.lang("The %0 character style '%1' is missing from the document", + labelInJstyleFile, + styleName); + default -> throw new IllegalArgumentException("Expected " + UnoStyle.CHARACTER_STYLES + + " or " + UnoStyle.PARAGRAPH_STYLES + + " for familyName"); + } + + "\n" + + Localization.lang("Please create it in the document or change in the file:") + + "\n" + + pathToStyleFile; + return OOVoidResult.error(new OOError("StyleIsNotKnown", msg)); } if (!internalName.get().equals(styleName)) { String msg = - switch (familyName) { - case UnoStyle.PARAGRAPH_STYLES -> - Localization.lang("The %0 paragraph style '%1' is a display name for '%2'.", - labelInJstyleFile, - styleName, - internalName.get()); - case UnoStyle.CHARACTER_STYLES -> - Localization.lang("The %0 character style '%1' is a display name for '%2'.", - labelInJstyleFile, - styleName, - internalName.get()); - default -> - throw new IllegalArgumentException("Expected " + UnoStyle.CHARACTER_STYLES - + " or " + UnoStyle.PARAGRAPH_STYLES - + " for familyName"); - } - + "\n" - + Localization.lang("Please use the latter in the style file below" - + " to avoid localization problems.") - + "\n" - + pathToStyleFile; - return OOVoidResult.error(new OOError("StyleNameIsNotInternal", msg)); + switch (familyName) { + case UnoStyle.PARAGRAPH_STYLES -> Localization.lang("The %0 paragraph style '%1' is a display name for '%2'.", + labelInJstyleFile, + styleName, + internalName.get()); + case UnoStyle.CHARACTER_STYLES -> Localization.lang("The %0 character style '%1' is a display name for '%2'.", + labelInJstyleFile, + styleName, + internalName.get()); + default -> throw new IllegalArgumentException("Expected " + UnoStyle.CHARACTER_STYLES + + " or " + UnoStyle.PARAGRAPH_STYLES + + " for familyName"); + } + + "\n" + + Localization.lang("Please use the latter in the style file below" + + " to avoid localization problems.") + + "\n" + + pathToStyleFile; + return OOVoidResult.error(new OOError("StyleNameIsNotInternal", msg)); } return OOVoidResult.ok(); } @@ -423,26 +413,26 @@ public OOVoidResult checkStylesExistInTheDocument(OOBibStyle style, XTe List> results = new ArrayList<>(); try { results.add(checkStyleExistsInTheDocument(UnoStyle.PARAGRAPH_STYLES, - style.getReferenceHeaderParagraphFormat(), - doc, - "ReferenceHeaderParagraphFormat", - pathToStyleFile)); + style.getReferenceHeaderParagraphFormat(), + doc, + "ReferenceHeaderParagraphFormat", + pathToStyleFile)); results.add(checkStyleExistsInTheDocument(UnoStyle.PARAGRAPH_STYLES, - style.getReferenceParagraphFormat(), - doc, - "ReferenceParagraphFormat", - pathToStyleFile)); + style.getReferenceParagraphFormat(), + doc, + "ReferenceParagraphFormat", + pathToStyleFile)); if (style.isFormatCitations()) { results.add(checkStyleExistsInTheDocument(UnoStyle.CHARACTER_STYLES, - style.getCitationCharacterFormat(), - doc, - "CitationCharacterFormat", - pathToStyleFile)); + style.getCitationCharacterFormat(), + doc, + "CitationCharacterFormat", + pathToStyleFile)); } } catch (WrappedTargetException ex) { results.add(OOVoidResult.error(new OOError("Other error in checkStyleExistsInTheDocument", - ex.getMessage(), - ex))); + ex.getMessage(), + ex))); } return collectResults("checkStyleExistsInTheDocument failed", results); @@ -472,7 +462,6 @@ public Optional> guiActionGetCitationEntries() { try { return Optional.of(ManageCitations.getCitationEntries(doc)); - } catch (NoDocumentException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); return FAIL; @@ -487,24 +476,18 @@ public Optional> guiActionGetCitationEntries() { } /** - * Apply editable parts of citationEntries to the document: store - * pageInfo. - * + * Apply editable parts of citationEntries to the document: store pageInfo. + *

* Does not change presentation. - * - * Note: we use no undo context here, because only - * DocumentConnection.setUserDefinedStringPropertyValue() is called, - * and Undo in LO will not undo that. - * - * GUI: "Manage citations" dialog "OK" button. - * Called from: ManageCitationsDialogViewModel.storeSettings + *

+ * Note: we use no undo context here, because only DocumentConnection.setUserDefinedStringPropertyValue() is called, and Undo in LO will not undo that. + *

+ * GUI: "Manage citations" dialog "OK" button. Called from: ManageCitationsDialogViewModel.storeSettings * *

* Currently the only editable part is pageInfo. *

- * Since the only call to applyCitationEntries() only changes - * pageInfo w.r.t those returned by getCitationEntries(), we can - * do with the following restrictions: + * Since the only call to applyCitationEntries() only changes pageInfo w.r.t those returned by getCitationEntries(), we can do with the following restrictions: *

    *
  • Missing pageInfo means no action.
  • *
  • Missing CitationEntry means no action (no attempt to remove @@ -524,51 +507,34 @@ public void guiActionApplyCitationEntries(List citationEntries) { try { ManageCitations.applyCitationEntries(doc, citationEntries); - } catch (NoDocumentException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (PropertyVetoException - | IllegalTypeException - | WrappedTargetException - | com.sun.star.lang.IllegalArgumentException ex) { + | IllegalTypeException + | WrappedTargetException + | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn(title, ex); OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); } } /** - * * Creates a citation group from {@code entries} at the cursor. - * + *

    * Uses LO undo context "Insert citation". - * + *

    * Note: Undo does not remove or reestablish custom properties. * - * @param entries The entries to cite. - * - * @param database The database the entries belong to (all of them). - * Used when creating the citation mark. - * - * Consistency: for each entry in {@entries}: looking it up in - * {@code syncOptions.get().databases} (if present) - * should yield {@code database}. - * - * @param style The bibliography style we are using. - * - * @param citationType Indicates whether it is an in-text - * citation, a citation in parenthesis or - * an invisible citation. - * - * @param pageInfo A single page-info for these entries. - * Attributed to the last entry. - * - * @param syncOptions Indicates whether in-text citations - * should be refreshed in the document. - * Optional.empty() indicates no refresh. - * Otherwise provides options for refreshing - * the reference list. + * @param entries The entries to cite. + * @param database The database the entries belong to (all of them). Used when creating the citation mark. + *

    + * Consistency: for each entry in {@entries}: looking it up in {@code syncOptions.get().databases} (if present) should yield {@code database}. + * @param style The bibliography style we are using. + * @param citationType Indicates whether it is an in-text citation, a citation in parenthesis or an invisible citation. + * @param pageInfo A single page-info for these entries. Attributed to the last entry. + * @param syncOptions Indicates whether in-text citations should be refreshed in the document. Optional.empty() indicates no refresh. Otherwise provides options for refreshing the reference list. */ public void guiActionInsertEntry(List entries, BibDatabase database, @@ -581,9 +547,9 @@ public void guiActionInsertEntry(List entries, OOResult odoc = getXTextDocument(); if (testDialog(title, - odoc.asVoidResult(), - styleIsRequired(style), - selectedBibEntryIsRequired(entries, OOError::noEntriesSelectedForCitation))) { + odoc.asVoidResult(), + styleIsRequired(style), + selectedBibEntryIsRequired(entries, OOError::noEntriesSelectedForCitation))) { return; } XTextDocument doc = odoc.get(); @@ -603,8 +569,8 @@ public void guiActionInsertEntry(List entries, } if (testDialog(title, - checkStylesExistInTheDocument(style, doc), - checkIfOpenOfficeIsRecordingChanges(doc))) { + checkStylesExistInTheDocument(style, doc), + checkIfOpenOfficeIsRecordingChanges(doc))) { return; } @@ -620,12 +586,12 @@ public void guiActionInsertEntry(List entries, } syncOptions - .map(e -> e.setUpdateBibliography(this.refreshBibliographyDuringSyncWhenCiting)) - .map(e -> e.setAlwaysAddCitedOnPages(this.alwaysAddCitedOnPages)); + .map(e -> e.setUpdateBibliography(this.refreshBibliographyDuringSyncWhenCiting)) + .map(e -> e.setAlwaysAddCitedOnPages(this.alwaysAddCitedOnPages)); if (syncOptions.isPresent()) { if (testDialog(databaseIsRequired(syncOptions.get().databases, - OOError::noDataBaseIsOpenForSyncingAfterCitation))) { + OOError::noDataBaseIsOpenForSyncingAfterCitation))) { return; } } @@ -634,18 +600,17 @@ public void guiActionInsertEntry(List entries, UnoUndo.enterUndoContext(doc, "Insert citation"); EditInsert.insertCitationGroup(doc, - frontend.get(), - cursor.get(), - entries, - database, - style, - citationType, - pageInfo); + frontend.get(), + cursor.get(), + entries, + database, + style, + citationType, + pageInfo); if (syncOptions.isPresent()) { Update.resyncDocument(doc, style, fcursor.get(), syncOptions.get()); } - } catch (NoDocumentException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); return; @@ -653,10 +618,10 @@ public void guiActionInsertEntry(List entries, OOError.from(ex).setTitle(title).showErrorDialog(dialogService); return; } catch (CreationException - | IllegalTypeException - | NotRemoveableException - | PropertyVetoException - | WrappedTargetException ex) { + | IllegalTypeException + | NotRemoveableException + | PropertyVetoException + | WrappedTargetException ex) { LOGGER.warn("Could not insert entry", ex); OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); return; @@ -667,7 +632,6 @@ public void guiActionInsertEntry(List entries, /** * GUI action "Merge citations" - * */ public void guiActionMergeCitationGroups(List databases, OOBibStyle style) { @@ -675,9 +639,9 @@ public void guiActionMergeCitationGroups(List databases, OOBibStyle OOResult odoc = getXTextDocument(); if (testDialog(title, - odoc.asVoidResult(), - styleIsRequired(style), - databaseIsRequired(databases, OOError::noDataBaseIsOpen))) { + odoc.asVoidResult(), + styleIsRequired(style), + databaseIsRequired(databases, OOError::noDataBaseIsOpen))) { return; } XTextDocument doc = odoc.get(); @@ -685,9 +649,9 @@ public void guiActionMergeCitationGroups(List databases, OOBibStyle OOResult fcursor = getFunctionalTextViewCursor(doc, title); if (testDialog(title, - fcursor.asVoidResult(), - checkStylesExistInTheDocument(style, doc), - checkIfOpenOfficeIsRecordingChanges(doc))) { + fcursor.asVoidResult(), + checkStylesExistInTheDocument(style, doc), + checkIfOpenOfficeIsRecordingChanges(doc))) { return; } @@ -701,17 +665,16 @@ public void guiActionMergeCitationGroups(List databases, OOBibStyle Update.SyncOptions syncOptions = new Update.SyncOptions(databases); Update.resyncDocument(doc, style, fcursor.get(), syncOptions); } - } catch (NoDocumentException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (CreationException - | IllegalTypeException - | NotRemoveableException - | PropertyVetoException - | WrappedTargetException - | com.sun.star.lang.IllegalArgumentException ex) { + | IllegalTypeException + | NotRemoveableException + | PropertyVetoException + | WrappedTargetException + | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn("Problem combining cite markers", ex); OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); } finally { @@ -722,9 +685,8 @@ public void guiActionMergeCitationGroups(List databases, OOBibStyle /** * GUI action "Separate citations". - * - * Do the opposite of MergeCitationGroups. - * Combined markers are split, with a space inserted between. + *

    + * Do the opposite of MergeCitationGroups. Combined markers are split, with a space inserted between. */ public void guiActionSeparateCitations(List databases, OOBibStyle style) { @@ -732,9 +694,9 @@ public void guiActionSeparateCitations(List databases, OOBibStyle s OOResult odoc = getXTextDocument(); if (testDialog(title, - odoc.asVoidResult(), - styleIsRequired(style), - databaseIsRequired(databases, OOError::noDataBaseIsOpen))) { + odoc.asVoidResult(), + styleIsRequired(style), + databaseIsRequired(databases, OOError::noDataBaseIsOpen))) { return; } @@ -742,9 +704,9 @@ public void guiActionSeparateCitations(List databases, OOBibStyle s OOResult fcursor = getFunctionalTextViewCursor(doc, title); if (testDialog(title, - fcursor.asVoidResult(), - checkStylesExistInTheDocument(style, doc), - checkIfOpenOfficeIsRecordingChanges(doc))) { + fcursor.asVoidResult(), + checkStylesExistInTheDocument(style, doc), + checkIfOpenOfficeIsRecordingChanges(doc))) { return; } @@ -758,17 +720,16 @@ public void guiActionSeparateCitations(List databases, OOBibStyle s Update.SyncOptions syncOptions = new Update.SyncOptions(databases); Update.resyncDocument(doc, style, fcursor.get(), syncOptions); } - } catch (NoDocumentException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (CreationException - | IllegalTypeException - | NotRemoveableException - | PropertyVetoException - | WrappedTargetException - | com.sun.star.lang.IllegalArgumentException ex) { + | IllegalTypeException + | NotRemoveableException + | PropertyVetoException + | WrappedTargetException + | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn("Problem during separating cite markers", ex); OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); } finally { @@ -779,11 +740,10 @@ public void guiActionSeparateCitations(List databases, OOBibStyle s /** * GUI action for "Export cited" - * + *

    * Does not refresh the bibliography. * - * @param returnPartialResult If there are some unresolved keys, - * shall we return an otherwise nonempty result, or Optional.empty()? + * @param returnPartialResult If there are some unresolved keys, shall we return an otherwise nonempty result, or Optional.empty()? */ public Optional exportCitedHelper(List databases, boolean returnPartialResult) { @@ -793,8 +753,8 @@ public Optional exportCitedHelper(List databases, OOResult odoc = getXTextDocument(); if (testDialog(title, - odoc.asVoidResult(), - databaseIsRequired(databases, OOError::noDataBaseIsOpenForExport))) { + odoc.asVoidResult(), + databaseIsRequired(databases, OOError::noDataBaseIsOpenForExport))) { return FAIL; } XTextDocument doc = odoc.get(); @@ -813,23 +773,23 @@ public Optional exportCitedHelper(List databases, if (!result.newDatabase.hasEntries()) { dialogService.showErrorDialogAndWait( - Localization.lang("Unable to generate new library"), - Localization.lang("Your OpenOffice/LibreOffice document references" - + " no citation keys" - + " which could also be found in your current library.")); + Localization.lang("Unable to generate new library"), + Localization.lang("Your OpenOffice/LibreOffice document references" + + " no citation keys" + + " which could also be found in your current library.")); return FAIL; } List unresolvedKeys = result.unresolvedKeys; if (!unresolvedKeys.isEmpty()) { dialogService.showErrorDialogAndWait( - Localization.lang("Unable to generate new library"), - Localization.lang("Your OpenOffice/LibreOffice document references" - + " at least %0 citation keys" - + " which could not be found in your current library." - + " Some of these are %1.", - String.valueOf(unresolvedKeys.size()), - String.join(", ", unresolvedKeys))); + Localization.lang("Unable to generate new library"), + Localization.lang("Your OpenOffice/LibreOffice document references" + + " at least %0 citation keys" + + " which could not be found in your current library." + + " Some of these are %1.", + String.valueOf(unresolvedKeys.size()), + String.join(", ", unresolvedKeys))); if (returnPartialResult) { return Optional.of(result.newDatabase); } else { @@ -842,7 +802,7 @@ public Optional exportCitedHelper(List databases, } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (WrappedTargetException - | com.sun.star.lang.IllegalArgumentException ex) { + | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn("Problem generating new database.", ex); OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); } @@ -853,8 +813,7 @@ public Optional exportCitedHelper(List databases, * GUI action, refreshes citation markers and bibliography. * * @param databases Must have at least one. - * @param style Style. - * + * @param style Style. */ public void guiActionUpdateDocument(List databases, OOBibStyle style) { @@ -864,8 +823,8 @@ public void guiActionUpdateDocument(List databases, OOBibStyle styl OOResult odoc = getXTextDocument(); if (testDialog(title, - odoc.asVoidResult(), - styleIsRequired(style))) { + odoc.asVoidResult(), + styleIsRequired(style))) { return; } @@ -874,9 +833,9 @@ public void guiActionUpdateDocument(List databases, OOBibStyle styl OOResult fcursor = getFunctionalTextViewCursor(doc, title); if (testDialog(title, - fcursor.asVoidResult(), - checkStylesExistInTheDocument(style, doc), - checkIfOpenOfficeIsRecordingChanges(doc))) { + fcursor.asVoidResult(), + checkStylesExistInTheDocument(style, doc), + checkIfOpenOfficeIsRecordingChanges(doc))) { return; } @@ -891,11 +850,10 @@ public void guiActionUpdateDocument(List databases, OOBibStyle styl Update.SyncOptions syncOptions = new Update.SyncOptions(databases); syncOptions - .setUpdateBibliography(true) - .setAlwaysAddCitedOnPages(this.alwaysAddCitedOnPages); + .setUpdateBibliography(true) + .setAlwaysAddCitedOnPages(this.alwaysAddCitedOnPages); unresolvedKeys = Update.synchronizeDocument(doc, frontend, style, fcursor.get(), syncOptions); - } finally { UnoUndo.leaveUndoContext(doc); fcursor.get().restore(doc); @@ -903,23 +861,21 @@ public void guiActionUpdateDocument(List databases, OOBibStyle styl if (!unresolvedKeys.isEmpty()) { String msg = Localization.lang( - "Your OpenOffice/LibreOffice document references the citation key '%0'," - + " which could not be found in your current library.", - unresolvedKeys.get(0)); + "Your OpenOffice/LibreOffice document references the citation key '%0'," + + " which could not be found in your current library.", + unresolvedKeys.get(0)); dialogService.showErrorDialogAndWait(title, msg); return; } - } catch (NoDocumentException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (DisposedException ex) { OOError.from(ex).setTitle(title).showErrorDialog(dialogService); } catch (CreationException - | WrappedTargetException - | com.sun.star.lang.IllegalArgumentException ex) { + | WrappedTargetException + | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn("Could not update bibliography", ex); OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); } } - } diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java b/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java index 728b5cf541e..d340eaf18ac 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java @@ -37,7 +37,7 @@ class OOBibBaseConnect { /** * Created when connected to a document. - * + *

    * Cleared (to null) when we discover we lost the connection. */ private XTextDocument xTextDocument; @@ -46,18 +46,18 @@ class OOBibBaseConnect { * Constructor */ public OOBibBaseConnect(Path loPath, DialogService dialogService) - throws - BootstrapException, - CreationException { + throws + BootstrapException, + CreationException { this.dialogService = dialogService; this.xDesktop = simpleBootstrap(loPath); } private XDesktop simpleBootstrap(Path loPath) - throws - CreationException, - BootstrapException { + throws + CreationException, + BootstrapException { // Get the office component context: XComponentContext context = org.jabref.gui.openoffice.Bootstrap.bootstrap(loPath); @@ -75,9 +75,9 @@ private XDesktop simpleBootstrap(Path loPath) } private static List getTextDocuments(XDesktop desktop) - throws - NoSuchElementException, - WrappedTargetException { + throws + NoSuchElementException, + WrappedTargetException { List result = new ArrayList<>(); @@ -88,19 +88,15 @@ private static List getTextDocuments(XDesktop desktop) Object next = compEnum.nextElement(); XComponent comp = UnoCast.cast(XComponent.class, next).get(); Optional doc = UnoCast.cast(XTextDocument.class, comp); - if (doc.isPresent()) { - result.add(doc.get()); - } + doc.ifPresent(result::add); } return result; } /** - * Run a dialog allowing the user to choose among the documents in `list`. - * - * @return Null if no document was selected. Otherwise the - * document selected. + * Run a dialog allowing the user to choose among the documents in `list`. * + * @return Null if no document was selected. Otherwise the document selected. */ private static XTextDocument selectDocumentDialog(List list, DialogService dialogService) { @@ -126,18 +122,18 @@ public String toString() { } List viewModel = (list.stream() - .map(DocumentTitleViewModel::new) - .collect(Collectors.toList())); + .map(DocumentTitleViewModel::new) + .collect(Collectors.toList())); // This whole method is part of a background task when // auto-detecting instances, so we need to show dialog in FX // thread Optional selectedDocument = - (dialogService - .showChoiceDialogAndWait(Localization.lang("Select document"), - Localization.lang("Found documents:"), - Localization.lang("Use selected document"), - viewModel)); + (dialogService + .showChoiceDialogAndWait(Localization.lang("Select document"), + Localization.lang("Found documents:"), + Localization.lang("Use selected document"), + viewModel)); return (selectedDocument .map(DocumentTitleViewModel::getXtextDocument) @@ -146,26 +142,20 @@ public String toString() { /** * Choose a document to work with. - * + *

    * Assumes we have already connected to LibreOffice or OpenOffice. - * - * If there is a single document to choose from, selects that. - * If there are more than one, shows selection dialog. - * If there are none, throws NoDocumentFoundException - * - * After successful selection connects to the selected document - * and extracts some frequently used parts (starting points for - * managing its content). - * - * Finally initializes this.xTextDocument with the selected - * document and parts extracted. - * + *

    + * If there is a single document to choose from, selects that. If there are more than one, shows selection dialog. If there are none, throws NoDocumentFoundException + *

    + * After successful selection connects to the selected document and extracts some frequently used parts (starting points for managing its content). + *

    + * Finally initializes this.xTextDocument with the selected document and parts extracted. */ public void selectDocument(boolean autoSelectForSingle) - throws - NoDocumentFoundException, - NoSuchElementException, - WrappedTargetException { + throws + NoDocumentFoundException, + NoSuchElementException, + WrappedTargetException { XTextDocument selected; List textDocumentList = getTextDocuments(this.xDesktop); @@ -175,7 +165,7 @@ public void selectDocument(boolean autoSelectForSingle) selected = textDocumentList.get(0); // Get the only one } else { // Bring up a dialog selected = OOBibBaseConnect.selectDocumentDialog(textDocumentList, - this.dialogService); + this.dialogService); } if (selected == null) { @@ -187,7 +177,6 @@ public void selectDocument(boolean autoSelectForSingle) /** * Mark the current document as missing. - * */ private void forgetDocument() { this.xTextDocument = null; @@ -195,10 +184,8 @@ private void forgetDocument() { /** * A simple test for document availability. - * - * See also `isDocumentConnectionMissing` for a test - * actually attempting to use teh connection. - * + *

    + * See also `isDocumentConnectionMissing` for a test actually attempting to use teh connection. */ public boolean isConnectedToDocument() { return this.xTextDocument != null; @@ -222,12 +209,11 @@ public boolean isDocumentConnectionMissing() { } /** - * Either return a valid XTextDocument or throw - * NoDocumentException. + * Either return a valid XTextDocument or throw NoDocumentException. */ public XTextDocument getXTextDocumentOrThrow() - throws - NoDocumentException { + throws + NoDocumentException { if (isDocumentConnectionMissing()) { throw new NoDocumentException("Not connected to document"); } @@ -242,7 +228,7 @@ public OOResult getXTextDocument() { } /** - * The title of the current document, or Optional.empty() + * The title of the current document, or Optional.empty() */ public Optional getCurrentDocumentTitle() { if (isDocumentConnectionMissing()) { @@ -251,5 +237,4 @@ public Optional getCurrentDocumentTitle() { return UnoTextDocument.getFrameTitle(this.xTextDocument); } } - } // end of OOBibBaseConnect diff --git a/src/main/java/org/jabref/gui/openoffice/OOError.java b/src/main/java/org/jabref/gui/openoffice/OOError.java index b296ffe30c0..c8ad7ef53aa 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOError.java +++ b/src/main/java/org/jabref/gui/openoffice/OOError.java @@ -41,48 +41,48 @@ public void showErrorDialog(DialogService dialogService) { public static OOError from(JabRefException err) { return new OOError( - Localization.lang("JabRefException"), - err.getLocalizedMessage(), - err); + Localization.lang("JabRefException"), + err.getLocalizedMessage(), + err); } // For DisposedException public static OOError from(DisposedException err) { return new OOError( - Localization.lang("Connection lost"), - Localization.lang("Connection to OpenOffice/LibreOffice has been lost." - + " Please make sure OpenOffice/LibreOffice is running," - + " and try to reconnect."), - err); + Localization.lang("Connection lost"), + Localization.lang("Connection to OpenOffice/LibreOffice has been lost." + + " Please make sure OpenOffice/LibreOffice is running," + + " and try to reconnect."), + err); } // For NoDocumentException public static OOError from(NoDocumentException err) { return new OOError( - Localization.lang("Not connected to document"), - Localization.lang("Not connected to any Writer document." - + " Please make sure a document is open," - + " and use the 'Select Writer document' button" - + " to connect to it."), - err); + Localization.lang("Not connected to document"), + Localization.lang("Not connected to any Writer document." + + " Please make sure a document is open," + + " and use the 'Select Writer document' button" + + " to connect to it."), + err); } // For NoDocumentFoundException public static OOError from(NoDocumentFoundException err) { return new OOError( - Localization.lang("No Writer documents found"), - Localization.lang("Could not connect to any Writer document." - + " Please make sure a document is open" - + " before using the 'Select Writer document' button" - + " to connect to it."), - err); + Localization.lang("No Writer documents found"), + Localization.lang("Could not connect to any Writer document." + + " Please make sure a document is open" + + " before using the 'Select Writer document' button" + + " to connect to it."), + err); } public static OOError fromMisc(Exception err) { return new OOError( - "Exception", - err.getMessage(), - err); + "Exception", + err.getMessage(), + err); } /* @@ -92,50 +92,50 @@ public static OOError fromMisc(Exception err) { // noDataBaseIsOpenForCiting public static OOError noDataBaseIsOpenForCiting() { return new OOError( - Localization.lang("No database"), - Localization.lang("No bibliography database is open for citation.") - + "\n" - + Localization.lang("Open one before citing.")); + Localization.lang("No database"), + Localization.lang("No bibliography database is open for citation.") + + "\n" + + Localization.lang("Open one before citing.")); } public static OOError noDataBaseIsOpenForSyncingAfterCitation() { return new OOError( - Localization.lang("No database"), - Localization.lang("No database is open for updating citation markers after citing.") - + "\n" - + Localization.lang("Open one before citing.")); + Localization.lang("No database"), + Localization.lang("No database is open for updating citation markers after citing.") + + "\n" + + Localization.lang("Open one before citing.")); } // noDataBaseIsOpenForExport public static OOError noDataBaseIsOpenForExport() { return new OOError( - Localization.lang("No database is open"), - Localization.lang("We need a database to export from. Open one.")); + Localization.lang("No database is open"), + Localization.lang("We need a database to export from. Open one.")); } // noDataBaseIsOpenForExport public static OOError noDataBaseIsOpen() { return new OOError( - Localization.lang("No database is open"), - Localization.lang("This operation requires a bibliography database.")); + Localization.lang("No database is open"), + Localization.lang("This operation requires a bibliography database.")); } // noValidStyleSelected public static OOError noValidStyleSelected() { return new OOError(Localization.lang("No valid style file defined"), - Localization.lang("No bibliography style is selected for citation.") - + "\n" - + Localization.lang("Select one before citing.") - + "\n" - + Localization.lang("You must select either a valid style file," - + " or use one of the default styles.")); + Localization.lang("No bibliography style is selected for citation.") + + "\n" + + Localization.lang("Select one before citing.") + + "\n" + + Localization.lang("You must select either a valid style file," + + " or use one of the default styles.")); } // noEntriesSelectedForCitation public static OOError noEntriesSelectedForCitation() { return new OOError(Localization.lang("No entries selected for citation"), - Localization.lang("No bibliography entries are selected for citation.") - + "\n" - + Localization.lang("Select some before citing.")); + Localization.lang("No bibliography entries are selected for citation.") + + "\n" + + Localization.lang("Select some before citing.")); } } diff --git a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java index e1127163fb3..07e97b7ca81 100644 --- a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java +++ b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java @@ -90,19 +90,19 @@ public class OpenOfficePanel { private final UndoManager undoManager; private final TaskExecutor taskExecutor; private final StyleLoader loader; - private OpenOfficePreferences ooPrefs; - private OOBibBase2 ooBase; + private OpenOfficePreferences openOfficePreferences; + private OOBibBase ooBase; private OOBibStyle style; public OpenOfficePanel(PreferencesService preferencesService, - OpenOfficePreferences ooPrefs, + OpenOfficePreferences openOfficePreferences, KeyBindingRepository keyBindingRepository, TaskExecutor taskExecutor, DialogService dialogService, StateManager stateManager, UndoManager undoManager) { ActionFactory factory = new ActionFactory(keyBindingRepository); - this.ooPrefs = ooPrefs; + this.openOfficePreferences = openOfficePreferences; this.preferencesService = preferencesService; this.taskExecutor = taskExecutor; this.dialogService = dialogService; @@ -132,7 +132,7 @@ public OpenOfficePanel(PreferencesService preferencesService, update.setTooltip(new Tooltip(Localization.lang("Sync OpenOffice/LibreOffice bibliography"))); update.setMaxWidth(Double.MAX_VALUE); - loader = new StyleLoader(ooPrefs, + loader = new StyleLoader(openOfficePreferences, preferencesService.getLayoutFormatterPreferences(Globals.journalAbbreviationRepository), preferencesService.getGeneralPreferences().getDefaultEncoding()); @@ -159,8 +159,8 @@ private boolean getOrUpdateTheStyle(String title) { } catch (IOException ex) { LOGGER.warn("Unable to reload style file '" + style.getPath() + "'", ex); String msg = (Localization.lang("Unable to reload style file") - + "'" + style.getPath() + "'" - + "\n" + ex.getMessage()); + + "'" + style.getPath() + "'" + + "\n" + ex.getMessage()); new OOError(title, msg, ex).showErrorDialog(dialogService); return FAIL; } @@ -227,10 +227,10 @@ private void initPanel() { settingsB.setOnAction(e -> settingsMenu.show(settingsB, Side.BOTTOM, 0, 0)); manageCitations.setMaxWidth(Double.MAX_VALUE); manageCitations.setOnAction(e -> { - ManageCitationsDialogView dialog = new ManageCitationsDialogView(ooBase); - if (dialog.isOkToShowThisDialog()) { - dialogService.showCustomDialogAndWait(dialog); - } + ManageCitationsDialogView dialog = new ManageCitationsDialogView(ooBase); + if (dialog.isOkToShowThisDialog()) { + dialogService.showCustomDialogAndWait(dialog); + } }); exportCitations.setMaxWidth(Double.MAX_VALUE); @@ -256,7 +256,6 @@ private void initPanel() { } private void exportEntries() { - final String title = Localization.lang("Problem generating new database."); List databases = getBaseList(); boolean returnPartialResult = false; Optional newDatabase = ooBase.exportCitedHelper(databases, returnPartialResult); @@ -268,7 +267,7 @@ private void exportEntries() { private List getBaseList() { List databases = new ArrayList<>(); - if (ooPrefs.getUseAllDatabases()) { + if (openOfficePreferences.getUseAllDatabases()) { for (BibDatabaseContext database : stateManager.getOpenDatabases()) { databases.add(database.getDatabase()); } @@ -329,7 +328,6 @@ private void connectManually() { connect(); } else { dialogService.showErrorDialogAndWait(Localization.lang("Could not connect to running OpenOffice/LibreOffice."), Localization.lang("If connecting manually, please verify program and library paths.")); - } }) .executeWith(taskExecutor); @@ -365,15 +363,15 @@ private void updateButtonAvailability() { } private void connect() { - ooPrefs = preferencesService.getOpenOfficePreferences(); + openOfficePreferences = preferencesService.getOpenOfficePreferences(); - Task connectTask = new Task<>() { + Task connectTask = new Task<>() { @Override - protected OOBibBase2 call() throws Exception { + protected OOBibBase call() throws Exception { updateProgress(ProgressBar.INDETERMINATE_PROGRESS, ProgressBar.INDETERMINATE_PROGRESS); - var path = Path.of(ooPrefs.getExecutablePath()); + var path = Path.of(openOfficePreferences.getExecutablePath()); return createBibBase(path); } }; @@ -393,16 +391,16 @@ protected OOBibBase2 call() throws Exception { LOGGER.warn("Could not connect to running OpenOffice/LibreOffice", ex); dialogService.showErrorDialogAndWait(Localization.lang("Unable to connect. One possible reason is that JabRef " - + "and OpenOffice/LibreOffice are not both running in either 32 bit mode or 64 bit mode.")); + + "and OpenOffice/LibreOffice are not both running in either 32 bit mode or 64 bit mode.")); } else if (ex instanceof IOException) { LOGGER.warn("Could not connect to running OpenOffice/LibreOffice", ex); dialogService.showErrorDialogAndWait(Localization.lang("Could not connect to running OpenOffice/LibreOffice."), - Localization.lang("Could not connect to running OpenOffice/LibreOffice.") - + "\n" - + Localization.lang("Make sure you have installed OpenOffice/LibreOffice with Java support.") + "\n" - + Localization.lang("If connecting manually, please verify program and library paths.") + "\n" + "\n" + Localization.lang("Error message:"), - ex); + Localization.lang("Could not connect to running OpenOffice/LibreOffice.") + + "\n" + + Localization.lang("Make sure you have installed OpenOffice/LibreOffice with Java support.") + "\n" + + Localization.lang("If connecting manually, please verify program and library paths.") + "\n" + "\n" + Localization.lang("Error message:"), + ex); } else { dialogService.showErrorDialogAndWait(Localization.lang("Autodetection failed"), Localization.lang("Autodetection failed"), ex); } @@ -412,17 +410,15 @@ protected OOBibBase2 call() throws Exception { taskExecutor.execute(connectTask); } - private OOBibBase2 createBibBase(Path loPath) throws BootstrapException, CreationException { - return new OOBibBase2(loPath, dialogService); + private OOBibBase createBibBase(Path loPath) throws BootstrapException, CreationException { + return new OOBibBase(loPath, dialogService); } /** - * Given the withText and inParenthesis options, - * return the corresponding citationType. + * Given the withText and inParenthesis options, return the corresponding citationType. * - * @param withText False means invisible citation (no text). - * @param inParenthesis True means "(Au and Thor 2000)". - * False means "Au and Thor (2000)". + * @param withText False means invisible citation (no text). + * @param inParenthesis True means "(Au and Thor 2000)". False means "Au and Thor (2000)". */ private static CitationType citationTypeFromOptions(boolean withText, boolean inParenthesis) { if (!withText) { @@ -447,16 +443,16 @@ private void pushEntries(CitationType citationType, boolean addPageInfo) { final BibDatabase database = stateManager.getActiveDatabase().get().getDatabase(); if (database == null) { OOError.noDataBaseIsOpenForCiting() - .setTitle(errorDialogTitle) - .showErrorDialog(dialogService); + .setTitle(errorDialogTitle) + .showErrorDialog(dialogService); return; } List entries = stateManager.getSelectedEntries(); if (entries.isEmpty()) { OOError.noEntriesSelectedForCitation() - .setTitle(errorDialogTitle) - .showErrorDialog(dialogService); + .setTitle(errorDialogTitle) + .showErrorDialog(dialogService); return; } @@ -490,16 +486,16 @@ private void pushEntries(CitationType citationType, boolean addPageInfo) { } Optional syncOptions = - (ooPrefs.getSyncWhenCiting() - ? Optional.of(new Update.SyncOptions(getBaseList())) - : Optional.empty()); + (openOfficePreferences.getSyncWhenCiting() + ? Optional.of(new Update.SyncOptions(getBaseList())) + : Optional.empty()); ooBase.guiActionInsertEntry(entries, - database, - style, - citationType, - pageInfo, - syncOptions); + database, + style, + citationType, + pageInfo, + syncOptions); } /** @@ -559,7 +555,7 @@ private ContextMenu createSettingsPopup() { ContextMenu contextMenu = new ContextMenu(); CheckMenuItem autoSync = new CheckMenuItem(Localization.lang("Automatically sync bibliography when inserting citations")); - autoSync.selectedProperty().set(ooPrefs.getSyncWhenCiting()); + autoSync.selectedProperty().set(openOfficePreferences.getSyncWhenCiting()); ToggleGroup toggleGroup = new ToggleGroup(); RadioMenuItem useActiveBase = new RadioMenuItem(Localization.lang("Look up BibTeX entries in the active tab only")); @@ -569,28 +565,28 @@ private ContextMenu createSettingsPopup() { MenuItem clearConnectionSettings = new MenuItem(Localization.lang("Clear connection settings")); - if (ooPrefs.getUseAllDatabases()) { + if (openOfficePreferences.getUseAllDatabases()) { useAllBases.setSelected(true); } else { useActiveBase.setSelected(true); } autoSync.setOnAction(e -> { - ooPrefs.setSyncWhenCiting(autoSync.isSelected()); - preferencesService.setOpenOfficePreferences(ooPrefs); + openOfficePreferences.setSyncWhenCiting(autoSync.isSelected()); + preferencesService.setOpenOfficePreferences(openOfficePreferences); }); useAllBases.setOnAction(e -> { - ooPrefs.setUseAllDatabases(useAllBases.isSelected()); - preferencesService.setOpenOfficePreferences(ooPrefs); + openOfficePreferences.setUseAllDatabases(useAllBases.isSelected()); + preferencesService.setOpenOfficePreferences(openOfficePreferences); }); useActiveBase.setOnAction(e -> { - ooPrefs.setUseAllDatabases(!useActiveBase.isSelected()); - preferencesService.setOpenOfficePreferences(ooPrefs); + openOfficePreferences.setUseAllDatabases(!useActiveBase.isSelected()); + preferencesService.setOpenOfficePreferences(openOfficePreferences); }); clearConnectionSettings.setOnAction(e -> { - ooPrefs.clearConnectionSettings(); + openOfficePreferences.clearConnectionSettings(); dialogService.notify(Localization.lang("Cleared connection settings")); - preferencesService.setOpenOfficePreferences(ooPrefs); + preferencesService.setOpenOfficePreferences(openOfficePreferences); }); contextMenu.getItems().addAll(autoSync, new SeparatorMenuItem(), useActiveBase, useAllBases, new SeparatorMenuItem(), clearConnectionSettings); diff --git a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java index 6792d2fbb8e..5435dda2abd 100644 --- a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java +++ b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java @@ -36,6 +36,7 @@ public class StyleSelectDialogView extends BaseDialog { private final MenuItem edit = new MenuItem(Localization.lang("Edit")); private final MenuItem reload = new MenuItem(Localization.lang("Reload")); private final StyleLoader loader; + @FXML private TableColumn colName; @FXML private TableView tvStyles; @FXML private TableColumn colJournals; diff --git a/src/main/java/org/jabref/logic/openoffice/OpenOfficeFileSearch.java b/src/main/java/org/jabref/logic/openoffice/OpenOfficeFileSearch.java index 309096b08cf..dd59b8a09bf 100644 --- a/src/main/java/org/jabref/logic/openoffice/OpenOfficeFileSearch.java +++ b/src/main/java/org/jabref/logic/openoffice/OpenOfficeFileSearch.java @@ -43,8 +43,9 @@ public static List detectInstallations() { private static List findOpenOfficeDirectories(List programDirectories) { - BiPredicate filePredicate = (path, attr) -> attr.isDirectory() && (path.toString().toLowerCase(Locale.ROOT).contains("openoffice") - || path.toString().toLowerCase(Locale.ROOT).contains("libreoffice")); + BiPredicate filePredicate = (path, attr) -> + attr.isDirectory() && (path.toString().toLowerCase(Locale.ROOT).contains("openoffice") + || path.toString().toLowerCase(Locale.ROOT).contains("libreoffice")); return programDirectories.stream().flatMap(dirs -> { try { diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java index 0004d3fe6db..9c171553a4b 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditInsert.java @@ -32,17 +32,14 @@ public class EditInsert { private EditInsert() { - /**/ } /** * In insertEntry we receive BibEntry values from the GUI. - * + *

    * In the document we store citations by their citation key. - * - * If the citation key is missing, the best we can do is to notify the user. Or the programmer, - * that we cannot accept such input. - * + *

    + * If the citation key is missing, the best we can do is to notify the user. Or the programmer, that we cannot accept such input. */ private static String insertEntryGetCitationKey(BibEntry entry) { Optional key = entry.getCitationKey(); @@ -53,7 +50,7 @@ private static String insertEntryGetCitationKey(BibEntry entry) { } /** - * @param cursor Where to insert. + * @param cursor Where to insert. * @param pageInfo A single pageInfo for a list of entries. This is what we get from the GUI. */ public static void insertCitationGroup(XTextDocument doc, @@ -64,13 +61,13 @@ public static void insertCitationGroup(XTextDocument doc, OOBibStyle style, CitationType citationType, String pageInfo) - throws - NoDocumentException, - NotRemoveableException, - WrappedTargetException, - PropertyVetoException, - CreationException, - IllegalTypeException { + throws + NoDocumentException, + NotRemoveableException, + WrappedTargetException, + PropertyVetoException, + CreationException, + IllegalTypeException { List citationKeys = OOListUtil.map(entries, EditInsert::insertEntryGetCitationKey); @@ -86,13 +83,13 @@ public static void insertCitationGroup(XTextDocument doc, } // The text we insert - OOText citeText = null; + OOText citeText; if (style.isNumberEntries()) { citeText = OOText.fromString("[-]"); // A dash only. Only refresh later. } else { citeText = style.createCitationMarker(citations, - citationType.inParenthesis(), - NonUniqueCitationMarker.FORGIVEN); + citationType.inParenthesis(), + NonUniqueCitationMarker.FORGIVEN); } if (StringUtil.isBlank(OOText.toString(citeText))) { @@ -102,17 +99,16 @@ public static void insertCitationGroup(XTextDocument doc, try { UnoScreenRefresh.lockControllers(doc); UpdateCitationMarkers.createAndFillCitationGroup(frontend, - doc, - citationKeys, - pageInfos, - citationType, - citeText, - cursor, - style, - true /* insertSpaceAfter */); + doc, + citationKeys, + pageInfos, + citationType, + citeText, + cursor, + style, + true /* insertSpaceAfter */); } finally { UnoScreenRefresh.unlockControllers(doc); } - } } diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java index f91e8aec93d..a927a205442 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java @@ -34,21 +34,20 @@ public class EditMerge { private static final Logger LOGGER = LoggerFactory.getLogger(EditMerge.class); private EditMerge() { - // hide constructor } /* * @return true if modified document */ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend frontend, OOBibStyle style) - throws - CreationException, - IllegalArgumentException, - IllegalTypeException, - NoDocumentException, - NotRemoveableException, - PropertyVetoException, - WrappedTargetException { + throws + CreationException, + IllegalArgumentException, + IllegalTypeException, + NoDocumentException, + NotRemoveableException, + PropertyVetoException, + WrappedTargetException { boolean madeModifications; @@ -62,8 +61,8 @@ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend frontend List groups = joinableGroupData.group; List newCitations = (groups.stream() - .flatMap(group -> group.citationsInStorageOrder.stream()) - .collect(Collectors.toList())); + .flatMap(group -> group.citationsInStorageOrder.stream()) + .collect(Collectors.toList())); CitationType citationType = groups.get(0).citationType; List> pageInfos = frontend.backend.combinePageInfos(groups); @@ -77,18 +76,17 @@ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend frontend /* insertSpaceAfter: no, it is already there (or could be) */ boolean insertSpaceAfter = false; UpdateCitationMarkers.createAndFillCitationGroup(frontend, - doc, - citationKeys, - pageInfos, - citationType, - OOText.fromString("tmp"), - textCursor, - style, - insertSpaceAfter); + doc, + citationKeys, + pageInfos, + citationType, + OOText.fromString("tmp"), + textCursor, + style, + insertSpaceAfter); } madeModifications = !joinableGroups.isEmpty(); - } finally { UnoScreenRefresh.unlockControllers(doc); } @@ -97,10 +95,14 @@ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend frontend } private static class JoinableGroupData { - /** A list of consecutive citation groups only separated by spaces. */ + /** + * A list of consecutive citation groups only separated by spaces. + */ List group; - /** A cursor covering the XTextRange of each entry in group (and the spaces between them) */ + /** + * A cursor covering the XTextRange of each entry in group (and the spaces between them) + */ XTextCursor groupCursor; JoinableGroupData(List group, XTextCursor groupCursor) { @@ -147,11 +149,9 @@ void reset() { /** * Decide if group could be added to state.currentGroup * - * @param group The CitationGroup to test + * @param group The CitationGroup to test * @param currentRange The XTextRange corresponding to group. - * - * @return false if cannot add, true if can. If returned true, then state.cursorBetween and - * state.currentGroupCursor are expanded to end at the start of currentRange. + * @return false if cannot add, true if can. If returned true, then state.cursorBetween and state.currentGroupCursor are expanded to end at the start of currentRange. */ private static boolean checkAddToGroup(ScanState state, CitationGroup group, XTextRange currentRange) { @@ -184,14 +184,14 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup group, XTe int textOrder = UnoTextRange.compareStarts(state.prevRange, currentRange); if (textOrder != (-1)) { String msg = - String.format("MergeCitationGroups:" - + " \"%s\" supposed to be followed by \"%s\"," - + " but %s", - state.prevRange.getString(), - currentRange.getString(), - ((textOrder == 0) - ? "they start at the same position" - : "the start of the latter precedes the start of the first")); + String.format("MergeCitationGroups:" + + " \"%s\" supposed to be followed by \"%s\"," + + " but %s", + state.prevRange.getString(), + currentRange.getString(), + ((textOrder == 0) + ? "they start at the same position" + : "the start of the latter precedes the start of the first")); LOGGER.warn(msg); return false; } @@ -217,7 +217,7 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup group, XTe XTextRange rangeStart = currentRange.getStart(); boolean couldExpand = true; XTextCursor thisCharCursor = - (currentRange.getText().createTextCursorByRange(state.cursorBetween.getEnd())); + (currentRange.getText().createTextCursorByRange(state.cursorBetween.getEnd())); while (couldExpand && (UnoTextRange.compareEnds(state.cursorBetween, rangeStart) < 0)) { // @@ -247,10 +247,7 @@ private static boolean checkAddToGroup(ScanState state, CitationGroup group, XTe } /** - * Add group to state.currentGroup - * Set state.cursorBetween to start at currentRange.getEnd() - * Expand state.currentGroupCursor to also cover currentRange - * Set state.prev to group, state.prevRange to currentRange + * Add group to state.currentGroup Set state.cursorBetween to start at currentRange.getEnd() Expand state.currentGroupCursor to also cover currentRange Set state.prev to group, state.prevRange to currentRange */ private static void addToCurrentGroup(ScanState state, CitationGroup group, XTextRange currentRange) { final boolean isNewGroup = state.currentGroup.isEmpty(); @@ -271,7 +268,7 @@ private static void addToCurrentGroup(ScanState state, CitationGroup group, XTex // If new group, create currentGroupCursor if (isNewGroup) { state.currentGroupCursor = (currentRange.getText() - .createTextCursorByRange(currentRange.getStart())); + .createTextCursorByRange(currentRange.getStart())); } // include currentRange in currentGroupCursor @@ -288,12 +285,12 @@ private static void addToCurrentGroup(ScanState state, CitationGroup group, XTex } /** - * Scan the document for joinable groups. Return those found. + * Scan the document for joinable groups. Return those found. */ private static List scan(XTextDocument doc, OOFrontend frontend) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { List result = new ArrayList<>(); List groups = frontend.getCitationGroupsSortedWithinPartitions(doc, false /* mapFootnotesToFootnoteMarks */); @@ -306,7 +303,7 @@ private static List scan(XTextDocument doc, OOFrontend fronte for (CitationGroup group : groups) { XTextRange currentRange = (frontend.getMarkRange(doc, group) - .orElseThrow(IllegalStateException::new)); + .orElseThrow(IllegalStateException::new)); /* * Decide if we add group to the group. False when the group is empty. @@ -340,5 +337,4 @@ private static List scan(XTextDocument doc, OOFrontend fronte } return result; } - } diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java index 66630a6f8d0..101dffb813a 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditSeparate.java @@ -25,21 +25,20 @@ public class EditSeparate { private EditSeparate() { - /**/ } public static boolean separateCitations(XTextDocument doc, OOFrontend frontend, List databases, OOBibStyle style) - throws - CreationException, - IllegalTypeException, - NoDocumentException, - NotRemoveableException, - PropertyVetoException, - WrappedTargetException, - com.sun.star.lang.IllegalArgumentException { + throws + CreationException, + IllegalTypeException, + NoDocumentException, + NotRemoveableException, + PropertyVetoException, + WrappedTargetException, + com.sun.star.lang.IllegalArgumentException { boolean madeModifications = false; @@ -58,8 +57,8 @@ public static boolean separateCitations(XTextDocument doc, for (CitationGroup group : groups) { XTextRange range1 = (frontend - .getMarkRange(doc, group) - .orElseThrow(IllegalStateException::new)); + .getMarkRange(doc, group) + .orElseThrow(IllegalStateException::new)); XTextCursor textCursor = range1.getText().createTextCursorByRange(range1); List citations = group.citationsInStorageOrder; @@ -77,14 +76,14 @@ public static boolean separateCitations(XTextDocument doc, Citation citation = citations.get(i); UpdateCitationMarkers.createAndFillCitationGroup(frontend, - doc, - List.of(citation.citationKey), - List.of(citation.getPageInfo()), - group.citationType, - OOText.fromString(citation.citationKey), - textCursor, - style, - insertSpaceAfter); + doc, + List.of(citation.citationKey), + List.of(citation.getPageInfo()), + group.citationType, + OOText.fromString(citation.citationKey), + textCursor, + style, + insertSpaceAfter); textCursor.collapseToEnd(); } diff --git a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java index c38cd4fd4cc..a5a55fa5b18 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java +++ b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java @@ -19,7 +19,6 @@ public class ExportCited { private ExportCited() { - /**/ } public static class GenerateDatabaseResult { @@ -36,20 +35,16 @@ public static class GenerateDatabaseResult { } /** - * * @param databases The databases to look up the citation keys in the document from. * @return A new database, with cloned entries. - * * If a key is not found, it is added to result.unresolvedKeys - * - * Cross references (in StandardField.CROSSREF) are followed (not recursively): - * If the referenced entry is found, it is included in the result. - * If it is not found, it is silently ignored. + *

    + * Cross references (in StandardField.CROSSREF) are followed (not recursively): If the referenced entry is found, it is included in the result. If it is not found, it is silently ignored. */ public static GenerateDatabaseResult generateDatabase(XTextDocument doc, List databases) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { OOFrontend frontend = new OOFrontend(doc); CitedKeys citationKeys = frontend.citationGroups.getCitedKeysUnordered(); @@ -77,14 +72,14 @@ public static GenerateDatabaseResult generateDatabase(XTextDocument doc, List { + .getField(StandardField.CROSSREF) + .ifPresent(crossReference -> { boolean isNew = !seen.contains(crossReference); if (isNew) { // Add it if it is in the current library loopDatabase - .getEntryByCitationKey(crossReference) - .ifPresent(entriesToInsert::add); + .getEntryByCitationKey(crossReference) + .ifPresent(entriesToInsert::add); seen.add(crossReference); } }); @@ -94,5 +89,4 @@ public static GenerateDatabaseResult generateDatabase(XTextDocument doc, List getCitationEntries(XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { OOFrontend frontend = new OOFrontend(doc); return frontend.getCitationEntries(doc); } public static void applyCitationEntries(XTextDocument doc, List citationEntries) - throws - NoDocumentException, - PropertyVetoException, - IllegalTypeException, - WrappedTargetException, - IllegalArgumentException { + throws + NoDocumentException, + PropertyVetoException, + IllegalTypeException, + WrappedTargetException, + IllegalArgumentException { OOFrontend frontend = new OOFrontend(doc); frontend.applyCitationEntries(doc, citationEntries); } diff --git a/src/main/java/org/jabref/logic/openoffice/action/Update.java b/src/main/java/org/jabref/logic/openoffice/action/Update.java index c05c460b4cf..89419b43507 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/Update.java +++ b/src/main/java/org/jabref/logic/openoffice/action/Update.java @@ -34,11 +34,11 @@ private static List updateDocument(XTextDocument doc, FunctionalTextViewCursor fcursor, boolean doUpdateBibliography, boolean alwaysAddCitedOnPages) - throws - CreationException, - NoDocumentException, - WrappedTargetException, - com.sun.star.lang.IllegalArgumentException { + throws + CreationException, + NoDocumentException, + WrappedTargetException, + com.sun.star.lang.IllegalArgumentException { final boolean useLockControllers = true; @@ -54,10 +54,10 @@ private static List updateDocument(XTextDocument doc, if (doUpdateBibliography) { UpdateBibliography.rebuildBibTextSection(doc, - frontend, - frontend.citationGroups.getBibliography().get(), - style, - alwaysAddCitedOnPages); + frontend, + frontend.citationGroups.getBibliography().get(), + style, + alwaysAddCitedOnPages); } return frontend.citationGroups.getUnresolvedKeys(); @@ -96,19 +96,19 @@ public static List synchronizeDocument(XTextDocument doc, OOBibStyle style, FunctionalTextViewCursor fcursor, SyncOptions syncOptions) - throws - CreationException, - NoDocumentException, - WrappedTargetException, - com.sun.star.lang.IllegalArgumentException { + throws + CreationException, + NoDocumentException, + WrappedTargetException, + com.sun.star.lang.IllegalArgumentException { return Update.updateDocument(doc, - frontend, - syncOptions.databases, - style, - fcursor, - syncOptions.updateBibliography, - syncOptions.alwaysAddCitedOnPages); + frontend, + syncOptions.databases, + style, + fcursor, + syncOptions.updateBibliography, + syncOptions.alwaysAddCitedOnPages); } /* @@ -118,15 +118,14 @@ public static List resyncDocument(XTextDocument doc, OOBibStyle style, FunctionalTextViewCursor fcursor, SyncOptions syncOptions) - throws - CreationException, - NoDocumentException, - WrappedTargetException, - com.sun.star.lang.IllegalArgumentException { + throws + CreationException, + NoDocumentException, + WrappedTargetException, + com.sun.star.lang.IllegalArgumentException { OOFrontend frontend = new OOFrontend(doc); return Update.synchronizeDocument(doc, frontend, style, fcursor, syncOptions); } - } diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java index 4a0d8d05e0e..7899bc21076 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java @@ -37,9 +37,7 @@ import org.slf4j.LoggerFactory; /** - * Backend52, Codec52 and OODataModel.JabRef52 refer to the mode of storage, encoding and - * what-is-stored in the document under JabRef version 5.2. These basically did not change up to - * JabRef 5.4. + * Backend52, Codec52 and OODataModel.JabRef52 refer to the mode of storage, encoding and what-is-stored in the document under JabRef version 5.2. These basically did not change up to JabRef 5.4. */ public class Backend52 { private static final Logger LOGGER = LoggerFactory.getLogger(Backend52.class); @@ -55,25 +53,21 @@ public Backend52() { } /** - * Get reference mark names from the document matching the pattern - * used for JabRef reference mark names. - * + * Get reference mark names from the document matching the pattern used for JabRef reference mark names. + *

    * Note: the names returned are in arbitrary order. - * */ public List getJabRefReferenceMarkNames(XTextDocument doc) - throws - NoDocumentException { + throws + NoDocumentException { List allNames = this.citationStorageManager.getUsedNames(doc); return Codec52.filterIsJabRefReferenceMarkName(allNames); } /** - * Names of custom properties belonging to us, but without a corresponding reference mark. - * These can be deleted. + * Names of custom properties belonging to us, but without a corresponding reference mark. These can be deleted. * * @param citationGroupNames These are the names that are used. - * */ private List findUnusedJabrefPropertyNames(XTextDocument doc, List citationGroupNames) { @@ -82,10 +76,10 @@ private List findUnusedJabrefPropertyNames(XTextDocument doc, List pageInfoThrash = new ArrayList<>(); List jabrefPropertyNames = - UnoUserDefinedProperty.getListOfNames(doc) - .stream() - .filter(Codec52::isJabRefReferenceMarkName) - .collect(Collectors.toList()); + UnoUserDefinedProperty.getListOfNames(doc) + .stream() + .filter(Codec52::isJabRefReferenceMarkName) + .toList(); for (String pn : jabrefPropertyNames) { if (!citationGroupNamesSet.contains(pn)) { pageInfoThrash.add(pn); @@ -95,21 +89,21 @@ private List findUnusedJabrefPropertyNames(XTextDocument doc, } /** - * @return Optional.empty if all is OK, message text otherwise. + * @return Optional.empty if all is OK, message text otherwise. */ public Optional healthReport(XTextDocument doc) - throws - NoDocumentException { + throws + NoDocumentException { List pageInfoThrash = - this.findUnusedJabrefPropertyNames(doc, this.getJabRefReferenceMarkNames(doc)); + this.findUnusedJabrefPropertyNames(doc, this.getJabRefReferenceMarkNames(doc)); if (pageInfoThrash.isEmpty()) { return Optional.empty(); } - StringBuilder msg = new StringBuilder("Backend52: found unused pageInfo data, with names listed below.\n"); - msg.append("In LibreOffice you may remove these in [File]/[Properties]/[Custom Properties]\n"); - msg.append(String.join("\n", pageInfoThrash)); - return Optional.of(msg.toString()); + String msg = "Backend52: found unused pageInfo data, with names listed below.\n" + + "In LibreOffice you may remove these in [File]/[Properties]/[Custom Properties]\n" + + String.join("\n", pageInfoThrash); + return Optional.of(msg); } private static void setPageInfoInDataInitial(List citations, Optional pageInfo) { @@ -131,51 +125,44 @@ private static Optional getPageInfoFromData(CitationGroup group) { * @param markName Reference mark name */ public CitationGroup readCitationGroupFromDocumentOrThrow(XTextDocument doc, String markName) - throws - WrappedTargetException, - NoDocumentException { + throws + WrappedTargetException, + NoDocumentException { Codec52.ParsedMarkName parsed = Codec52.parseMarkName(markName).orElseThrow(IllegalArgumentException::new); List citations = (parsed.citationKeys.stream() - .map(Citation::new) - .collect(Collectors.toList())); + .map(Citation::new) + .collect(Collectors.toList())); Optional pageInfo = (UnoUserDefinedProperty.getStringValue(doc, markName) - .map(OOText::fromString)); + .map(OOText::fromString)); pageInfo = PageInfo.normalizePageInfo(pageInfo); setPageInfoInDataInitial(citations, pageInfo); NamedRange namedRange = (citationStorageManager.getNamedRangeFromDocument(doc, markName) - .orElseThrow(IllegalArgumentException::new)); + .orElseThrow(IllegalArgumentException::new)); CitationGroupId groupId = new CitationGroupId(markName); CitationGroup group = new CitationGroup(OODataModel.JabRef52, - groupId, - parsed.citationType, - citations, - Optional.of(markName)); + groupId, + parsed.citationType, + citations, + Optional.of(markName)); this.cgidToNamedRange.put(groupId, namedRange); return group; } /** - * Create a reference mark at the end of {@code position} in the document. - * - * On return {@code position} is collapsed, and is after the inserted space, or at the end of - * the reference mark. - * - * @param citationKeys Keys to be cited. - * - * @param pageInfos An optional pageInfo for each citation key. - * Backend52 only uses and stores the last pageInfo, - * all others should be Optional.empty() + * Create a reference mark at the end of {@code position} in the document. + *

    + * On return {@code position} is collapsed, and is after the inserted space, or at the end of the reference mark. * - * @param position Collapsed to its end. - * - * @param insertSpaceAfter We insert a space after the mark, that carries on format of - * characters from the original position. + * @param citationKeys Keys to be cited. + * @param pageInfos An optional pageInfo for each citation key. Backend52 only uses and stores the last pageInfo, all others should be Optional.empty() + * @param position Collapsed to its end. + * @param insertSpaceAfter We insert a space after the mark, that carries on format of characters from the original position. */ public CitationGroup createCitationGroup(XTextDocument doc, List citationKeys, @@ -183,13 +170,13 @@ public CitationGroup createCitationGroup(XTextDocument doc, CitationType citationType, XTextCursor position, boolean insertSpaceAfter) - throws - CreationException, - NoDocumentException, - WrappedTargetException, - NotRemoveableException, - PropertyVetoException, - IllegalTypeException { + throws + CreationException, + NoDocumentException, + WrappedTargetException, + NotRemoveableException, + PropertyVetoException, + IllegalTypeException { Objects.requireNonNull(pageInfos); if (pageInfos.size() != citationKeys.size()) { @@ -213,7 +200,7 @@ public CitationGroup createCitationGroup(XTextDocument doc, } else { if (pageInfo.isPresent()) { LOGGER.warn("dataModel JabRef52" - + " only supports pageInfo for the last citation of a group"); + + " only supports pageInfo for the last citation of a group"); } } break; @@ -231,8 +218,8 @@ public CitationGroup createCitationGroup(XTextDocument doc, * has to be unique in the document. */ final String markName = Codec52.getUniqueMarkName(new HashSet<>(citationStorageManager.getUsedNames(doc)), - citationKeys, - citationType); + citationKeys, + citationType); final CitationGroupId groupId = new CitationGroupId(markName); @@ -241,10 +228,10 @@ public CitationGroup createCitationGroup(XTextDocument doc, */ boolean withoutBrackets = (citationType == CitationType.INVISIBLE_CIT); NamedRange namedRange = this.citationStorageManager.createNamedRange(doc, - markName, - position, - insertSpaceAfter, - withoutBrackets); + markName, + position, + insertSpaceAfter, + withoutBrackets); switch (dataModel) { case JabRef52: @@ -258,9 +245,9 @@ public CitationGroup createCitationGroup(XTextDocument doc, UnoUserDefinedProperty.removeIfExists(doc, markName); } CitationGroup group = new CitationGroup(OODataModel.JabRef52, - groupId, - citationType, citations, - Optional.of(markName)); + groupId, + citationType, citations, + Optional.of(markName)); this.cgidToNamedRange.put(groupId, namedRange); return group; case JabRef60: @@ -272,8 +259,7 @@ public CitationGroup createCitationGroup(XTextDocument doc, /** * @return A list with a nullable pageInfo entry for each citation in joinableGroups. - * - * TODO: JabRef52 combinePageInfos is not reversible. Should warn user to check the result. Or + * TODO: JabRef52 combinePageInfos is not reversible. Should warn user to check the result. Or * ask what to do. */ public static List> @@ -282,18 +268,18 @@ public CitationGroup createCitationGroup(XTextDocument doc, case JabRef52: // collect to pageInfos List> pageInfos = OOListUtil.map(joinableGroup, - Backend52::getPageInfoFromData); + Backend52::getPageInfoFromData); // Try to do something of the pageInfos. String singlePageInfo = (pageInfos.stream() - .filter(Optional::isPresent) - .map(pi -> OOText.toString(pi.get())) - .distinct() - .collect(Collectors.joining("; "))); + .filter(Optional::isPresent) + .map(pi -> OOText.toString(pi.get())) + .distinct() + .collect(Collectors.joining("; "))); int totalCitations = (joinableGroup.stream() - .map(CitationGroup::numberOfCitations) - .mapToInt(Integer::intValue).sum()); + .map(CitationGroup::numberOfCitations) + .mapToInt(Integer::intValue).sum()); if ("".equals(singlePageInfo)) { singlePageInfo = null; } @@ -301,9 +287,9 @@ public CitationGroup createCitationGroup(XTextDocument doc, case JabRef60: return (joinableGroup.stream() - .flatMap(group -> (group.citationsInStorageOrder.stream() - .map(Citation::getPageInfo))) - .collect(Collectors.toList())); + .flatMap(group -> (group.citationsInStorageOrder.stream() + .map(Citation::getPageInfo))) + .collect(Collectors.toList())); default: throw new IllegalArgumentException("unhandled dataModel here"); } @@ -325,10 +311,10 @@ private NamedRange getNamedRangeOrThrow(CitationGroup group) { } public void removeCitationGroup(CitationGroup group, XTextDocument doc) - throws - WrappedTargetException, - NoDocumentException, - NotRemoveableException { + throws + WrappedTargetException, + NoDocumentException, + NotRemoveableException { NamedRange namedRange = getNamedRangeOrThrow(group); String refMarkName = namedRange.getRangeName(); namedRange.removeFromDocument(doc); @@ -340,22 +326,21 @@ public void removeCitationGroup(CitationGroup group, XTextDocument doc) * @return Optional.empty if the reference mark is missing. */ public Optional getMarkRange(CitationGroup group, XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { NamedRange namedRange = getNamedRangeOrThrow(group); return namedRange.getMarkRange(doc); } /** - * Cursor for the reference marks as is: not prepared for filling, but does not need - * cleanFillCursorForCitationGroup either. + * Cursor for the reference marks as is: not prepared for filling, but does not need cleanFillCursorForCitationGroup either. */ public Optional getRawCursorForCitationGroup(CitationGroup group, XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { NamedRange namedRange = getNamedRangeOrThrow(group); return namedRange.getRawCursor(doc); } @@ -364,28 +349,30 @@ public Optional getRawCursorForCitationGroup(CitationGroup group, X * Must be followed by call to cleanFillCursorForCitationGroup */ public XTextCursor getFillCursorForCitationGroup(CitationGroup group, XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException, - CreationException { + throws + NoDocumentException, + WrappedTargetException, + CreationException { NamedRange namedRange = getNamedRangeOrThrow(group); return namedRange.getFillCursor(doc); } - /** To be called after getFillCursorForCitationGroup */ + /** + * To be called after getFillCursorForCitationGroup + */ public void cleanFillCursorForCitationGroup(CitationGroup group, XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { NamedRange namedRange = getNamedRangeOrThrow(group); namedRange.cleanFillCursor(doc); } public List getCitationEntries(XTextDocument doc, CitationGroups cgs) - throws - WrappedTargetException, - NoDocumentException { + throws + WrappedTargetException, + NoDocumentException { switch (dataModel) { case JabRef52: @@ -395,13 +382,13 @@ public List getCitationEntries(XTextDocument doc, CitationGroups for (CitationGroup group : cgs.getCitationGroupsUnordered()) { String name = group.groupId.citationGroupIdAsString(); XTextCursor cursor = (this - .getRawCursorForCitationGroup(group, doc) - .orElseThrow(IllegalStateException::new)); + .getRawCursorForCitationGroup(group, doc) + .orElseThrow(IllegalStateException::new)); String context = GetContext.getCursorStringWithContext(cursor, 30, 30, true); Optional pageInfo = (group.numberOfCitations() > 0 - ? (getPageInfoFromData(group) - .map(e -> OOText.toString(e))) - : Optional.empty()); + ? (getPageInfoFromData(group) + .map(e -> OOText.toString(e))) + : Optional.empty()); CitationEntry entry = new CitationEntry(name, context, pageInfo); citations.add(entry); } @@ -418,11 +405,11 @@ public List getCitationEntries(XTextDocument doc, CitationGroups * Only applies to storage. Citation markers are not changed. */ public void applyCitationEntries(XTextDocument doc, List citationEntries) - throws - PropertyVetoException, - IllegalTypeException, - IllegalArgumentException, - WrappedTargetException { + throws + PropertyVetoException, + IllegalTypeException, + IllegalArgumentException, + WrappedTargetException { switch (dataModel) { case JabRef52: @@ -442,6 +429,5 @@ public void applyCitationEntries(XTextDocument doc, List citation throw new IllegalStateException("applyCitationEntries: unhandled dataModel "); } } - } diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java index 45f3bd3ca04..0b8932fda6c 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Codec52.java @@ -12,30 +12,35 @@ import org.jabref.model.openoffice.style.CitationType; /** - * How and what is encoded in reference mark names under JabRef 5.2. - * - * - pageInfo does not appear here. It is not encoded in the mark name. + * How and what is encoded in reference mark names under JabRef 5.2. + *

    + * - pageInfo does not appear here. It is not encoded in the mark name. */ class Codec52 { private static final String BIB_CITATION = "JR_cite"; private static final Pattern CITE_PATTERN = - // Pattern.compile(BIB_CITATION + "(\\d*)_(\\d*)_(.*)"); - // citationType is always "1" "2" or "3" - Pattern.compile(BIB_CITATION + "(\\d*)_([123])_(.*)"); + // Pattern.compile(BIB_CITATION + "(\\d*)_(\\d*)_(.*)"); + // citationType is always "1" "2" or "3" + Pattern.compile(BIB_CITATION + "(\\d*)_([123])_(.*)"); private Codec52() { - /**/ } /** * This is what we get back from parsing a refMarkName. */ public static class ParsedMarkName { - /** "", "0", "1" ... */ + /** + * "", "0", "1" ... + */ public final String index; - /** in-text-citation type */ + /** + * in-text-citation type + */ public final CitationType citationType; - /** Citation keys embedded in the reference mark. */ + /** + * Citation keys embedded in the reference mark. + */ public final List citationKeys; ParsedMarkName(String index, CitationType citationType, List citationKeys) { @@ -64,21 +69,19 @@ private static int citationTypeToInt(CitationType type) { case AUTHORYEAR_PAR -> 1; case AUTHORYEAR_INTEXT -> 2; case INVISIBLE_CIT -> 3; - default -> throw new IllegalArgumentException("Invalid CitationType"); }; } /** - * Produce a reference mark name for JabRef for the given citationType and list citation keys that - * does not yet appear among the reference marks of the document. + * Produce a reference mark name for JabRef for the given citationType and list citation keys that does not yet appear among the reference marks of the document. * * @param usedNames Reference mark names already in use. * @param citationKeys Identifies the cited sources. * @param citationType Encodes the effect of withText and inParenthesis options. - * - * The first occurrence of citationKeys gets no serial number, the second gets 0, the third 1 ... - * - * Or the first unused in this series, after removals. + *

    + * The first occurrence of citationKeys gets no serial number, the second gets 0, the third 1 ... + *

    + * Or the first unused in this series, after removals. */ public static String getUniqueMarkName(Set usedNames, List citationKeys, @@ -100,7 +103,6 @@ public static String getUniqueMarkName(Set usedNames, * Parse a JabRef (reference) mark name. * * @return Optional.empty() on failure. - * */ public static Optional parseMarkName(String refMarkName) { @@ -117,8 +119,7 @@ public static Optional parseMarkName(String refMarkName) { } /** - * @return true if name matches the pattern used for JabRef - * reference mark names. + * @return true if name matches the pattern used for JabRef reference mark names. */ public static boolean isJabRefReferenceMarkName(String name) { return (CITE_PATTERN.matcher(name).find()); diff --git a/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java b/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java index ffce5b9553e..865682f0ccc 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/GetContext.java @@ -12,21 +12,17 @@ public class GetContext { private static final Logger LOGGER = LoggerFactory.getLogger(GetContext.class); private GetContext() { - // Just to hide the public constructor } /** - * Get the text belonging to cursor with up to - * charBefore and charAfter characters of context. - * - * The actual context may be smaller than requested. - * - * @param cursor - * @param charBefore Number of characters requested. - * @param charAfter Number of characters requested. - * @param htmlMarkup If true, the text belonging to the reference mark is surrounded by bold - * html tag. + * Get the text belonging to cursor with up to charBefore and charAfter characters of context. + *

    + * The actual context may be smaller than requested. * + * @param cursor + * @param charBefore Number of characters requested. + * @param charAfter Number of characters requested. + * @param htmlMarkup If true, the text belonging to the reference mark is surrounded by bold html tag. */ public static String getCursorStringWithContext(XTextCursor cursor, int charBefore, @@ -43,7 +39,7 @@ public static String getCursorStringWithContext(XTextCursor cursor, // If we are close to charBefore and see a space, then cut here. Might avoid cutting // a word in half. if ((i >= (charBefore - flex)) - && Character.isWhitespace(cursor.getString().charAt(0))) { + && Character.isWhitespace(cursor.getString().charAt(0))) { break; } } catch (IndexOutOfBoundsException ex) { @@ -72,10 +68,9 @@ public static String getCursorStringWithContext(XTextCursor cursor, String result = cursor.getString(); if (htmlMarkup) { result = (result.substring(0, addedBefore) - + "" + citPart + "" - + result.substring(lengthWithBefore)); + + "" + citPart + "" + + result.substring(lengthWithBefore)); } return result.trim(); } - } diff --git a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java index 93ad6d12908..fead1169b8e 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeManagerReferenceMark.java @@ -21,23 +21,23 @@ public NamedRange createNamedRange(XTextDocument doc, XTextCursor position, boolean insertSpaceAfter, boolean withoutBrackets) - throws - CreationException { + throws + CreationException { return NamedRangeReferenceMark.create(doc, refMarkName, position, insertSpaceAfter, withoutBrackets); } @Override public List getUsedNames(XTextDocument doc) - throws - NoDocumentException { + throws + NoDocumentException { return UnoReferenceMark.getListOfNames(doc); } @Override public Optional getNamedRangeFromDocument(XTextDocument doc, String refMarkName) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { return (NamedRangeReferenceMark .getFromDocument(doc, refMarkName) .map(x -> x)); 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 324b984377c..0091367c7d8 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java @@ -25,17 +25,20 @@ class NamedRangeReferenceMark implements NamedRange { // for debugging we may want visible bracket private static final boolean - REFERENCE_MARK_USE_INVISIBLE_BRACKETS = true; // !debug; + REFERENCE_MARK_USE_INVISIBLE_BRACKETS = true; // !debug; public static final String - REFERENCE_MARK_LEFT_BRACKET = REFERENCE_MARK_USE_INVISIBLE_BRACKETS ? ZERO_WIDTH_SPACE : "<"; + REFERENCE_MARK_LEFT_BRACKET = REFERENCE_MARK_USE_INVISIBLE_BRACKETS ? ZERO_WIDTH_SPACE : "<"; public static final String - REFERENCE_MARK_RIGHT_BRACKET = REFERENCE_MARK_USE_INVISIBLE_BRACKETS ? ZERO_WIDTH_SPACE : ">"; + REFERENCE_MARK_RIGHT_BRACKET = REFERENCE_MARK_USE_INVISIBLE_BRACKETS ? ZERO_WIDTH_SPACE : ">"; private static final Logger LOGGER = LoggerFactory.getLogger(NamedRangeReferenceMark.class); - private String rangeId; /* reference mark name */ + /** + * reference mark name + */ + private final String rangeId; private NamedRangeReferenceMark(String rangeId) { this.rangeId = rangeId; @@ -46,20 +49,15 @@ String getId() { } /** - * Insert {@code n} spaces in a way that reference marks just before or just after the cursor - * are not affected. - * - * This is based on the observation, that starting two new paragraphs separates us from - * reference marks on either side. - * - * The pattern used is: - * {@code safeInsertSpaces(n): para, para, left, space(n), right-delete, left(n), left-delete} - * - * @param position Where to insert (at position.getStart()) - * @param numSpaces Number of spaces to insert. - * - * @return a new cursor, covering the just-inserted spaces. + * Insert {@code n} spaces in a way that reference marks just before or just after the cursor are not affected. + *

    + * This is based on the observation, that starting two new paragraphs separates us from reference marks on either side. + *

    + * The pattern used is: {@code safeInsertSpaces(n): para, para, left, space(n), right-delete, left(n), left-delete} * + * @param position Where to insert (at position.getStart()) + * @param numSpaces Number of spaces to insert. + * @return a new cursor, covering the just-inserted spaces. */ private static XTextCursor safeInsertSpacesBetweenReferenceMarks(XTextRange position, int numSpaces) { // Start with an empty cursor at position.getStart(); @@ -82,8 +80,8 @@ private static void createReprInDocument(XTextDocument doc, XTextCursor position, boolean insertSpaceAfter, boolean withoutBrackets) - throws - CreationException { + throws + CreationException { // The cursor we received: we push it before us. position.collapseToEnd(); @@ -101,8 +99,8 @@ private static void createReprInDocument(XTextDocument doc, final String left = NamedRangeReferenceMark.REFERENCE_MARK_LEFT_BRACKET; final String right = NamedRangeReferenceMark.REFERENCE_MARK_RIGHT_BRACKET; String bracketedContent = (withoutBrackets - ? "" - : left + right); + ? "" + : left + right); cursor.getText().insertString(cursor, bracketedContent, true); @@ -123,8 +121,8 @@ static NamedRangeReferenceMark create(XTextDocument doc, XTextCursor position, boolean insertSpaceAfter, boolean withoutBrackets) - throws - CreationException { + throws + CreationException { createReprInDocument(doc, refMarkName, position, insertSpaceAfter, withoutBrackets); return new NamedRangeReferenceMark(refMarkName); @@ -134,23 +132,23 @@ static NamedRangeReferenceMark create(XTextDocument doc, * @return Optional.empty if there is no corresponding range. */ static Optional getFromDocument(XTextDocument doc, String refMarkName) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { return (UnoReferenceMark.getAnchor(doc, refMarkName) - .map(e -> new NamedRangeReferenceMark(refMarkName))); + .map(e -> new NamedRangeReferenceMark(refMarkName))); } /** * Remove it from the document. - * + *

    * See: removeCitationGroups */ @Override public void removeFromDocument(XTextDocument doc) - throws - WrappedTargetException, - NoDocumentException { + throws + WrappedTargetException, + NoDocumentException { UnoReferenceMark.removeIfExists(doc, this.getRangeName()); } @@ -160,34 +158,27 @@ public String getRangeName() { } /** - * - * @return Optional.empty if the reference mark is missing. - * - * See: UnoReferenceMark.getAnchor + * @return Optional.empty if the reference mark is missing. See: UnoReferenceMark.getAnchor */ @Override public Optional getMarkRange(XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { String name = this.getRangeName(); return UnoReferenceMark.getAnchor(doc, name); } /** - * Cursor for the reference marks as is, not prepared for filling, but does not need - * cleanFillCursor either. + * Cursor for the reference marks as is, not prepared for filling, but does not need cleanFillCursor either. * - * @return Optional.empty() if reference mark is missing from the document, - * otherwise an XTextCursor for getMarkRange - * - * See: getRawCursorForCitationGroup + * @return Optional.empty() if reference mark is missing from the document, otherwise an XTextCursor for getMarkRange See: getRawCursorForCitationGroup */ @Override public Optional getRawCursor(XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { String name = this.getRangeName(); @@ -210,10 +201,10 @@ public Optional getRawCursor(XTextDocument doc) */ @Override public XTextCursor getFillCursor(XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException, - CreationException { + throws + NoDocumentException, + WrappedTargetException, + CreationException { String name = this.getRangeName(); @@ -357,8 +348,8 @@ public static void checkFillCursor(XTextCursor cursor) { alpha.goLeft(leftLength, true); if (!left.equals(alpha.getString())) { String msg = String.format("checkFillCursor:" - + " ('%s') is not prefixed with REFERENCE_MARK_LEFT_BRACKET, has '%s'", - cursor.getString(), alpha.getString()); + + " ('%s') is not prefixed with REFERENCE_MARK_LEFT_BRACKET, has '%s'", + cursor.getString(), alpha.getString()); throw new IllegalStateException(msg); } } @@ -369,24 +360,23 @@ public static void checkFillCursor(XTextCursor cursor) { omega.goRight(rightLength, true); if (!right.equals(omega.getString())) { String msg = String.format("checkFillCursor:" - + " ('%s') is not followed by REFERENCE_MARK_RIGHT_BRACKET, has '%s'", - cursor.getString(), omega.getString()); + + " ('%s') is not followed by REFERENCE_MARK_RIGHT_BRACKET, has '%s'", + cursor.getString(), omega.getString()); throw new IllegalStateException(msg); } } } /** - * Remove brackets, but if the result would become empty, leave them; if the result would be a - * single characer, leave the left bracket. - * + * Remove brackets, but if the result would become empty, leave them; if the result would be a single characer, leave the left bracket. + *

    * See: cleanFillCursorForCitationGroup */ @Override public void cleanFillCursor(XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { // alwaysRemoveBrackets : full compatibility with JabRef 5.2: brackets are temporary, only // exist between getFillCursor and cleanFillCursor. @@ -422,12 +412,12 @@ public void cleanFillCursor(XTextDocument doc) } boolean removeRight = ((contentLength >= 1) - || ((contentLength == 0) && removeBracketsFromEmpty) - || alwaysRemoveBrackets); + || ((contentLength == 0) && removeBracketsFromEmpty) + || alwaysRemoveBrackets); boolean removeLeft = ((contentLength >= 2) - || ((contentLength == 0) && removeBracketsFromEmpty) - || alwaysRemoveBrackets); + || ((contentLength == 0) && removeBracketsFromEmpty) + || alwaysRemoveBrackets); if (removeRight) { XTextCursor omega = full.getText().createTextCursorByRange(full); diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java index 58057c382e7..bcf77852ec4 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java @@ -47,9 +47,9 @@ public class OOFrontend { public final CitationGroups citationGroups; public OOFrontend(XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { // TODO: dataModel should come from looking at the document and preferences. this.backend = new Backend52(); @@ -58,7 +58,7 @@ public OOFrontend(XTextDocument doc) List citationGroupNames = this.backend.getJabRefReferenceMarkNames(doc); Map citationGroups = - readCitationGroupsFromDocument(this.backend, doc, citationGroupNames); + readCitationGroupsFromDocument(this.backend, doc, citationGroupNames); this.citationGroups = new CitationGroups(citationGroups); } @@ -67,8 +67,8 @@ public OODataModel getDataModel() { } public Optional healthReport(XTextDocument doc) - throws - NoDocumentException { + throws + NoDocumentException { return backend.healthReport(doc); } @@ -76,9 +76,9 @@ public Optional healthReport(XTextDocument doc) readCitationGroupsFromDocument(Backend52 backend, XTextDocument doc, List citationGroupNames) - throws - WrappedTargetException, - NoDocumentException { + throws + WrappedTargetException, + NoDocumentException { Map citationGroups = new HashMap<>(); for (String name : citationGroupNames) { @@ -89,32 +89,27 @@ public Optional healthReport(XTextDocument doc) } /** - * Creates a list of {@code RangeSortable} values for our {@code CitationGroup} - * values. Originally designed to be passed to {@code visualSort}. - * + * Creates a list of {@code RangeSortable} values for our {@code CitationGroup} values. Originally designed to be passed to {@code visualSort}. + *

    * The elements of the returned list are actually of type {@code RangeSortEntry}. + *

    + * The result is sorted within {@code XTextRange.getText()} partitions of the citation groups according to their {@code XTextRange} (before mapping to footnote marks). + *

    + * In the result, RangeSortable.getIndexInPosition() contains unique indexes within the original partition (not after mapFootnotesToFootnoteMarks). * - * The result is sorted within {@code XTextRange.getText()} partitions of the citation groups - * according to their {@code XTextRange} (before mapping to footnote marks). - * - * In the result, RangeSortable.getIndexInPosition() contains unique indexes within the original - * partition (not after mapFootnotesToFootnoteMarks). - * - * @param mapFootnotesToFootnoteMarks If true, replace ranges in footnotes with the range of the - * corresponding footnote mark. This is used for numbering the citations. - * + * @param mapFootnotesToFootnoteMarks If true, replace ranges in footnotes with the range of the corresponding footnote mark. This is used for numbering the citations. */ - private List> - createVisualSortInput(XTextDocument doc, boolean mapFootnotesToFootnoteMarks) - throws - NoDocumentException, - WrappedTargetException { + private List> createVisualSortInput(XTextDocument doc, + boolean mapFootnotesToFootnoteMarks) + throws + NoDocumentException, + WrappedTargetException { List> sortables = new ArrayList<>(); for (CitationGroup group : citationGroups.getCitationGroupsUnordered()) { XTextRange range = (this - .getMarkRange(doc, group) - .orElseThrow(IllegalStateException::new)); + .getMarkRange(doc, group) + .orElseThrow(IllegalStateException::new)); sortables.add(new RangeSortEntry<>(range, 0, group)); } @@ -137,7 +132,7 @@ public Optional healthReport(XTextDocument doc) // Sort within partitions RangeSort.RangePartitions> partitions = - RangeSort.partitionAndSortRanges(sortables); + RangeSort.partitionAndSortRanges(sortables); // build final list List> result = new ArrayList<>(); @@ -148,75 +143,64 @@ public Optional healthReport(XTextDocument doc) sortable.setIndexInPosition(indexInPartition++); if (mapFootnotesToFootnoteMarks) { Optional footnoteMarkRange = - UnoTextRange.getFootnoteMarkRange(sortable.getRange()); + UnoTextRange.getFootnoteMarkRange(sortable.getRange()); // Adjust range if we are inside a footnote: - if (footnoteMarkRange.isPresent()) { - sortable.setRange(footnoteMarkRange.get()); - } + footnoteMarkRange.ifPresent(sortable::setRange); } result.add(sortable); } } - return result.stream().map(e -> e).collect(Collectors.toList()); + return new ArrayList<>(result); } /** - * @param mapFootnotesToFootnoteMarks If true, sort reference marks in footnotes as if they - * appeared at the corresponding footnote mark. - * - * @return citation groups sorted by their visual positions. - * - * Limitation: for two column layout visual (top-down, left-right) order does not match the - * expected (textual) order. - * + * @param mapFootnotesToFootnoteMarks If true, sort reference marks in footnotes as if they appeared at the corresponding footnote mark. + * @return citation groups sorted by their visual positions. Limitation: for two column layout visual (top-down, left-right) order does not match the expected (textual) order. */ private List getVisuallySortedCitationGroups(XTextDocument doc, boolean mapFootnotesToFootnoteMarks, FunctionalTextViewCursor fcursor) - throws - WrappedTargetException, - NoDocumentException { + throws + WrappedTargetException, + NoDocumentException { List> sortables = createVisualSortInput(doc, mapFootnotesToFootnoteMarks); List> sorted = RangeSortVisual.visualSort(sortables, doc, fcursor); return (sorted.stream() - .map(RangeSortable::getContent) - .collect(Collectors.toList())); + .map(RangeSortable::getContent) + .collect(Collectors.toList())); } /** * Return citation groups in visual order within (but not across) XText partitions. - * - * This is (1) sufficient for combineCiteMarkers which looks for consecutive XTextRanges within - * each XText, (2) not confused by multicolumn layout or multipage display. + *

    + * This is (1) sufficient for combineCiteMarkers which looks for consecutive XTextRanges within each XText, (2) not confused by multicolumn layout or multipage display. */ public List getCitationGroupsSortedWithinPartitions(XTextDocument doc, boolean mapFootnotesToFootnoteMarks) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { // This is like getVisuallySortedCitationGroups, // but we skip the visualSort part. List> sortables = - createVisualSortInput(doc, mapFootnotesToFootnoteMarks); + createVisualSortInput(doc, mapFootnotesToFootnoteMarks); - return (sortables.stream().map(e -> e.getContent()).collect(Collectors.toList())); + return (sortables.stream().map(RangeSortable::getContent).collect(Collectors.toList())); } /** - * Create a citation group for the given citation keys, at the end of position. - * - * On return {@code position} is collapsed, and is after the inserted space, or at the end of - * the reference mark. + * Create a citation group for the given citation keys, at the end of position. + *

    + * On return {@code position} is collapsed, and is after the inserted space, or at the end of the reference mark. * - * @param citationKeys In storage order - * @param pageInfos In storage order + * @param citationKeys In storage order + * @param pageInfos In storage order * @param citationType - * @param position Collapsed to its end. - * @param insertSpaceAfter If true, we insert a space after the mark, that carries on format of - * characters from the original position. + * @param position Collapsed to its end. + * @param insertSpaceAfter If true, we insert a space after the mark, that carries on format of characters from the original position. */ public CitationGroup createCitationGroup(XTextDocument doc, List citationKeys, @@ -224,24 +208,24 @@ public CitationGroup createCitationGroup(XTextDocument doc, CitationType citationType, XTextCursor position, boolean insertSpaceAfter) - throws - CreationException, - NoDocumentException, - WrappedTargetException, - NotRemoveableException, - PropertyVetoException, - IllegalTypeException { + throws + CreationException, + NoDocumentException, + WrappedTargetException, + NotRemoveableException, + PropertyVetoException, + IllegalTypeException { Objects.requireNonNull(pageInfos); if (pageInfos.size() != citationKeys.size()) { throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); } CitationGroup group = backend.createCitationGroup(doc, - citationKeys, - pageInfos, - citationType, - position, - insertSpaceAfter); + citationKeys, + pageInfos, + citationType, + position, + insertSpaceAfter); this.citationGroups.afterCreateCitationGroup(group); return group; @@ -251,20 +235,20 @@ public CitationGroup createCitationGroup(XTextDocument doc, * Remove {@code group} both from the document and notify {@code citationGroups} */ public void removeCitationGroup(CitationGroup group, XTextDocument doc) - throws - WrappedTargetException, - NoDocumentException, - NotRemoveableException { + throws + WrappedTargetException, + NoDocumentException, + NotRemoveableException { backend.removeCitationGroup(group, doc); this.citationGroups.afterRemoveCitationGroup(group); } public void removeCitationGroups(List cgs, XTextDocument doc) - throws - WrappedTargetException, - NoDocumentException, - NotRemoveableException { + throws + WrappedTargetException, + NoDocumentException, + NotRemoveableException { for (CitationGroup group : cgs) { removeCitationGroup(group, doc); @@ -275,20 +259,19 @@ public void removeCitationGroups(List cgs, XTextDocument doc) * ranges controlled by citation groups should not overlap with each other. * * @return Optional.empty() if the reference mark is missing. - * */ public Optional getMarkRange(XTextDocument doc, CitationGroup group) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { return backend.getMarkRange(group, doc); } public XTextCursor getFillCursorForCitationGroup(XTextDocument doc, CitationGroup group) - throws - NoDocumentException, - WrappedTargetException, - CreationException { + throws + NoDocumentException, + WrappedTargetException, + CreationException { return backend.getFillCursorForCitationGroup(group, doc); } @@ -296,41 +279,39 @@ public XTextCursor getFillCursorForCitationGroup(XTextDocument doc, CitationGrou * Remove brackets added by getFillCursorForCitationGroup. */ public void cleanFillCursorForCitationGroup(XTextDocument doc, CitationGroup group) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { backend.cleanFillCursorForCitationGroup(group, doc); } /** - * @return A RangeForOverlapCheck for each citation group. - * - * result.size() == nRefMarks + * @return A RangeForOverlapCheck for each citation group. result.size() == nRefMarks */ public List> citationRanges(XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { List> result = - new ArrayList<>(citationGroups.numberOfCitationGroups()); + new ArrayList<>(citationGroups.numberOfCitationGroups()); for (CitationGroup group : citationGroups.getCitationGroupsUnordered()) { XTextRange range = this.getMarkRange(doc, group).orElseThrow(IllegalStateException::new); String description = group.groupId.citationGroupIdAsString(); result.add(new RangeForOverlapCheck<>(range, - group.groupId, - RangeForOverlapCheck.REFERENCE_MARK_KIND, - description)); + group.groupId, + RangeForOverlapCheck.REFERENCE_MARK_KIND, + description)); } return result; } public List> bibliographyRanges(XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { List> result = new ArrayList<>(); @@ -338,9 +319,9 @@ public List> bibliographyRanges(XTextDocum if (range.isPresent()) { String description = "bibliography"; result.add(new RangeForOverlapCheck<>(range.get(), - new CitationGroupId("bibliography"), - RangeForOverlapCheck.BIBLIOGRAPHY_MARK_KIND, - description)); + new CitationGroupId("bibliography"), + RangeForOverlapCheck.BIBLIOGRAPHY_MARK_KIND, + description)); } return result; } @@ -353,23 +334,17 @@ public List> viewCursorRanges(XTextDocumen if (range.isPresent()) { String description = "cursor"; result.add(new RangeForOverlapCheck<>(range.get(), - new CitationGroupId("cursor"), - RangeForOverlapCheck.CURSOR_MARK_KIND, - description)); + new CitationGroupId("cursor"), + RangeForOverlapCheck.CURSOR_MARK_KIND, + description)); } return result; } /** - * @return A range for each footnote mark where the footnote contains at least one citation group. - * - * Purpose: We do not want markers of footnotes containing reference marks to overlap with - * reference marks. Overwriting these footnote marks might kill our reference marks in the - * footnote. - * - * Note: Here we directly communicate to the document, not through the backend. This is because - * mapping ranges to footnote marks does not depend on how do we mark or structure those - * ranges. + * @return A range for each footnote mark where the footnote contains at least one citation group. Purpose: We do not want markers of footnotes containing reference marks to overlap with reference marks. Overwriting these footnote marks might kill our reference marks in the footnote. + *

    + * Note: Here we directly communicate to the document, not through the backend. This is because mapping ranges to footnote marks does not depend on how do we mark or structure those ranges. */ public List> footnoteMarkRanges(XTextDocument doc, List> citationRanges) { @@ -379,7 +354,7 @@ public List> viewCursorRanges(XTextDocumen List> result = new ArrayList<>(); RangeSort.RangePartitions> partitions = - RangeSort.partitionRanges(citationRanges); + RangeSort.partitionRanges(citationRanges); // Each partition corresponds to an XText, and each footnote has a single XText. // (This latter ignores the possibility of XTextContents inserted into footnotes.) @@ -398,9 +373,9 @@ public List> viewCursorRanges(XTextDocumen } result.add(new RangeForOverlapCheck<>(footnoteMarkRange.get(), - citationRange.idWithinKind, - RangeForOverlapCheck.FOOTNOTE_MARK_KIND, - "FootnoteMark for " + citationRange.format())); + citationRange.idWithinKind, + RangeForOverlapCheck.FOOTNOTE_MARK_KIND, + "FootnoteMark for " + citationRange.format())); } return result; } @@ -414,14 +389,14 @@ static String rangeOverlapsToMessage(List> overlap : overlaps) { String listOfRanges = (overlap.valuesForOverlappingRanges.stream() - .map(v -> String.format("'%s'", v.format())) - .collect(Collectors.joining(", "))); + .map(v -> String.format("'%s'", v.format())) + .collect(Collectors.joining(", "))); msg.append( - switch (overlap.kind) { - case EQUAL_RANGE -> Localization.lang("Found identical ranges"); - case OVERLAP -> Localization.lang("Found overlapping ranges"); - case TOUCH -> Localization.lang("Found touching ranges"); - }); + switch (overlap.kind) { + case EQUAL_RANGE -> Localization.lang("Found identical ranges"); + case OVERLAP -> Localization.lang("Found overlapping ranges"); + case TOUCH -> Localization.lang("Found touching ranges"); + }); msg.append(": "); msg.append(listOfRanges); msg.append("\n"); @@ -431,18 +406,18 @@ static String rangeOverlapsToMessage(List * Assume userRanges is small (usually 1 elements for checking the cursor) - * + *

    * Returns on first problem found. */ public OOVoidResult checkRangeOverlapsWithCursor(XTextDocument doc, List> userRanges, boolean requireSeparation) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { List> citationRanges = citationRanges(doc); List> ranges = new ArrayList<>(); @@ -453,30 +428,29 @@ static String rangeOverlapsToMessage(List>> overlaps = - RangeOverlapBetween.findFirst(doc, - userRanges, - ranges, - requireSeparation); + RangeOverlapBetween.findFirst(doc, + userRanges, + ranges, + requireSeparation); if (overlaps.isEmpty()) { return OOVoidResult.ok(); } return OOVoidResult.error(new JabRefException("Found overlapping or touching ranges", - rangeOverlapsToMessage(overlaps))); + rangeOverlapsToMessage(overlaps))); } /** * @param requireSeparation Report range pairs that only share a boundary. - * @param reportAtMost Limit number of overlaps reported (0 for no limit) - * + * @param reportAtMost Limit number of overlaps reported (0 for no limit) */ public OOVoidResult checkRangeOverlaps(XTextDocument doc, List> userRanges, boolean requireSeparation, int reportAtMost) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { List> citationRanges = citationRanges(doc); List> ranges = new ArrayList<>(); @@ -486,69 +460,56 @@ public OOVoidResult checkRangeOverlaps(XTextDocument doc, ranges.addAll(footnoteMarkRanges(doc, citationRanges)); List>> overlaps = - RangeOverlapWithin.findOverlappingRanges(doc, ranges, requireSeparation, reportAtMost); + RangeOverlapWithin.findOverlappingRanges(doc, ranges, requireSeparation, reportAtMost); if (overlaps.isEmpty()) { return OOVoidResult.ok(); } return OOVoidResult.error(new JabRefException("Found overlapping or touching ranges", - rangeOverlapsToMessage(overlaps))); + rangeOverlapsToMessage(overlaps))); } /** - * GUI: Get a list of CitationEntry objects corresponding to citations - * in the document. - * + * GUI: Get a list of CitationEntry objects corresponding to citations in the document. + *

    * Called from: ManageCitationsDialogViewModel constructor. * - * @return A list with entries corresponding to citations in the text, in arbitrary order (same - * order as from getJabRefReferenceMarkNames). - * - * Note: visual or alphabetic order could be more manageable for the user. We - * could provide these here, but switching between them needs change on GUI - * (adding a toggle or selector). - * - * Note: CitationEntry implements Comparable, where compareTo() and equals() are - * based on refMarkName. The order used in the "Manage citations" dialog - * does not seem to use that. - * - * The 1st is labeled "Citation" (show citation in bold, and some context - * around it). - * - * The columns can be sorted by clicking on the column title. For the - * "Citation" column, the sorting is based on the content, (the context - * before the citation), not on the citation itself. - * - * In the "Extra information ..." column some visual indication of the - * editable part could be helpful. - * - * Wish: selecting an entry (or a button in the line) in the GUI could move the cursor - * in the document to the entry. + * @return A list with entries corresponding to citations in the text, in arbitrary order (same order as from getJabRefReferenceMarkNames). Note: visual or alphabetic order could be more manageable for the user. We could provide these here, but switching between them needs change on GUI (adding a toggle or selector). + *

    + * Note: CitationEntry implements Comparable, where compareTo() and equals() are based on refMarkName. The order used in the "Manage citations" dialog does not seem to use that. + *

    + * The 1st is labeled "Citation" (show citation in bold, and some context around it). + *

    + * The columns can be sorted by clicking on the column title. For the "Citation" column, the sorting is based on the content, (the context before the citation), not on the citation itself. + *

    + * In the "Extra information ..." column some visual indication of the editable part could be helpful. + *

    + * Wish: selecting an entry (or a button in the line) in the GUI could move the cursor in the document to the entry. */ public List getCitationEntries(XTextDocument doc) - throws - WrappedTargetException, - NoDocumentException { + throws + WrappedTargetException, + NoDocumentException { return this.backend.getCitationEntries(doc, citationGroups); } public void applyCitationEntries(XTextDocument doc, List citationEntries) - throws - PropertyVetoException, - IllegalTypeException, - IllegalArgumentException, - WrappedTargetException { + throws + PropertyVetoException, + IllegalTypeException, + IllegalArgumentException, + WrappedTargetException { this.backend.applyCitationEntries(doc, citationEntries); } public void imposeGlobalOrder(XTextDocument doc, FunctionalTextViewCursor fcursor) - throws - WrappedTargetException, - NoDocumentException { + throws + WrappedTargetException, + NoDocumentException { boolean mapFootnotesToFootnoteMarks = true; List sortedCitationGroups = - getVisuallySortedCitationGroups(doc, mapFootnotesToFootnoteMarks, fcursor); + getVisuallySortedCitationGroups(doc, mapFootnotesToFootnoteMarks, fcursor); List sortedCitationGroupIds = OOListUtil.map(sortedCitationGroups, group -> group.groupId); citationGroups.setGlobalOrder(sortedCitationGroupIds); } diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/RangeForOverlapCheck.java b/src/main/java/org/jabref/logic/openoffice/frontend/RangeForOverlapCheck.java index 6cbf560ec62..914195bd243 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/RangeForOverlapCheck.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/RangeForOverlapCheck.java @@ -6,17 +6,10 @@ /** * Describe a protected range for overlap checking and reporting. - * - * To check that our protected ranges do not overlap, we collect - * these ranges. To check for overlaps between these, we need the - * {@code range} itself. To report the results of overlap - * checking, we need a {@code description} that can be understood - * by the user. - * - * To be able to refer back to more extended data, we might need to - * identify its {@code kind}, and its index in the corresponding - * tables or other identifier within its kind ({@code idWithinKind}) - * + *

    + * To check that our protected ranges do not overlap, we collect these ranges. To check for overlaps between these, we need the {@code range} itself. To report the results of overlap checking, we need a {@code description} that can be understood by the user. + *

    + * To be able to refer back to more extended data, we might need to identify its {@code kind}, and its index in the corresponding tables or other identifier within its kind ({@code idWithinKind}) */ public class RangeForOverlapCheck implements RangeHolder { 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 ebda8359ba5..68b2aa565a7 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java @@ -26,13 +26,12 @@ public class UpdateBibliography { private static final String BIB_SECTION_END_NAME = "JR_bib_end"; private UpdateBibliography() { - /**/ } public static Optional getBibliographyRange(XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { return UnoTextSection.getAnchor(doc, BIB_SECTION_NAME); } @@ -44,28 +43,28 @@ public static void rebuildBibTextSection(XTextDocument doc, CitedKeys bibliography, OOBibStyle style, boolean alwaysAddCitedOnPages) - throws - WrappedTargetException, - CreationException, - NoDocumentException { + throws + WrappedTargetException, + CreationException, + NoDocumentException { clearBibTextSectionContent2(doc); populateBibTextSection(doc, - frontend, - bibliography, - style, - alwaysAddCitedOnPages); + frontend, + bibliography, + style, + alwaysAddCitedOnPages); } /** * Insert a paragraph break and create a text section for the bibliography. - * + *

    * Only called from `clearBibTextSectionContent2` */ private static void createBibTextSection2(XTextDocument doc) - throws - CreationException { + throws + CreationException { // Always creating at the end of the document. // Alternatively, we could receive a cursor. @@ -75,23 +74,20 @@ private static void createBibTextSection2(XTextDocument doc) } /** - * Find and clear the text section BIB_SECTION_NAME to "", - * or create it. - * + * Find and clear the text section BIB_SECTION_NAME to "", or create it. + *

    * Only called from: `rebuildBibTextSection` - * */ private static void clearBibTextSectionContent2(XTextDocument doc) - throws - CreationException, - NoDocumentException, - WrappedTargetException { + throws + CreationException, + NoDocumentException, + WrappedTargetException { // Optional sectionRange = UnoTextSection.getAnchor(doc, BIB_SECTION_NAME); Optional sectionRange = getBibliographyRange(doc); if (sectionRange.isEmpty()) { createBibTextSection2(doc); - return; } else { // Clear it XTextCursor cursor = doc.getText().createTextCursorByRange(sectionRange.get()); @@ -101,7 +97,7 @@ private static void clearBibTextSectionContent2(XTextDocument doc) /** * Only called from: `rebuildBibTextSection` - * + *

    * Assumes the section named BIB_SECTION_NAME exists. */ private static void populateBibTextSection(XTextDocument doc, @@ -109,11 +105,11 @@ private static void populateBibTextSection(XTextDocument doc, CitedKeys bibliography, OOBibStyle style, boolean alwaysAddCitedOnPages) - throws - CreationException, - IllegalArgumentException, - NoDocumentException, - WrappedTargetException { + throws + CreationException, + IllegalArgumentException, + NoDocumentException, + WrappedTargetException { XTextRange sectionRange = getBibliographyRange(doc).orElseThrow(IllegalStateException::new); @@ -122,9 +118,9 @@ private static void populateBibTextSection(XTextDocument doc, // emit the title of the bibliography OOTextIntoOO.removeDirectFormatting(cursor); OOText bibliographyText = OOFormatBibliography.formatBibliography(frontend.citationGroups, - bibliography, - style, - alwaysAddCitedOnPages); + bibliography, + style, + alwaysAddCitedOnPages); OOTextIntoOO.write(doc, cursor, bibliographyText); cursor.collapseToEnd(); @@ -140,5 +136,4 @@ private static void populateBibTextSection(XTextDocument doc, cursor.collapseToEnd(); } - } diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java index 834fce1d0ce..0eee3bd6016 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java @@ -30,26 +30,21 @@ public class UpdateCitationMarkers { private static final Logger LOGGER = LoggerFactory.getLogger(UpdateCitationMarkers.class); private UpdateCitationMarkers() { - /**/ } /** - * Visit each reference mark in referenceMarkNames, overwrite its - * text content. - * - * After each fillCitationMarkInCursor call check if we lost the - * BIB_SECTION_NAME bookmark and recreate it if we did. + * Visit each reference mark in referenceMarkNames, overwrite its text content. + *

    + * After each fillCitationMarkInCursor call check if we lost the BIB_SECTION_NAME bookmark and recreate it if we did. * * @param frontend - * - * @param style Bibliography style to use. - * + * @param style Bibliography style to use. */ public static void applyNewCitationMarkers(XTextDocument doc, OOFrontend frontend, OOBibStyle style) - throws - NoDocumentException, - CreationException, - WrappedTargetException { + throws + NoDocumentException, + CreationException, + WrappedTargetException { CitationGroups citationGroups = frontend.citationGroups; @@ -58,9 +53,9 @@ public static void applyNewCitationMarkers(XTextDocument doc, OOFrontend fronten boolean withText = (group.citationType != CitationType.INVISIBLE_CIT); Optional marker = group.getCitationMarker(); - if (!marker.isPresent()) { + if (marker.isEmpty()) { LOGGER.warn("applyNewCitationMarkers: no marker for {}", - group.groupId.citationGroupIdAsString()); + group.groupId.citationGroupIdAsString()); continue; } @@ -72,7 +67,6 @@ public static void applyNewCitationMarkers(XTextDocument doc, OOFrontend fronten frontend.cleanFillCursorForCitationGroup(doc, group); } - } } @@ -81,10 +75,10 @@ public static void fillCitationMarkInCursor(XTextDocument doc, OOText citationText, boolean withText, OOBibStyle style) - throws - WrappedTargetException, - CreationException, - IllegalArgumentException { + throws + WrappedTargetException, + CreationException, + IllegalArgumentException { Objects.requireNonNull(cursor); Objects.requireNonNull(citationText); @@ -102,21 +96,15 @@ public static void fillCitationMarkInCursor(XTextDocument doc, } /** - * Inserts a citation group in the document: creates and fills it. + * Inserts a citation group in the document: creates and fills it. * - * @param citationKeys BibTeX keys of + * @param citationKeys BibTeX keys of * @param pageInfos * @param citationType - * - * @param citationText Text for the citation. A citation mark or - * placeholder if not yet available. - * - * @param position Location to insert at. + * @param citationText Text for the citation. A citation mark or placeholder if not yet available. + * @param position Location to insert at. * @param style - * @param insertSpaceAfter A space inserted after the reference - * mark makes it easier to separate from the text - * coming after. But is not wanted when we recreate a - * reference mark. + * @param insertSpaceAfter A space inserted after the reference mark makes it easier to separate from the text coming after. But is not wanted when we recreate a reference mark. */ public static void createAndFillCitationGroup(OOFrontend frontend, XTextDocument doc, @@ -127,25 +115,25 @@ public static void createAndFillCitationGroup(OOFrontend frontend, XTextCursor position, OOBibStyle style, boolean insertSpaceAfter) - throws - NotRemoveableException, - WrappedTargetException, - PropertyVetoException, - IllegalArgumentException, - CreationException, - NoDocumentException, - IllegalTypeException { + throws + NotRemoveableException, + WrappedTargetException, + PropertyVetoException, + IllegalArgumentException, + CreationException, + NoDocumentException, + IllegalTypeException { Objects.requireNonNull(pageInfos); if (pageInfos.size() != citationKeys.size()) { throw new IllegalArgumentException("pageInfos.size != citationKeys.size"); } CitationGroup group = frontend.createCitationGroup(doc, - citationKeys, - pageInfos, - citationType, - position, - insertSpaceAfter); + citationKeys, + pageInfos, + citationType, + position, + insertSpaceAfter); final boolean withText = citationType.withText(); @@ -158,5 +146,4 @@ public static void createAndFillCitationGroup(OOFrontend frontend, } position.collapseToEnd(); } - } diff --git a/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java index 63981ceba70..57fba4dc272 100644 --- a/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java +++ b/src/main/java/org/jabref/model/openoffice/backend/NamedRange.java @@ -11,13 +11,9 @@ import com.sun.star.text.XTextRange; /** - * NamedRange (with NamedRangeManager) attempts to provide a common interface for working with - * reference mark based and bookmark based text ranges to be used as locations to fill with citation - * markers. LibreOffice supports name-based lookup and listing names for both (hence the name). - * - * Note: currently only implemented for refence marks (in NamedRangeReferenceMark and - * NamedRangeManagerReferenceMark). - * + * NamedRange (with NamedRangeManager) attempts to provide a common interface for working with reference mark based and bookmark based text ranges to be used as locations to fill with citation markers. LibreOffice supports name-based lookup and listing names for both (hence the name). + *

    + * Note: currently only implemented for refence marks (in NamedRangeReferenceMark and NamedRangeManagerReferenceMark). */ public interface NamedRange { @@ -27,45 +23,42 @@ public interface NamedRange { * @return Optional.empty if the mark is missing from the document. */ Optional getMarkRange(XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException; + throws + NoDocumentException, + WrappedTargetException; /** - * Cursor for the reference marks as is, not prepared for filling, but does not need - * cleanFillCursor either. + * Cursor for the reference marks as is, not prepared for filling, but does not need cleanFillCursor either. */ Optional getRawCursor(XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException; + throws + NoDocumentException, + WrappedTargetException; /** * Get a cursor for filling in text. - * + *

    * Must be followed by cleanFillCursor() */ XTextCursor getFillCursor(XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException, - CreationException; + throws + NoDocumentException, + WrappedTargetException, + CreationException; /** - * Remove brackets, but if the result would become empty, leave them; if the result would be a - * single character, leave the left bracket. - * + * Remove brackets, but if the result would become empty, leave them; if the result would be a single character, leave the left bracket. */ void cleanFillCursor(XTextDocument doc) - throws - NoDocumentException, - WrappedTargetException; + throws + NoDocumentException, + WrappedTargetException; /** - * Note: create is in NamedRangeManager + * Note: create is in NamedRangeManager */ void removeFromDocument(XTextDocument doc) - throws - WrappedTargetException, - NoDocumentException; + throws + WrappedTargetException, + NoDocumentException; } diff --git a/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java b/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java index 9bbcc752350..25a82b4ad19 100644 --- a/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java +++ b/src/main/java/org/jabref/model/openoffice/backend/NamedRangeManager.java @@ -17,15 +17,15 @@ NamedRange createNamedRange(XTextDocument doc, XTextCursor position, boolean insertSpaceAfter, boolean withoutBrackets) - throws - CreationException; + throws + CreationException; List getUsedNames(XTextDocument doc) - throws - NoDocumentException; + throws + NoDocumentException; Optional getNamedRangeFromDocument(XTextDocument doc, String markName) - throws - NoDocumentException, - WrappedTargetException; + throws + NoDocumentException, + WrappedTargetException; } diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java index 6b4a96de644..14f5822de4f 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java @@ -4,40 +4,33 @@ /** * Helper functions to produce some of the markup as understood by OOTextIntoOO.write - * - * These do not cover all tags, only those needed to embed markup - * from Layout and citation marker formatters into citation markers and - * bibliography. + *

    + * These do not cover all tags, only those needed to embed markup from Layout and citation marker formatters into citation markers and bibliography. */ public class OOFormat { private OOFormat() { - /* */ } /** * Mark {@code ootext} as using a character locale known to OO. * * @param locale language[-country[-territory]] - * - * https://www.openoffice.org/api/docs/common/ref/com/sun/star/lang/Locale.html - * - * The country part is optional. - * - * The territory part is not only optional, the allowed "codes are vendor and browser-specific", - * so probably best to avoid them if possible. - * + *

    + * https://www.openoffice.org/api/docs/common/ref/com/sun/star/lang/Locale.html + *

    + * The country part is optional. + *

    + * The territory part is not only optional, the allowed "codes are vendor and browser-specific", so probably best to avoid them if possible. */ public static OOText setLocale(OOText ootext, String locale) { return OOText.fromString(String.format("", locale) + ootext.toString() + ""); } /** - * Mark {@code ootext} as using the character locale "zxx", which means "no language", "no - * linguistic content". - * + * Mark {@code ootext} as using the character locale "zxx", which means "no language", "no linguistic content". + *

    * Used around citation marks, probably to turn off spellchecking. - * */ public static OOText setLocaleNone(OOText ootext) { return OOFormat.setLocale(ootext, "zxx"); @@ -46,14 +39,12 @@ public static OOText setLocaleNone(OOText ootext) { /** * Mark {@code ootext} using a character style {@code charStyle} * - * @param charStyle Name of a character style known to OO. May be empty for "Standard", which in - * turn means do not override any properties. - * + * @param charStyle Name of a character style known to OO. May be empty for "Standard", which in turn means do not override any properties. */ public static OOText setCharStyle(OOText ootext, String charStyle) { return OOText.fromString(String.format("", charStyle) - + ootext.toString() - + ""); + + ootext.toString() + + ""); } /** @@ -81,4 +72,4 @@ public static OOText formatReferenceToPageNumberOfReferenceMark(String reference String string = String.format("", referenceMarkName); return OOText.fromString(string); } - } +} diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOText.java b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java index 5b5fa4caba9..8478ca4a65a 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOText.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOText.java @@ -4,9 +4,8 @@ /** * Text with HTML-like markup as understood by OOTextIntoOO.write - * - * Some of the tags can be added using OOFormat methods. Others come from the layout engine, either - * by interpreting LaTeX markup or from settings in the jstyle file. + *

    + * Some of the tags can be added using OOFormat methods. Others come from the layout engine, either by interpreting LaTeX markup or from settings in the jstyle file. */ public class OOText { @@ -17,7 +16,9 @@ private OOText(String data) { this.data = data; } - /** @return null for null input, otherwise the argument wrapped into a new OOText */ + /** + * @return null for null input, otherwise the argument wrapped into a new OOText + */ public static OOText fromString(String string) { if (string == null) { return null; @@ -25,7 +26,9 @@ public static OOText fromString(String string) { return new OOText(string); } - /** @return null for null input, otherwise the string inside the argument */ + /** + * @return null for null input, otherwise the string inside the argument + */ public static String toString(OOText ootext) { if (ootext == null) { return null; diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java index 909b088b5b3..6ed9dedebc1 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java @@ -53,7 +53,7 @@ public class OOTextIntoOO { private static final Logger LOGGER = LoggerFactory.getLogger(OOTextIntoOO.class); /** - * "ParaStyleName" is an OpenOffice Property name. + * "ParaStyleName" is an OpenOffice Property name. */ private static final String PARA_STYLE_NAME = "ParaStyleName"; @@ -77,78 +77,60 @@ public class OOTextIntoOO { private static final byte SUBSCRIPT_HEIGHT = (byte) 58; private static final String TAG_NAME_REGEXP = - "(?:b|i|em|tt|smallcaps|sup|sub|u|s|p|span|oo:referenceToPageNumberOfReferenceMark)"; + "(?:b|i|em|tt|smallcaps|sup|sub|u|s|p|span|oo:referenceToPageNumberOfReferenceMark)"; private static final String ATTRIBUTE_NAME_REGEXP = - "(?:oo:ParaStyleName|oo:CharStyleName|lang|style|target)"; + "(?:oo:ParaStyleName|oo:CharStyleName|lang|style|target)"; private static final String ATTRIBUTE_VALUE_REGEXP = "\"([^\"]*)\""; private static final Pattern HTML_TAG = - Pattern.compile("<(/" + TAG_NAME_REGEXP + ")>" - + "|" - + "<(" + TAG_NAME_REGEXP + ")" - + "((?:\\s+(" + ATTRIBUTE_NAME_REGEXP + ")=" + ATTRIBUTE_VALUE_REGEXP + ")*)" - + ">"); + Pattern.compile("<(/" + TAG_NAME_REGEXP + ")>" + + "|" + + "<(" + TAG_NAME_REGEXP + ")" + + "((?:\\s+(" + ATTRIBUTE_NAME_REGEXP + ")=" + ATTRIBUTE_VALUE_REGEXP + ")*)" + + ">"); private static final Pattern ATTRIBUTE_PATTERN = - Pattern.compile("\\s+(" + ATTRIBUTE_NAME_REGEXP + ")=" + ATTRIBUTE_VALUE_REGEXP); + Pattern.compile("\\s+(" + ATTRIBUTE_NAME_REGEXP + ")=" + ATTRIBUTE_VALUE_REGEXP); private OOTextIntoOO() { - // Hide the public constructor } /** - * Insert a text with formatting indicated by HTML-like tags, into - * a text at the position given by a cursor. - * - * Limitation: understands no entities. It does not receive any either, unless - * the user provides it. - * - * To limit the damage {@code TAG_NAME_REGEXP} and {@code ATTRIBUTE_NAME_REGEXP} - * explicitly lists the names we care about. - * + * Insert a text with formatting indicated by HTML-like tags, into a text at the position given by a cursor. + *

    + * Limitation: understands no entities. It does not receive any either, unless the user provides it. + *

    + * To limit the damage {@code TAG_NAME_REGEXP} and {@code ATTRIBUTE_NAME_REGEXP} explicitly lists the names we care about. + *

    * Notable changes w.r.t insertOOFormattedTextAtCurrentLocation: - * + *

    * - new tags: + *

    + * - {@code } - earlier was applied from code + *

    + * - {@code } - earlier was applied from code, for "CitationCharacterFormat" + *

    + * - {@code

    } start new paragraph - earlier was applied from code + *

    + * - {@code

    } : start new paragraph and apply ParStyleName - earlier was applied from code + *

    + * - {@code } - earlier: known, but ignored - now: equivalent to {@code } - {@code } (self-closing) + *

    + * - closing tags try to properly restore state (in particular, the "not directly set" state) instead of dictating an "off" state. This makes a difference when the value inherited from another level (for example the paragraph) is not the "off" state. + *

    + * An example: a style with {@code ReferenceParagraphFormat="JR_bibentry"} Assume JR_bibentry in LibreOffice is a paragraph style that prescribes "bold" font. LAYOUT only prescribes bold around year. Which parts of the bibliography entries should come out as bold? + *

    + * - The user can format citation marks (it is enough to format their start) and the properties not (everywhere) dictated by the style are preserved (where they are not). * - * - {@code } - * - earlier was applied from code - * - * - {@code } - * - earlier was applied from code, for "CitationCharacterFormat" - * - * - {@code

    } start new paragraph - * - earlier was applied from code - * - * - {@code

    } : start new paragraph and apply ParStyleName - * - earlier was applied from code - * - * - {@code } - * - earlier: known, but ignored - * - now: equivalent to {@code } - * - {@code } (self-closing) - * - * - closing tags try to properly restore state (in particular, the "not directly set" state) - * instead of dictating an "off" state. This makes a difference when the value inherited from - * another level (for example the paragraph) is not the "off" state. - * - * An example: a style with - * {@code ReferenceParagraphFormat="JR_bibentry"} - * Assume JR_bibentry in LibreOffice is a paragraph style that prescribes "bold" font. - * LAYOUT only prescribes bold around year. - * Which parts of the bibliography entries should come out as bold? - * - * - The user can format citation marks (it is enough to format their start) and the - * properties not (everywhere) dictated by the style are preserved (where they are not). - * - * @param position The cursor giving the insert location. Not modified. - * @param ootext The marked-up text to insert. + * @param position The cursor giving the insert location. Not modified. + * @param ootext The marked-up text to insert. */ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) - throws - WrappedTargetException, - CreationException { + throws + WrappedTargetException, + CreationException { Objects.requireNonNull(doc); Objects.requireNonNull(ootext); @@ -231,7 +213,7 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) case "oo:ParaStyleName": //

    if (StringUtil.isNullOrEmpty(value)) { - LOGGER.debug(String.format("oo:ParaStyleName inherited")); + LOGGER.debug("oo:ParaStyleName inherited"); } else { if (setParagraphStyle(cursor, value)) { // Presumably tested already: @@ -250,12 +232,8 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) String key = pair.a; String value = pair.b; switch (key) { - case "target": - UnoCrossRef.insertReferenceToPageNumberOfReferenceMark(doc, value, cursor); - break; - default: - LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); - break; + case "target" -> UnoCrossRef.insertReferenceToPageNumberOfReferenceMark(doc, value, cursor); + default -> LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); } } break; @@ -270,27 +248,23 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) String key = pair.a; String value = pair.b; switch (key) { - case "oo:CharStyleName": - // - settings.addAll(setCharStyleName(value)); - break; - case "lang": - // - // - settings.addAll(setCharLocale(value)); - break; - case "style": + case "oo:CharStyleName" -> + // + settings.addAll(setCharStyleName(value)); + case "lang" -> + // + // + settings.addAll(setCharLocale(value)); + case "style" -> { // HTML-style small-caps if ("font-variant: small-caps".equals(value)) { settings.addAll(setCharCaseMap(CaseMap.SMALLCAPS)); break; } LOGGER.warn(String.format("Unexpected value %s for attribute '%s' for <%s>", - value, key, tagName)); - break; - default: - LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); - break; + value, key, tagName)); + } + default -> LOGGER.warn(String.format("Unexpected attribute '%s' for <%s>", key, tagName)); } } formatStack.pushLayer(settings); @@ -310,9 +284,9 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) String expected = expectEnd.pop(); if (!tagName.equals(expected)) { LOGGER.warn(String.format("expected '<%s>', found '<%s>' after '%s'", - expected, - tagName, - currentSubstring)); + expected, + tagName, + currentSubstring)); } break; default: @@ -330,21 +304,18 @@ public static void write(XTextDocument doc, XTextCursor position, OOText ootext) cursor.collapseToEnd(); if (!expectEnd.empty()) { - String rest = ""; + StringBuilder rest = new StringBuilder(); for (String s : expectEnd) { - rest = String.format("<%s>", s) + rest; + rest.insert(0, String.format("<%s>", s)); } - LOGGER.warn(String.format("OOTextIntoOO.write:" - + " expectEnd stack is not empty at the end: %s%n", - rest)); + LOGGER.warn(String.format("OOTextIntoOO.write: expectEnd stack is not empty at the end: %s%n", rest)); } } /** - * Purpose: in some cases we do not want to inherit direct - * formatting from the context. - * - * In particular, when filling the bibliography title and body. + * Purpose: in some cases we do not want to inherit direct formatting from the context. + *

    + * In particular, when filling the bibliography title and body. */ public static void removeDirectFormatting(XTextCursor cursor) { @@ -358,8 +329,8 @@ public static void removeDirectFormatting(XTextCursor cursor) { propertySet.setPropertyValue(CHAR_STYLE_NAME, "Standard"); xPropertyState.setPropertyToDefault("CharCaseMap"); } catch (UnknownPropertyException | - PropertyVetoException | - WrappedTargetException ex) { + PropertyVetoException | + WrappedTargetException ex) { LOGGER.warn("exception caught", ex); } @@ -374,14 +345,14 @@ public static void removeDirectFormatting(XTextCursor cursor) { // Only report those we do not yet know about final Set knownToFail = Set.of("ListAutoFormat", - "ListId", - "NumberingIsNumber", - "NumberingLevel", - "NumberingRules", - "NumberingStartValue", - "ParaChapterNumberingLevel", - "ParaIsNumberingRestart", - "ParaStyleName"); + "ListId", + "NumberingIsNumber", + "NumberingLevel", + "NumberingRules", + "NumberingStartValue", + "ParaChapterNumberingLevel", + "ParaIsNumberingRestart", + "ParaStyleName"); // query again, just in case it matters propertySet = UnoCast.cast(XPropertySet.class, cursor).get(); @@ -422,34 +393,34 @@ static class MyPropertyStack { */ static final Set CONTROLLED_PROPERTIES = Set.of( - /* Used for SuperScript, SubScript. - * - * These three are interdependent: changing one may change others. - */ - "CharEscapement", "CharEscapementHeight", "CharAutoEscapement", + /* Used for SuperScript, SubScript. + * + * These three are interdependent: changing one may change others. + */ + "CharEscapement", "CharEscapementHeight", "CharAutoEscapement", - /* used for Bold */ - "CharWeight", + /* used for Bold */ + "CharWeight", - /* Used for Italic */ - "CharPosture", + /* Used for Italic */ + "CharPosture", - /* Used for strikeout. These two are interdependent. */ - "CharStrikeout", "CharCrossedOut", + /* Used for strikeout. These two are interdependent. */ + "CharStrikeout", "CharCrossedOut", - /* Used for underline. These three are interdependent, but apparently - * we can leave out the last two. - */ - "CharUnderline", // "CharUnderlineColor", "CharUnderlineHasColor", + /* Used for underline. These three are interdependent, but apparently + * we can leave out the last two. + */ + "CharUnderline", // "CharUnderlineColor", "CharUnderlineHasColor", - /* Used for lang="zxx", to silence spellchecker. */ - "CharLocale", + /* Used for lang="zxx", to silence spellchecker. */ + "CharLocale", - /* Used for CitationCharacterFormat. */ - "CharStyleName", + /* Used for CitationCharacterFormat. */ + "CharStyleName", - /* Used for and */ - "CharCaseMap"); + /* Used for and */ + "CharCaseMap"); /** * The number of properties actually controlled. @@ -467,9 +438,7 @@ static class MyPropertyStack { final String[] goodNames; /** - * Maintain a stack of layers, each containing a description of the desired state of - * properties. Each description is an ArrayList of property values, Optional.empty() - * encoding "not directly set". + * Maintain a stack of layers, each containing a description of the desired state of properties. Each description is an ArrayList of property values, Optional.empty() encoding "not directly set". */ final Stack>> layers; @@ -498,7 +467,7 @@ static class MyPropertyStack { this.goodNames = new String[goodSize]; for (Map.Entry entry : goodNameToIndex.entrySet()) { - goodNames[ entry.getValue() ] = entry.getKey(); + goodNames[entry.getValue()] = entry.getKey(); } // XMultiPropertySet.setPropertyValues() requires alphabetically sorted property names. @@ -537,9 +506,8 @@ static class MyPropertyStack { } /** - * Given a list of property name, property value pairs, construct and push a new layer - * describing the intended state after these have been applied. - * + * Given a list of property name, property value pairs, construct and push a new layer describing the intended state after these have been applied. + *

    * Opening tags usually call this. */ void pushLayer(List> settings) { @@ -571,7 +539,7 @@ void popLayer() { /** * Apply the current desired formatting state to a cursor. - * + *

    * The idea is to minimize the number of calls to OpenOffice. */ void apply(XTextCursor cursor) { @@ -629,7 +597,7 @@ private static List> parseAttributes(String attributes) { while (attributeMatcher.find()) { String key = attributeMatcher.group(1); String value = attributeMatcher.group(2); - res.add(new OOPair(key, value)); + res.add(new OOPair<>(key, value)); } return res; } @@ -640,13 +608,13 @@ private static List> parseAttributes(String attributes) { * true. */ private static boolean isPropertyDefault(XTextCursor cursor, String propertyName) - throws - UnknownPropertyException { + throws + UnknownPropertyException { XPropertyState xPropertyState = UnoCast.cast(XPropertyState.class, cursor).get(); PropertyState state = xPropertyState.getPropertyState(propertyName); if (state == PropertyState.AMBIGUOUS_VALUE) { throw new java.lang.IllegalArgumentException("PropertyState.AMBIGUOUS_VALUE" - + " (expected properties for a homogeneous cursor)"); + + " (expected properties for a homogeneous cursor)"); } return state == PropertyState.DEFAULT_VALUE; } @@ -657,33 +625,33 @@ private static boolean isPropertyDefault(XTextCursor cursor, String propertyName private static List> setCharWeight(float value) { List> settings = new ArrayList<>(); - settings.add(new OOPair<>("CharWeight", (Float) value)); + settings.add(new OOPair<>("CharWeight", value)); return settings; } private static List> setCharPosture(FontSlant value) { List> settings = new ArrayList<>(); - settings.add(new OOPair<>("CharPosture", (Object) value)); + settings.add(new OOPair<>("CharPosture", value)); return settings; } private static List> setCharCaseMap(short value) { List> settings = new ArrayList<>(); - settings.add(new OOPair<>("CharCaseMap", (Short) value)); + settings.add(new OOPair<>("CharCaseMap", value)); return settings; } // com.sun.star.awt.FontUnderline private static List> setCharUnderline(short value) { List> settings = new ArrayList<>(); - settings.add(new OOPair<>(CHAR_UNDERLINE, (Short) value)); + settings.add(new OOPair<>(CHAR_UNDERLINE, value)); return settings; } // com.sun.star.awt.FontStrikeout private static List> setCharStrikeout(short value) { List> settings = new ArrayList<>(); - settings.add(new OOPair<>(CHAR_STRIKEOUT, (Short) value)); + settings.add(new OOPair<>(CHAR_STRIKEOUT, value)); return settings; } @@ -701,7 +669,7 @@ private static List> setCharStyleName(String value) { // Locale private static List> setCharLocale(Locale value) { List> settings = new ArrayList<>(); - settings.add(new OOPair<>("CharLocale", (Object) value)); + settings.add(new OOPair<>("CharLocale", value)); return settings; } @@ -731,12 +699,12 @@ private static List> setCharEscapement(Optional va MyPropertyStack formatStack) { List> settings = new ArrayList<>(); Optional oldValue = (formatStack - .getPropertyValue(CHAR_ESCAPEMENT) - .map(e -> (short) e)); + .getPropertyValue(CHAR_ESCAPEMENT) + .map(e -> (short) e)); Optional oldHeight = (formatStack - .getPropertyValue(CHAR_ESCAPEMENT_HEIGHT) - .map(e -> (byte) e)); + .getPropertyValue(CHAR_ESCAPEMENT_HEIGHT) + .map(e -> (byte) e)); if (relative && (value.isPresent() || height.isPresent())) { double oldHeightFloat = oldHeight.orElse(CHAR_ESCAPEMENT_HEIGHT_DEFAULT) * 0.01; @@ -746,17 +714,17 @@ private static List> setCharEscapement(Optional va byte newHeight = (byte) Math.round(heightFloat * oldHeightFloat); short newValue = (short) Math.round(valueFloat * oldHeightFloat + oldValueFloat); if (value.isPresent()) { - settings.add(new OOPair<>(CHAR_ESCAPEMENT, (Short) newValue)); + settings.add(new OOPair<>(CHAR_ESCAPEMENT, newValue)); } if (height.isPresent()) { - settings.add(new OOPair<>(CHAR_ESCAPEMENT_HEIGHT, (Byte) newHeight)); + settings.add(new OOPair<>(CHAR_ESCAPEMENT_HEIGHT, newHeight)); } } else { if (value.isPresent()) { - settings.add(new OOPair<>(CHAR_ESCAPEMENT, (Short) value.get())); + settings.add(new OOPair<>(CHAR_ESCAPEMENT, value.get())); } if (height.isPresent()) { - settings.add(new OOPair<>(CHAR_ESCAPEMENT_HEIGHT, (Byte) height.get())); + settings.add(new OOPair<>(CHAR_ESCAPEMENT_HEIGHT, height.get())); } } return settings; @@ -764,16 +732,16 @@ private static List> setCharEscapement(Optional va private static List> setSubScript(MyPropertyStack formatStack) { return setCharEscapement(Optional.of(SUBSCRIPT_VALUE), - Optional.of(SUBSCRIPT_HEIGHT), - true, - formatStack); + Optional.of(SUBSCRIPT_HEIGHT), + true, + formatStack); } private static List> setSuperScript(MyPropertyStack formatStack) { return setCharEscapement(Optional.of(SUPERSCRIPT_VALUE), - Optional.of(SUPERSCRIPT_HEIGHT), - true, - formatStack); + Optional.of(SUPERSCRIPT_HEIGHT), + true, + formatStack); } /* @@ -789,9 +757,9 @@ public static boolean setParagraphStyle(XTextCursor cursor, String paragraphStyl propertySet.setPropertyValue(PARA_STYLE_NAME, paragraphStyle); return PASS; } catch (UnknownPropertyException - | PropertyVetoException - | com.sun.star.lang.IllegalArgumentException - | WrappedTargetException ex) { + | PropertyVetoException + | com.sun.star.lang.IllegalArgumentException + | WrappedTargetException ex) { return FAIL; } } @@ -806,5 +774,4 @@ private static void insertParagraphBreak(XText text, XTextCursor cursor) { throw new java.lang.IllegalArgumentException("Caught unexpected com.sun.star.lang.IllegalArgumentException", ex); } } - } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java b/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java index e08a7f4a2ad..314de5e37f3 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/FunctionalTextViewCursor.java @@ -44,13 +44,13 @@ public class FunctionalTextViewCursor { /* The initial position of the cursor or null. */ - private XTextRange initialPosition; + private final XTextRange initialPosition; /* The initial selection in the document or null. */ - private XServiceInfo initialSelection; + private final XServiceInfo initialSelection; /* The view cursor, potentially moved from its original location. */ - private XTextViewCursor viewCursor; + private final XTextViewCursor viewCursor; private FunctionalTextViewCursor(XTextRange initialPosition, XServiceInfo initialSelection, @@ -90,8 +90,8 @@ public static OOResult get(XTextDocument doc) if (initialSelection == null) { String errorMessage = ("Selection is not available: cannot provide a functional view cursor"); return OOResult.error(errorMessage); - } else if (!Arrays.stream(initialSelection.getSupportedServiceNames()) - .anyMatch("com.sun.star.text.TextRanges"::equals)) { + } else if (Arrays.stream(initialSelection.getSupportedServiceNames()) + .noneMatch("com.sun.star.text.TextRanges"::equals)) { // initialSelection does not support TextRanges. // We need to change it (and the viewCursor with it). XTextRange newSelection = doc.getText().getStart(); diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlap.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlap.java index 3edd059d7ff..1f4f3ae0ed4 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlap.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlap.java @@ -3,7 +3,7 @@ import java.util.List; /** - * Used in reporting range overlaps. + * Used in reporting range overlaps. */ public class RangeOverlap { public final RangeOverlapKind kind; diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java index 16b7735fb7a..a5cb13fb4f0 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapBetween.java @@ -14,13 +14,14 @@ public class RangeOverlapBetween { - private RangeOverlapBetween() { } + private RangeOverlapBetween() { + } /** * Check for any overlap between two sets of XTextRange values. - * + *

    * Assume fewHolders is small (usually a single element, for checking the cursor) - * + *

    * Returns on first problem found. */ public static @@ -44,8 +45,8 @@ List> findFirst(XTextDocument doc, for (V aHolder : fewHolders) { XText aText = aHolder.getRange().getText(); fewTuples.add(new OOTuple3<>(aText, - UnoCast.cast(XTextRangeCompare.class, aText).get(), - aHolder)); + UnoCast.cast(XTextRangeCompare.class, aText).get(), + aHolder)); } /* @@ -81,14 +82,14 @@ List> findFirst(XTextDocument doc, // // We return EQUAL_RANGE RangeOverlapKind kind = (equal ? RangeOverlapKind.EQUAL_RANGE - : (touching ? RangeOverlapKind.TOUCH - : RangeOverlapKind.OVERLAP)); + : (touching ? RangeOverlapKind.TOUCH + : RangeOverlapKind.OVERLAP)); List valuesForOverlappingRanges = new ArrayList<>(); valuesForOverlappingRanges.add(aHolder); valuesForOverlappingRanges.add(bHolder); - result.add(new RangeOverlap(kind, valuesForOverlappingRanges)); + result.add(new RangeOverlap<>(kind, valuesForOverlappingRanges)); return result; } } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapKind.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapKind.java index 2bb7f8f4af7..1098a85a87f 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapKind.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapKind.java @@ -2,13 +2,19 @@ public enum RangeOverlapKind { - /** The ranges share a boundary */ + /** + * The ranges share a boundary + */ TOUCH, - /** They share some characters */ + /** + * They share some characters + */ OVERLAP, - /** They cover the same XTextRange */ + /** + * They cover the same XTextRange + */ EQUAL_RANGE } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java index a8534b630ae..69ff4ca91d1 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeOverlapWithin.java @@ -12,23 +12,18 @@ public class RangeOverlapWithin { - private RangeOverlapWithin() { } + private RangeOverlapWithin() { + } /** * Report identical, overlapping or touching ranges between elements of rangeHolders. + *

    + * For overlapping and touching, only report consecutive ranges and only with a single sample of otherwise identical ranges. * - * For overlapping and touching, only report consecutive ranges and only with a single sample of - * otherwise identical ranges. - * - * @param rangeHolders represent the ranges to be checked. - * - * Note: for each rangeHolder, rangeHolder.getRange() is called multiple times. - * To avoid repeated work, they should keep a copy of the range instead of - * getting it each time from the document. - * - * @param reportAtMost Limit the number of records returned to atMost. - * Zero {@code reportAtMost} means no limit. - * + * @param rangeHolders represent the ranges to be checked. + *

    + * Note: for each rangeHolder, rangeHolder.getRange() is called multiple times. To avoid repeated work, they should keep a copy of the range instead of getting it each time from the document. + * @param reportAtMost Limit the number of records returned to atMost. Zero {@code reportAtMost} means no limit. * @param includeTouching Should the result contain ranges sharing only a boundary? */ public static @@ -44,13 +39,10 @@ List> findOverlappingRanges(XTextDocument doc, /** * Report identical, overlapping or touching ranges. + *

    + * For overlapping and touching, only report consecutive ranges and only with a single sample of otherwise identical ranges. * - * For overlapping and touching, only report consecutive ranges and only with a single sample of - * otherwise identical ranges. - * - * @param atMost Limit the number of records returned to atMost. - * Zero {@code atMost} means no limit. - * + * @param atMost Limit the number of records returned to atMost. Zero {@code atMost} means no limit. * @param includeTouching Should the result contain ranges sharing only a boundary? */ public static @@ -66,7 +58,7 @@ List> findOverlappingRanges(RangeSort.RangePartitions input, continue; } XTextRangeCompare cmp = UnoCast.cast(XTextRangeCompare.class, - partition.get(0).getRange().getText()).get(); + partition.get(0).getRange().getText()).get(); for (int i = 0; i < (partition.size() - 1); i++) { V aHolder = partition.get(i); @@ -82,15 +74,15 @@ List> findOverlappingRanges(RangeSort.RangePartitions input, // aValues.add(bHolder); // collect those equal while (i < (partition.size() - 1) && - UnoTextRange.compareStartsThenEndsUnsafe( - cmp, - aRange, - partition.get(i + 1).getRange()) == 0) { + UnoTextRange.compareStartsThenEndsUnsafe( + cmp, + aRange, + partition.get(i + 1).getRange()) == 0) { bHolder = partition.get(i + 1); aValues.add(bHolder); i++; } - result.add(new RangeOverlap(RangeOverlapKind.EQUAL_RANGE, aValues)); + result.add(new RangeOverlap<>(RangeOverlapKind.EQUAL_RANGE, aValues)); if (atMost > 0 && result.size() >= atMost) { return result; } @@ -105,17 +97,16 @@ List> findOverlappingRanges(RangeSort.RangePartitions input, List valuesForOverlappingRanges = new ArrayList<>(); valuesForOverlappingRanges.add(aHolder); valuesForOverlappingRanges.add(bHolder); - result.add(new RangeOverlap((cmpResult == 0) - ? RangeOverlapKind.TOUCH - : RangeOverlapKind.OVERLAP, - valuesForOverlappingRanges)); + result.add(new RangeOverlap<>((cmpResult == 0) + ? RangeOverlapKind.TOUCH + : RangeOverlapKind.OVERLAP, + valuesForOverlappingRanges)); } if (atMost > 0 && result.size() >= atMost) { - return result; + return result; } } } return result; } - } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java index 99ace5154e1..77982a9a7db 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSort.java @@ -13,22 +13,17 @@ import com.sun.star.text.XTextRangeCompare; /** - * RangeSort provides sorting based on XTextRangeCompare, which only provides comparison - * between XTextRange values within the same XText. + * RangeSort provides sorting based on XTextRangeCompare, which only provides comparison between XTextRange values within the same XText. */ public class RangeSort { private RangeSort() { - /**/ } /** * Compare two RangeHolders (using RangeHolder.getRange()) within an XText. - * - * Note: since we only look at the ranges, this comparison is generally not consistent with - * `equals` on the RangeHolders. Probably should not be used for key comparison in - * {@code TreeMap} or {@code Set} - * + *

    + * Note: since we only look at the ranges, this comparison is generally not consistent with `equals` on the RangeHolders. Probably should not be used for key comparison in {@code TreeMap} or {@code Set} */ private static class HolderComparatorWithinPartition implements Comparator { @@ -36,7 +31,7 @@ private static class HolderComparatorWithinPartition implements Comparator * Note: RangeHolder.getRange() is called many times. */ public static void sortWithinPartition(List rangeHolders) { @@ -83,7 +78,7 @@ public List> getPartitions() { } /** - * Partition RangeHolders by the corresponding XText. + * Partition RangeHolders by the corresponding XText. */ public static RangePartitions partitionRanges(List holders) { RangePartitions result = new RangePartitions<>(); diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java index e412f4ade6c..b83db3f1555 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortVisual.java @@ -14,25 +14,21 @@ /** * Sort XTextRange values visually (top-down,left-to-right). - * + *

    * Requires functional XTextViewCursor. - * - * Problem: for multicolumn layout and when viewing pages side-by-side in LO, the - * (top-down,left-to-right) order interpreted as-on-the-screen: an XTextRange at the top of - * the second column or second page is sorted before an XTextRange at the bottom of the - * first column of the first page. + *

    + * Problem: for multicolumn layout and when viewing pages side-by-side in LO, the (top-down,left-to-right) order interpreted as-on-the-screen: an XTextRange at the top of the second column or second page is sorted before an XTextRange at the bottom of the first column of the first page. */ public class RangeSortVisual { private static final Logger LOGGER = LoggerFactory.getLogger(RangeSortVisual.class); private RangeSortVisual() { - /**/ } /** * Sort the input {@code inputs} visually. - * + *

    * Requires a functional {@code XTextViewCursor}. * * @return The input, sorted by the elements XTextRange and getIndexInPosition. @@ -63,8 +59,8 @@ public static List> visualSort(List> input for (int i = 0; i < inputSize; i++) { RangeSortable input = inputs.get(i); comparableMarks.add(new ComparableMark<>(positions.get(i), - input.getIndexInPosition(), - input)); + input.getIndexInPosition(), + input)); } comparableMarks.sort(RangeSortVisual::compareTopToBottomLeftToRight); @@ -82,22 +78,16 @@ public static List> visualSort(List> input } /** - * Given a location, return its position: coordinates relative to the top left position of the - * first page of the document. - * - * Note: for text layouts with two or more columns, this gives the wrong order: - * top-down/left-to-right does not match reading order. - * - * Note: The "relative to the top left position of the first page" is meant "as it appears on - * the screen". - * - * In particular: when viewing pages side-by-side, the top half of the right page is - * higher than the lower half of the left page. Again, top-down/left-to-right does not - * match reading order. + * Given a location, return its position: coordinates relative to the top left position of the first page of the document. + *

    + * Note: for text layouts with two or more columns, this gives the wrong order: top-down/left-to-right does not match reading order. + *

    + * Note: The "relative to the top left position of the first page" is meant "as it appears on the screen". + *

    + * In particular: when viewing pages side-by-side, the top half of the right page is higher than the lower half of the left page. Again, top-down/left-to-right does not match reading order. * * @param range Location. - * @param cursor To get the position, we need az XTextViewCursor. - * It will be moved to the range. + * @param cursor To get the position, we need az XTextViewCursor. It will be moved to the range. */ private static Point findPositionOfTextRange(XTextRange range, XTextViewCursor cursor) { cursor.gotoRange(range, false); @@ -117,10 +107,9 @@ private static int compareTopToBottomLeftToRight(ComparableMark a, Compar /** * A reference mark name paired with its visual position. - * - * Comparison is based on (Y,X,indexInPosition): vertical compared first, horizontal second, - * indexInPosition third. - * + *

    + * Comparison is based on (Y,X,indexInPosition): vertical compared first, horizontal second, indexInPosition third. + *

    * Used for sorting reference marks by their visual positions. */ private static class ComparableMark { @@ -138,7 +127,5 @@ public ComparableMark(Point position, int indexInPosition, T content) { public T getContent() { return content; } - } - } diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java index 59a4c3fa9af..15482f0a3e6 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortable.java @@ -7,9 +7,10 @@ */ public interface RangeSortable extends RangeHolder { - /** The XTextRange - * - * For citation marks in footnotes this may be the range of the footnote mark. + /** + * The XTextRange + *

    + * For citation marks in footnotes this may be the range of the footnote mark. */ XTextRange getRange(); diff --git a/src/main/java/org/jabref/model/openoffice/style/Citation.java b/src/main/java/org/jabref/model/openoffice/style/Citation.java index 7bae4fd2548..899013773f2 100644 --- a/src/main/java/org/jabref/model/openoffice/style/Citation.java +++ b/src/main/java/org/jabref/model/openoffice/style/Citation.java @@ -10,27 +10,36 @@ public class Citation implements ComparableCitation, CitationMarkerEntry, CitationMarkerNumericEntry { - /** key in database */ + /** + * key in database + */ public final String citationKey; - /** Result from database lookup. Optional.empty() if not found. */ + /** + * Result from database lookup. Optional.empty() if not found. + */ private Optional db; - /** The number used for numbered citation styles . */ + /** + * The number used for numbered citation styles . + */ private Optional number; - /** Letter that makes the in-text citation unique. */ + /** + * Letter that makes the in-text citation unique. + */ private Optional uniqueLetter; - /** pageInfo */ + /** + * pageInfo + */ private Optional pageInfo; - /** isFirstAppearanceOfSource */ - private boolean isFirstAppearanceOfSource; - /** - * + * isFirstAppearanceOfSource */ + private boolean isFirstAppearanceOfSource; + public Citation(String citationKey) { this.citationKey = citationKey; this.db = Optional.empty(); @@ -57,9 +66,7 @@ public boolean getIsFirstAppearanceOfSource() { @Override public Optional getBibEntry() { - return (db.isPresent() - ? Optional.of(db.get().entry) - : Optional.empty()); + return db.map(citationLookupResult -> citationLookupResult.entry); } public static Optional lookup(BibDatabase database, String key) { @@ -70,10 +77,10 @@ public static Optional lookup(BibDatabase database, String public static Optional lookup(List databases, String key) { return (databases.stream() - .map(database -> Citation.lookup(database, key)) - .filter(Optional::isPresent) - .map(Optional::get) - .findFirst()); + .map(database -> Citation.lookup(database, key)) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst()); } public void lookupInDatabases(List databases) { @@ -129,18 +136,17 @@ public void setIsFirstAppearanceOfSource(boolean value) { * Setters for CitationGroups.distribute() */ public static void setLookupResult(OOPair> pair) { - Citation cit = pair.a; - cit.db = pair.b; + Citation citation = pair.a; + citation.db = pair.b; } public static void setNumber(OOPair> pair) { - Citation cit = pair.a; - cit.number = pair.b; + Citation citation = pair.a; + citation.number = pair.b; } public static void setUniqueLetter(OOPair> pair) { - Citation cit = pair.a; - cit.uniqueLetter = pair.b; + Citation citation = pair.a; + citation.uniqueLetter = pair.b; } - } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java index 90afb872d4f..30831035533 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java @@ -98,7 +98,7 @@ void imposeLocalOrder(Comparator entryComparator) { } this.localOrder = OOListUtil.order(citationsInStorageOrder, - new CompareCitation(entryComparator, true)); + new CompareCitation(entryComparator, true)); if (dataModel == OODataModel.JabRef52) { getCitationsInLocalOrder().get(last).setPageInfo(lastPageInfo); @@ -114,7 +114,7 @@ public List getLocalOrder() { */ public List getCitationsInLocalOrder() { - return OOListUtil.map(localOrder, i -> citationsInStorageOrder.get(i)); + return OOListUtil.map(localOrder, citationsInStorageOrder::get); } /* @@ -152,5 +152,4 @@ public void setCitationMarker(Optional citationMarker) { public Optional getCitationMarker() { return this.citationMarker; } - } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java index baaa931214c..6c271b12267 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroupId.java @@ -5,6 +5,7 @@ */ public class CitationGroupId { String groupId; + public CitationGroupId(String groupId) { this.groupId = groupId; } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java index e5e642fa652..226867ad274 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java @@ -19,15 +19,14 @@ /** * CitationGroups : the set of citation groups in the document. - * + *

    * This is the main input (as well as output) for creating citation markers and bibliography. - * */ public class CitationGroups { private static final Logger LOGGER = LoggerFactory.getLogger(CitationGroups.class); - private Map citationGroupsUnordered; + private final Map citationGroupsUnordered; /** * Provides order of appearance for the citation groups. @@ -35,7 +34,7 @@ public class CitationGroups { private Optional> globalOrder; /** - * This is going to be the bibliography + * This is going to be the bibliography */ private Optional bibliography; @@ -114,13 +113,12 @@ public List getCitationGroupsInGlobalOrder() { if (globalOrder.isEmpty()) { throw new IllegalStateException("getCitationGroupsInGlobalOrder: not ordered yet"); } - return OOListUtil.map(globalOrder.get(), groupId -> citationGroupsUnordered.get(groupId)); + return OOListUtil.map(globalOrder.get(), citationGroupsUnordered::get); } /** - * Impose an order of citation groups by providing the order of their citation group - * idendifiers. - * + * Impose an order of citation groups by providing the order of their citation group idendifiers. + *

    * Also set indexInGlobalOrder for each citation group. */ public void setGlobalOrder(List globalOrder) { @@ -151,8 +149,7 @@ public void imposeLocalOrder(Comparator entryComparator) { } /** - * Collect citations into a list of cited sources using neither CitationGroup.globalOrder or - * Citation.localOrder + * Collect citations into a list of cited sources using neither CitationGroup.globalOrder or Citation.localOrder */ public CitedKeys getCitedKeysUnordered() { LinkedHashMap res = new LinkedHashMap<>(); @@ -216,9 +213,9 @@ public List getUnresolvedKeys() { } public void createNumberedBibliographySortedInOrderOfAppearance() { - if (!bibliography.isEmpty()) { + if (bibliography.isPresent()) { throw new IllegalStateException("createNumberedBibliographySortedInOrderOfAppearance:" - + " already have a bibliography"); + + " already have a bibliography"); } CitedKeys citedKeys = getCitedKeysSortedInOrderOfAppearance(); citedKeys.numberCitedKeysInCurrentOrder(); @@ -230,7 +227,7 @@ public void createNumberedBibliographySortedInOrderOfAppearance() { * precondition: database lookup already performed (otherwise we just sort citation keys) */ public void createPlainBibliographySortedByComparator(Comparator entryComparator) { - if (!bibliography.isEmpty()) { + if (bibliography.isPresent()) { throw new IllegalStateException("createPlainBibliographySortedByComparator: already have a bibliography"); } CitedKeys citedKeys = getCitedKeysUnordered(); @@ -242,7 +239,7 @@ public void createPlainBibliographySortedByComparator(Comparator entry * precondition: database lookup already performed (otherwise we just sort citation keys) */ public void createNumberedBibliographySortedByComparator(Comparator entryComparator) { - if (!bibliography.isEmpty()) { + if (bibliography.isPresent()) { throw new IllegalStateException("createNumberedBibliographySortedByComparator: already have a bibliography"); } CitedKeys citedKeys = getCitedKeysUnordered(); @@ -290,5 +287,4 @@ public void afterRemoveCitationGroup(CitationGroup group) { bibliography = Optional.empty(); } - } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java b/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java index bfe6dc1debe..c82177a7e69 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationLookupResult.java @@ -19,16 +19,12 @@ public CitationLookupResult(BibEntry entry, BibDatabase database) { /** * Note: BibEntry overrides Object.equals, but BibDatabase does not. - * - * Consequently, {@code this.database.equals(that.database)} below - * is equivalent to {@code this.database == that.database}. - * - * Since within each GUI call we use a fixed list of databases, it is OK. - * - * CitationLookupResult.equals is used in CitedKey.addPath to check the added Citation - * refers to the same source as the others. As long as we look up each citation key - * only once (in CitationGroups.lookupCitations), the default implementation for equals - * would be sufficient (and could also omit hashCode below). + *

    + * Consequently, {@code this.database.equals(that.database)} below is equivalent to {@code this.database == that.database}. + *

    + * Since within each GUI call we use a fixed list of databases, it is OK. + *

    + * CitationLookupResult.equals is used in CitedKey.addPath to check the added Citation refers to the same source as the others. As long as we look up each citation key only once (in CitationGroups.lookupCitations), the default implementation for equals would be sufficient (and could also omit hashCode below). */ @Override public boolean equals(Object otherObject) { diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationMarkerEntry.java b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerEntry.java index 5fcb9bcc1a8..18bbe5588b3 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationMarkerEntry.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerEntry.java @@ -15,14 +15,12 @@ public interface CitationMarkerEntry extends CitationMarkerNormEntry { Optional getUniqueLetter(); /** - * pageInfo for this citation, provided by the user. - * May be empty, for none. + * pageInfo for this citation, provided by the user. May be empty, for none. */ Optional getPageInfo(); /** - * @return true if this citation is the first appearance of the source cited. Some styles use - * different limit on the number of authors shown in this case. + * @return true if this citation is the first appearance of the source cited. Some styles use different limit on the number of authors shown in this case. */ boolean getIsFirstAppearanceOfSource(); } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNormEntry.java b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNormEntry.java index a2581b38b60..1489dede932 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNormEntry.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationMarkerNormEntry.java @@ -7,14 +7,16 @@ */ public interface CitationMarkerNormEntry { - /** Citation key. This is what we usually get from the document. - * - * Used if getLookupResult() returns empty, which indicates failure to lookup in the databases. + /** + * Citation key. This is what we usually get from the document. + *

    + * Used if getLookupResult() returns empty, which indicates failure to lookup in the databases. */ String getCitationKey(); - /** Result of looking up citation key in databases. - * + /** + * Result of looking up citation key in databases. + *

    * Optional.empty() indicates unresolved citation. */ Optional getLookupResult(); diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationPath.java b/src/main/java/org/jabref/model/openoffice/style/CitationPath.java index 0920ea20feb..ba562ebe6bf 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationPath.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationPath.java @@ -1,8 +1,7 @@ package org.jabref.model.openoffice.style; /** - * Identifies a citation with the identifier of the citation group containing it and its storage - * index within. + * Identifies a citation with the identifier of the citation group containing it and its storage index within. */ public class CitationPath { diff --git a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java index 5331204bd75..8e5950d9d04 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java @@ -10,14 +10,13 @@ /** * Cited keys are collected from the citations in citation groups. - * - * They contain backreferences to the corresponding citations in {@code where}. This allows the - * extra information generated using CitedKeys to be distributed back to the in-text citations. + *

    + * They contain backreferences to the corresponding citations in {@code where}. This allows the extra information generated using CitedKeys to be distributed back to the in-text citations. */ public class CitedKey implements - ComparableCitedKey, - CitationMarkerNormEntry, - CitationMarkerNumericBibEntry { + ComparableCitedKey, + CitationMarkerNormEntry, + CitationMarkerNumericBibEntry { public final String citationKey; private final List where; @@ -27,16 +26,16 @@ public class CitedKey implements private Optional uniqueLetter; // For AuthorYear citation styles. private Optional normCitMarker; // For AuthorYear citation styles. - CitedKey(String citationKey, CitationPath path, Citation cit) { + CitedKey(String citationKey, CitationPath path, Citation citation) { this.citationKey = citationKey; this.where = new ArrayList<>(); // remember order this.where.add(path); // synchronized with Citation - this.db = cit.getLookupResult(); - this.number = cit.getNumber(); - this.uniqueLetter = cit.getUniqueLetter(); + this.db = citation.getLookupResult(); + this.number = citation.getNumber(); + this.uniqueLetter = citation.getUniqueLetter(); // CitedKey only this.normCitMarker = Optional.empty(); diff --git a/src/main/java/org/jabref/model/openoffice/style/ComparableCitation.java b/src/main/java/org/jabref/model/openoffice/style/ComparableCitation.java index 81120c09b2a..42a7e5869ba 100644 --- a/src/main/java/org/jabref/model/openoffice/style/ComparableCitation.java +++ b/src/main/java/org/jabref/model/openoffice/style/ComparableCitation.java @@ -5,8 +5,7 @@ import org.jabref.model.openoffice.ootext.OOText; /** - * When sorting citations (in a group), we also consider pageInfo. - * Otherwise we sort citations as cited keys. + * When sorting citations (in a group), we also consider pageInfo. Otherwise we sort citations as cited keys. */ public interface ComparableCitation extends ComparableCitedKey { Optional getPageInfo(); diff --git a/src/main/java/org/jabref/model/openoffice/style/NonUniqueCitationMarker.java b/src/main/java/org/jabref/model/openoffice/style/NonUniqueCitationMarker.java index 34300734d2f..e633f7a9c70 100644 --- a/src/main/java/org/jabref/model/openoffice/style/NonUniqueCitationMarker.java +++ b/src/main/java/org/jabref/model/openoffice/style/NonUniqueCitationMarker.java @@ -1,15 +1,18 @@ package org.jabref.model.openoffice.style; /** - * What should createCitationMarker do if it discovers that uniqueLetters provided are not - * sufficient for unique presentation? + * What should createCitationMarker do if it discovers that uniqueLetters provided are not sufficient for unique presentation? */ public enum NonUniqueCitationMarker { - /** Give an insufficient representation anyway. */ + /** + * Give an insufficient representation anyway. + */ FORGIVEN, - /** Throw an exception */ + /** + * Throw an exception + */ THROWS } diff --git a/src/main/java/org/jabref/model/openoffice/style/OODataModel.java b/src/main/java/org/jabref/model/openoffice/style/OODataModel.java index 835715dfca5..470edc1694d 100644 --- a/src/main/java/org/jabref/model/openoffice/style/OODataModel.java +++ b/src/main/java/org/jabref/model/openoffice/style/OODataModel.java @@ -6,13 +6,19 @@ import org.jabref.model.openoffice.ootext.OOText; -/** What is the data stored? */ +/** + * What is the data stored? + */ public enum OODataModel { - /** JabRef52: pageInfo belongs to CitationGroup, not Citation. */ + /** + * JabRef52: pageInfo belongs to CitationGroup, not Citation. + */ JabRef52, - /** JabRef60: pageInfo belongs to Citation. */ + /** + * JabRef60: pageInfo belongs to Citation. + */ JabRef60; /** diff --git a/src/main/java/org/jabref/model/openoffice/style/PageInfo.java b/src/main/java/org/jabref/model/openoffice/style/PageInfo.java index 1ff87569a3b..c92ad335b49 100644 --- a/src/main/java/org/jabref/model/openoffice/style/PageInfo.java +++ b/src/main/java/org/jabref/model/openoffice/style/PageInfo.java @@ -7,7 +7,6 @@ public class PageInfo { private PageInfo() { - // hide public constructor } /* @@ -27,7 +26,7 @@ public static Optional normalizePageInfo(Optional optionalText) /** * Defines sort order for pageInfo strings. - * + *

    * Optional.empty comes before non-empty. */ public static int comparePageInfo(Optional a, Optional b) { diff --git a/src/main/java/org/jabref/model/openoffice/uno/CreationException.java b/src/main/java/org/jabref/model/openoffice/uno/CreationException.java index 091d5469e2d..84e3c8afe55 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/CreationException.java +++ b/src/main/java/org/jabref/model/openoffice/uno/CreationException.java @@ -2,14 +2,12 @@ /** * Exception used to indicate failure in either - * - * XMultiServiceFactory.createInstance() - * XMultiComponentFactory.createInstanceWithContext() + *

    + * XMultiServiceFactory.createInstance() XMultiComponentFactory.createInstanceWithContext() */ public class CreationException extends Exception { public CreationException(String message) { super(message); } - } 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 fdbbb0dd1c6..f187527aeab 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoBookmark.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoBookmark.java @@ -14,14 +14,15 @@ public class UnoBookmark { - private UnoBookmark() { } + private UnoBookmark() { + } /** * Provides access to bookmarks by name. */ public static XNameAccess getNameAccess(XTextDocument doc) - throws - NoDocumentException { + throws + NoDocumentException { XBookmarksSupplier supplier = UnoCast.cast(XBookmarksSupplier.class, doc).get(); try { @@ -38,32 +39,28 @@ public static XNameAccess getNameAccess(XTextDocument doc) * @return The XTextRange for the bookmark, or Optional.empty(). */ public static Optional getAnchor(XTextDocument doc, String name) - throws - WrappedTargetException, - NoDocumentException { + throws + WrappedTargetException, + NoDocumentException { XNameAccess nameAccess = getNameAccess(doc); return (UnoNameAccess.getTextContentByName(nameAccess, name).map(XTextContent::getAnchor)); } /** - * Insert a bookmark with the given name at the cursor provided, or with another name if the one - * we asked for is already in use. - * + * Insert a bookmark with the given name at the cursor provided, or with another name if the one we asked for is already in use. + *

    * 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? - * + * @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. + * 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) - throws - CreationException { + throws + CreationException { return UnoNamed.insertNamedTextContent(doc, "com.sun.star.text.Bookmark", name, range, absorb); } @@ -71,9 +68,9 @@ public static XNamed create(XTextDocument doc, String name, XTextRange range, bo * Remove the named bookmark if it exists. */ public static void removeIfExists(XTextDocument doc, String name) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { XNameAccess marks = UnoBookmark.getNameAccess(doc); diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoCast.java b/src/main/java/org/jabref/model/openoffice/uno/UnoCast.java index fcc1bcc3e12..3234e4d130a 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoCast.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoCast.java @@ -6,7 +6,8 @@ public class UnoCast { - private UnoCast() { } + private UnoCast() { + } /** * cast : short for Optional.ofNullable(UnoRuntime.queryInterface(...)) diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoCrossRef.java b/src/main/java/org/jabref/model/openoffice/uno/UnoCrossRef.java index f5d20a1de4f..7df6d7dc04c 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoCrossRef.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoCrossRef.java @@ -14,7 +14,8 @@ public class UnoCrossRef { - private UnoCrossRef() { } + private UnoCrossRef() { + } /** * Update TextFields, etc. We use it to refresh cross-references in the document. @@ -26,17 +27,16 @@ public static void refresh(XTextDocument doc) { } /** - * Insert a clickable cross-reference to a reference mark, with a label containing the target's - * page number. - * + * Insert a clickable cross-reference to a reference mark, with a label containing the target's page number. + *

    * May need a documentConnection.refresh() after, to update the text shown. */ public static void insertReferenceToPageNumberOfReferenceMark(XTextDocument doc, String referenceMarkName, XTextRange cursor) - throws - CreationException, - WrappedTargetException { + throws + CreationException, + WrappedTargetException { // based on: https://wiki.openoffice.org/wiki/Documentation/DevGuide/Text/Reference_Marks XMultiServiceFactory msf = UnoCast.cast(XMultiServiceFactory.class, doc).get(); @@ -62,20 +62,20 @@ public static void insertReferenceToPageNumberOfReferenceMark(XTextDocument doc, try { // specify that the source is a reference mark (could also be a footnote, // bookmark or sequence field) - xFieldProps.setPropertyValue("ReferenceFieldSource", Short.valueOf(ReferenceFieldSource.REFERENCE_MARK)); + xFieldProps.setPropertyValue("ReferenceFieldSource", ReferenceFieldSource.REFERENCE_MARK); } catch (UnknownPropertyException ex) { throw new java.lang.IllegalStateException("The created GetReference does not have property" - + " 'ReferenceFieldSource'"); + + " 'ReferenceFieldSource'"); } catch (PropertyVetoException ex) { throw new java.lang.IllegalStateException("Caught PropertyVetoException on 'ReferenceFieldSource'"); } try { // We want the reference displayed as page number - xFieldProps.setPropertyValue("ReferenceFieldPart", Short.valueOf(ReferenceFieldPart.PAGE)); + xFieldProps.setPropertyValue("ReferenceFieldPart", ReferenceFieldPart.PAGE); } catch (UnknownPropertyException ex) { throw new java.lang.IllegalStateException("The created GetReference does not have property" - + " 'ReferenceFieldPart'"); + + " 'ReferenceFieldPart'"); } catch (PropertyVetoException ex) { throw new java.lang.IllegalStateException("Caught PropertyVetoException on 'ReferenceFieldPart'"); } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java b/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java index e761a56e12f..da29ee84d92 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoCursor.java @@ -11,22 +11,22 @@ public class UnoCursor { - private UnoCursor() { } + private UnoCursor() { + } /** * Get the cursor positioned by the user. */ public static Optional getViewCursor(XTextDocument doc) { return (UnoTextDocument.getCurrentController(doc) - .flatMap(e -> UnoCast.cast(XTextViewCursorSupplier.class, e)) - .map(XTextViewCursorSupplier::getViewCursor)); + .flatMap(e -> UnoCast.cast(XTextViewCursorSupplier.class, e)) + .map(XTextViewCursorSupplier::getViewCursor)); } /** * Create a text cursor for a textContent. * * @return Optional.empty if mark is null, otherwise cursor. - * */ public static Optional getTextCursorOfTextContentAnchor(XTextContent mark) { if (mark == null) { diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoNameAccess.java b/src/main/java/org/jabref/model/openoffice/uno/UnoNameAccess.java index 243c136f382..1250d56d923 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoNameAccess.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoNameAccess.java @@ -9,14 +9,15 @@ public class UnoNameAccess { - private UnoNameAccess() { } + private UnoNameAccess() { + } /** * @return null if name not found, or if the result does not support the XTextContent interface. */ public static Optional getTextContentByName(XNameAccess nameAccess, String name) - throws - WrappedTargetException { + throws + WrappedTargetException { try { return UnoCast.cast(XTextContent.class, nameAccess.getByName(name)); } catch (NoSuchElementException ex) { 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 5f1f50c873d..b9f43e56f80 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoNamed.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoNamed.java @@ -8,38 +8,27 @@ public class UnoNamed { - private UnoNamed() { } + private UnoNamed() { + } /** * Insert a new instance of a service at the provided cursor position. * - * @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 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. - * + * @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) - throws - CreationException { + throws + CreationException { XMultiServiceFactory msf = UnoCast.cast(XMultiServiceFactory.class, doc).get(); @@ -51,14 +40,13 @@ static XNamed insertNamedTextContent(XTextDocument doc, } XNamed xNamed = (UnoCast.cast(XNamed.class, xObject) - .orElseThrow(() -> new IllegalArgumentException("Service is not an XNamed"))); + .orElseThrow(() -> new IllegalArgumentException("Service is not an XNamed"))); xNamed.setName(name); // get XTextContent interface XTextContent xTextContent = (UnoCast.cast(XTextContent.class, xObject) - .orElseThrow(() -> new IllegalArgumentException("Service is not an XTextContent"))); + .orElseThrow(() -> new IllegalArgumentException("Service is not an XTextContent"))); range.getText().insertTextContent(range, xTextContent, absorb); return xNamed; } - } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java b/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java index 3a47818cf8b..74ea8aaa812 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java @@ -15,11 +15,12 @@ import com.sun.star.lang.WrappedTargetException; /** - * Utilities for properties. + * Utilities for properties. */ public class UnoProperties { - private UnoProperties() { } + private UnoProperties() { + } /* * asPropertySet @@ -35,7 +36,7 @@ public static Optional asPropertySet(XPropertyContainer propertyCo public static Optional getPropertySetInfo(XPropertySet propertySet) { return (Optional.ofNullable(propertySet) - .flatMap(e -> Optional.ofNullable(e.getPropertySetInfo()))); + .flatMap(e -> Optional.ofNullable(e.getPropertySetInfo()))); } public static Optional getPropertySetInfo(XPropertyContainer propertyContainer) { @@ -49,8 +50,8 @@ public static Optional getPropertySetInfo(XPropertyContainer p public static List getPropertyNames(Property[] properties) { Objects.requireNonNull(properties); return (Arrays.stream(properties) - .map(p -> p.Name) - .collect(Collectors.toList())); + .map(p -> p.Name) + .collect(Collectors.toList())); } public static List getPropertyNames(XPropertySetInfo propertySetInfo) { @@ -72,8 +73,8 @@ public static List getPropertyNames(XPropertyContainer propertyContainer */ public static Optional getValueAsObject(XPropertySet propertySet, String property) - throws - WrappedTargetException { + throws + WrappedTargetException { Objects.requireNonNull(propertySet); Objects.requireNonNull(property); try { @@ -84,8 +85,8 @@ public static Optional getValueAsObject(XPropertySet propertySet, String } public static Optional getValueAsObject(XPropertyContainer propertyContainer, String property) - throws - WrappedTargetException { + throws + WrappedTargetException { Optional propertySet = asPropertySet(propertyContainer); if (propertySet.isEmpty()) { return Optional.empty(); diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoRedlines.java b/src/main/java/org/jabref/model/openoffice/uno/UnoRedlines.java index 2c408648d6f..3793ce7a079 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoRedlines.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoRedlines.java @@ -12,13 +12,13 @@ import com.sun.star.text.XTextDocument; /** - * Change tracking and Redlines + * Change tracking and Redlines */ public class UnoRedlines { public static boolean getRecordChanges(XTextDocument doc) - throws - WrappedTargetException { + throws + WrappedTargetException { // https://wiki.openoffice.org/wiki/Documentation/DevGuide/Text/Settings // "Properties of com.sun.star.text.TextDocument" 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 7a719042d79..062564b8156 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoReferenceMark.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoReferenceMark.java @@ -17,17 +17,17 @@ public class UnoReferenceMark { - private UnoReferenceMark() { } + private UnoReferenceMark() { + } /** * @throws NoDocumentException If cannot get reference marks - * - * Note: also used by `isDocumentConnectionMissing` to test if we have a working connection. - * + *

    + * Note: also used by `isDocumentConnectionMissing` to test if we have a working connection. */ public static XNameAccess getNameAccess(XTextDocument doc) - throws - NoDocumentException { + throws + NoDocumentException { XReferenceMarksSupplier supplier = UnoCast.cast(XReferenceMarksSupplier.class, doc).get(); @@ -40,11 +40,11 @@ public static XNameAccess getNameAccess(XTextDocument doc) /** * Names of all reference marks. - * + *

    * Empty list for nothing. */ public static List getListOfNames(XTextDocument doc) - throws NoDocumentException { + throws NoDocumentException { XNameAccess nameAccess = UnoReferenceMark.getNameAccess(doc); String[] names = nameAccess.getElementNames(); @@ -56,13 +56,13 @@ public static List getListOfNames(XTextDocument doc) /** * Remove the named reference mark. - * + *

    * Removes both the text and the mark itself. */ public static void removeIfExists(XTextDocument doc, String name) - throws - WrappedTargetException, - NoDocumentException { + throws + WrappedTargetException, + NoDocumentException { XNameAccess xReferenceMarks = UnoReferenceMark.getNameAccess(doc); @@ -80,46 +80,41 @@ public static void removeIfExists(XTextDocument doc, String name) } /** - * @return reference mark as XTextContent, Optional.empty if not found. + * @return reference mark as XTextContent, Optional.empty if not found. */ public static Optional getAsTextContent(XTextDocument doc, String name) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { XNameAccess nameAccess = UnoReferenceMark.getNameAccess(doc); return UnoNameAccess.getTextContentByName(nameAccess, name); } /** - * XTextRange for the named reference mark, Optional.empty if not found. + * XTextRange for the named reference mark, Optional.empty if not found. */ public static Optional getAnchor(XTextDocument doc, String name) - throws - NoDocumentException, - WrappedTargetException { + throws + NoDocumentException, + WrappedTargetException { return (UnoReferenceMark.getAsTextContent(doc, name) - .map(XTextContent::getAnchor)); + .map(XTextContent::getAnchor)); } /** * 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. + *

    + * 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. * - * If {@code absorb} 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 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) - throws - CreationException { + throws + CreationException { return UnoNamed.insertNamedTextContent(doc, "com.sun.star.text.ReferenceMark", name, range, absorb); } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoScreenRefresh.java b/src/main/java/org/jabref/model/openoffice/uno/UnoScreenRefresh.java index e5c27fcbb5c..6de0afe5ad6 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoScreenRefresh.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoScreenRefresh.java @@ -7,17 +7,17 @@ */ public class UnoScreenRefresh { - private UnoScreenRefresh() { } + private UnoScreenRefresh() { + } /** * Disable screen refresh. - * + *

    * Must be paired with unlockControllers() - * + *

    * https://www.openoffice.org/api/docs/common/ref/com/sun/star/frame/XModel.html - * - * While there is at least one lock remaining, some - * notifications for display updates are not broadcasted. + *

    + * While there is at least one lock remaining, some notifications for display updates are not broadcasted. */ public static void lockControllers(XTextDocument doc) { doc.lockControllers(); diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoSelection.java b/src/main/java/org/jabref/model/openoffice/uno/UnoSelection.java index 43d89ed157b..a6e581cfce1 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoSelection.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoSelection.java @@ -17,7 +17,8 @@ public class UnoSelection { private static final Logger LOGGER = LoggerFactory.getLogger(UnoSelection.class); - private UnoSelection() { } + private UnoSelection() { + } private static Optional getSelectionSupplier(XTextDocument doc) { if (doc == null) { @@ -39,46 +40,21 @@ private static Optional getSelectionSupplier(XTextDocument d /** * @return may be Optional.empty(), or some type supporting XServiceInfo - * - * - * So far it seems the first thing we have to do - * with a selection is to decide what do we have. - * + * So far it seems the first thing we have to do with a selection is to decide what do we have. + *

    * One way to do that is accessing its XServiceInfo interface. - * - * Experiments using printServiceInfo with cursor in various - * positions in the document: - * - * With cursor within the frame, in text: - * *** xserviceinfo.getImplementationName: "SwXTextRanges" - * "com.sun.star.text.TextRanges" - * - * With cursor somewhere else in text: - * *** xserviceinfo.getImplementationName: "SwXTextRanges" - * "com.sun.star.text.TextRanges" - * - * With cursor in comment (also known as "annotation"): - * *** XSelectionSupplier is OK - * *** Object initialSelection is null - * *** xserviceinfo is null - * - * With frame selected: - * *** xserviceinfo.getImplementationName: "SwXTextFrame" - * "com.sun.star.text.BaseFrame" - * "com.sun.star.text.TextContent" - * "com.sun.star.document.LinkTarget" - * "com.sun.star.text.TextFrame" - * "com.sun.star.text.Text" - * - * With cursor selecting an inserted image: - * *** XSelectionSupplier is OK - * *** Object initialSelection is OK - * *** xserviceinfo is OK - * *** xserviceinfo.getImplementationName: "SwXTextGraphicObject" - * "com.sun.star.text.BaseFrame" - * "com.sun.star.text.TextContent" - * "com.sun.star.document.LinkTarget" - * "com.sun.star.text.TextGraphicObject" + *

    + * Experiments using printServiceInfo with cursor in various positions in the document: + *

    + * With cursor within the frame, in text: *** xserviceinfo.getImplementationName: "SwXTextRanges" "com.sun.star.text.TextRanges" + *

    + * With cursor somewhere else in text: *** xserviceinfo.getImplementationName: "SwXTextRanges" "com.sun.star.text.TextRanges" + *

    + * With cursor in comment (also known as "annotation"): *** XSelectionSupplier is OK *** Object initialSelection is null *** xserviceinfo is null + *

    + * With frame selected: *** xserviceinfo.getImplementationName: "SwXTextFrame" "com.sun.star.text.BaseFrame" "com.sun.star.text.TextContent" "com.sun.star.document.LinkTarget" "com.sun.star.text.TextFrame" "com.sun.star.text.Text" + *

    + * With cursor selecting an inserted image: *** XSelectionSupplier is OK *** Object initialSelection is OK *** xserviceinfo is OK *** xserviceinfo.getImplementationName: "SwXTextGraphicObject" "com.sun.star.text.BaseFrame" "com.sun.star.text.TextContent" "com.sun.star.document.LinkTarget" "com.sun.star.text.TextGraphicObject" */ public static Optional getSelectionAsXServiceInfo(XTextDocument doc) { Objects.requireNonNull(doc); @@ -100,13 +76,9 @@ public static Optional getSelectionAsXServiceInfo(XTextDocument do } /** - * Select the object represented by {@code newSelection} if it is - * known and selectable in this {@code XSelectionSupplier} object. - * - * Presumably result from {@code XSelectionSupplier.getSelection()} is - * usually OK. It also accepted - * {@code XTextRange newSelection = doc.getText().getStart();} - * + * Select the object represented by {@code newSelection} if it is known and selectable in this {@code XSelectionSupplier} object. + *

    + * Presumably result from {@code XSelectionSupplier.getSelection()} is usually OK. It also accepted {@code XTextRange newSelection = doc.getText().getStart();} */ public static void select(XTextDocument doc, Object newSelection) { Objects.requireNonNull(doc); diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java b/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java index cd4065ba8b3..aa659919fab 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoStyle.java @@ -18,11 +18,12 @@ public class UnoStyle { public static final String CHARACTER_STYLES = "CharacterStyles"; public static final String PARAGRAPH_STYLES = "ParagraphStyles"; - private UnoStyle() { } + private UnoStyle() { + } private static Optional getStyleFromFamily(XTextDocument doc, String familyName, String styleName) - throws - WrappedTargetException { + throws + WrappedTargetException { XStyleFamiliesSupplier fss = UnoCast.cast(XStyleFamiliesSupplier.class, doc).get(); XNameAccess families = UnoCast.cast(XNameAccess.class, fss.getStyleFamilies()).get(); @@ -43,34 +44,34 @@ private static Optional getStyleFromFamily(XTextDocument doc, String fam } public static Optional getParagraphStyle(XTextDocument doc, String styleName) - throws - WrappedTargetException { + throws + WrappedTargetException { return getStyleFromFamily(doc, PARAGRAPH_STYLES, styleName); } public static Optional getCharacterStyle(XTextDocument doc, String styleName) - throws - WrappedTargetException { + throws + WrappedTargetException { return getStyleFromFamily(doc, CHARACTER_STYLES, styleName); } public static Optional getInternalNameOfStyle(XTextDocument doc, String familyName, String name) - throws - WrappedTargetException { + throws + WrappedTargetException { return (getStyleFromFamily(doc, familyName, name) .map(XStyle::getName)); } public static Optional getInternalNameOfParagraphStyle(XTextDocument doc, String name) - throws - WrappedTargetException { + throws + WrappedTargetException { return getInternalNameOfStyle(doc, PARAGRAPH_STYLES, name); } public static Optional getInternalNameOfCharacterStyle(XTextDocument doc, String name) - throws - WrappedTargetException { + throws + WrappedTargetException { return getInternalNameOfStyle(doc, CHARACTER_STYLES, name); } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoTextDocument.java b/src/main/java/org/jabref/model/openoffice/uno/UnoTextDocument.java index c7e94e6bb4c..3f154a4ae9c 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoTextDocument.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoTextDocument.java @@ -7,6 +7,7 @@ import com.sun.star.document.XDocumentPropertiesSupplier; import com.sun.star.frame.XController; import com.sun.star.frame.XFrame; +import com.sun.star.lang.DisposedException; import com.sun.star.lang.WrappedTargetException; import com.sun.star.text.XTextDocument; import org.slf4j.Logger; @@ -16,25 +17,21 @@ public class UnoTextDocument { private static final Logger LOGGER = LoggerFactory.getLogger(UnoTextDocument.class); - private UnoTextDocument() { } + private UnoTextDocument() { + } /** - * @return True if we cannot reach the current document. + * @return True if we cannot reach the current document. */ public static boolean isDocumentConnectionMissing(XTextDocument doc) { - boolean missing = false; - if (doc == null) { - missing = true; - } + boolean missing = doc == null; // Attempt to check document is really available if (!missing) { try { UnoReferenceMark.getNameAccess(doc); - } catch (NoDocumentException ex) { - missing = true; - } catch (com.sun.star.lang.DisposedException ex) { + } catch (NoDocumentException | DisposedException ex) { missing = true; } } @@ -54,8 +51,8 @@ public static Optional getCurrentController(XTextDocument doc) { } /** - * @param doc The XTextDocument we want the frame title for. Null allowed. - * @return The title or Optional.empty() + * @param doc The XTextDocument we want the frame title for. Null allowed. + * @return The title or Optional.empty() */ public static Optional getFrameTitle(XTextDocument doc) { @@ -84,8 +81,8 @@ public static Optional getFrameTitle(XTextDocument doc) { static Optional getDocumentProperties(XTextDocument doc) { return (Optional.ofNullable(doc) - .flatMap(e -> UnoCast.cast(XDocumentPropertiesSupplier.class, e)) - .map(XDocumentPropertiesSupplier::getDocumentProperties)); + .flatMap(e -> UnoCast.cast(XDocumentPropertiesSupplier.class, e)) + .map(XDocumentPropertiesSupplier::getDocumentProperties)); } } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java b/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java index 56cb1498e2a..520878833e5 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoTextRange.java @@ -3,33 +3,30 @@ import java.util.Optional; import com.sun.star.text.XFootnote; +import com.sun.star.text.XTextContent; import com.sun.star.text.XTextRange; import com.sun.star.text.XTextRangeCompare; public class UnoTextRange { - private UnoTextRange() { } + private UnoTextRange() { + } /** - * If original is in a footnote, return a range containing - * the corresponding footnote marker. - * - * Returns Optional.empty if not in a footnote. + * If original is in a footnote, return a range containing the corresponding footnote marker. + *

    + * Returns Optional.empty if not in a footnote. */ public static Optional getFootnoteMarkRange(XTextRange original) { Optional footer = UnoCast.cast(XFootnote.class, original.getText()); - if (footer.isPresent()) { - // If we are inside a footnote, - // find the linking footnote marker: - // The footnote's anchor gives the correct position in the text: - return Optional.ofNullable(footer.get().getAnchor()); - } - return Optional.empty(); + // If we are inside a footnote, + // find the linking footnote marker: + // The footnote's anchor gives the correct position in the text: + return footer.map(XTextContent::getAnchor); } /** - * Test if two XTextRange values are comparable (i.e. they share - * the same getText()). + * Test if two XTextRange values are comparable (i.e. they share the same getText()). */ public static boolean comparables(XTextRange a, XTextRange b) { return a.getText() == b.getText(); @@ -37,7 +34,6 @@ public static boolean comparables(XTextRange a, XTextRange b) { /** * @return follows java conventions - * * 1 if (a > b); (-1) if (a < b) */ public static int compareStartsUnsafe(XTextRangeCompare compare, XTextRange a, XTextRange b) { @@ -54,7 +50,6 @@ public static int compareStarts(XTextRange a, XTextRange b) { /** * @return follows java conventions - * * 1 if (a > b); (-1) if (a < b) */ public static int compareEnds(XTextRange a, XTextRange b) { 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 3b9797f553e..56293eee947 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoTextSection.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoTextSection.java @@ -17,11 +17,11 @@ public class UnoTextSection { /** - * @return An XNameAccess to find sections by name. + * @return An XNameAccess to find sections by name. */ public static XNameAccess getNameAccess(XTextDocument doc) - throws - NoDocumentException { + throws + NoDocumentException { XTextSectionsSupplier supplier = UnoCast.cast(XTextSectionsSupplier.class, doc).get(); try { @@ -32,12 +32,12 @@ public static XNameAccess getNameAccess(XTextDocument doc) } /** - * Get an XTextSection by name. + * Get an XTextSection by name. */ public static Optional getByName(XTextDocument doc, String name) - throws - WrappedTargetException, - NoDocumentException { + throws + WrappedTargetException, + NoDocumentException { XNameAccess nameAccess = getNameAccess(doc); try { return Optional.ofNullable((XTextSection) ((Any) nameAccess.getByName(name)).getObject()); @@ -53,26 +53,25 @@ public static Optional getByName(XTextDocument doc, String name) * @return The XTextRange for the section, or Optional.empty(). */ public static Optional getAnchor(XTextDocument doc, String name) - throws - WrappedTargetException, - NoDocumentException { + throws + WrappedTargetException, + NoDocumentException { XNameAccess nameAccess = getNameAccess(doc); return (UnoNameAccess.getTextContentByName(nameAccess, name).map(XTextContent::getAnchor)); } /** - * Create a text section with the provided name and insert it at the provided cursor. + * 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. + * @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. */ public static XNamed create(XTextDocument doc, String name, XTextRange range, boolean absorb) - throws - CreationException { + throws + CreationException { return UnoNamed.insertNamedTextContent(doc, "com.sun.star.text.TextSection", name, range, absorb); } diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java b/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java index 4f08bb0ed5c..bd1f85e1690 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoUndo.java @@ -12,23 +12,20 @@ */ public class UnoUndo { - private UnoUndo() { } + private UnoUndo() { + } public static Optional getXUndoManager(XTextDocument doc) { // https://www.openoffice.org/api/docs/common/ref/com/sun/star/document/XUndoManager.html return (UnoCast.cast(XUndoManagerSupplier.class, doc) - .map(XUndoManagerSupplier::getUndoManager)); + .map(XUndoManagerSupplier::getUndoManager)); } /** - * Each call to enterUndoContext must be paired by a call to leaveUndoContext, otherwise, the - * document's undo stack is left in an inconsistent state. + * Each call to enterUndoContext must be paired by a call to leaveUndoContext, otherwise, the document's undo stack is left in an inconsistent state. */ public static void enterUndoContext(XTextDocument doc, String title) { - Optional undoManager = getXUndoManager(doc); - if (undoManager.isPresent()) { - undoManager.get().enterUndoContext(title); - } + getXUndoManager(doc).ifPresent(undoManager -> undoManager.enterUndoContext(title)); } public static void leaveUndoContext(XTextDocument doc) { diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java b/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java index f5ec43f3211..85158db2d1c 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoUserDefinedProperty.java @@ -24,14 +24,15 @@ /** * Document level user-defined properties. - * - * LibreOffice GUI: [File]/[Properties]/[Custom Properties] + *

    + * LibreOffice GUI: [File]/[Properties]/[Custom Properties] */ public class UnoUserDefinedProperty { private static final Logger LOGGER = LoggerFactory.getLogger(UnoUserDefinedProperty.class); - private UnoUserDefinedProperty() { } + private UnoUserDefinedProperty() { + } public static Optional getPropertyContainer(XTextDocument doc) { return UnoTextDocument.getDocumentProperties(doc).map(XDocumentProperties::getUserDefinedProperties); @@ -39,24 +40,20 @@ public static Optional getPropertyContainer(XTextDocument do public static List getListOfNames(XTextDocument doc) { return (UnoUserDefinedProperty.getPropertyContainer(doc) - .map(UnoProperties::getPropertyNames) - .orElse(new ArrayList<>())); + .map(UnoProperties::getPropertyNames) + .orElse(new ArrayList<>())); } /** * @param property Name of a custom document property in the current document. - * * @return The value of the property or Optional.empty() - * - * These properties are used to store extra data about individual citation. - * In particular, the `pageInfo` part. - * + * These properties are used to store extra data about individual citation. In particular, the `pageInfo` part. */ public static Optional getStringValue(XTextDocument doc, String property) - throws - WrappedTargetException { + throws + WrappedTargetException { Optional propertySet = (UnoUserDefinedProperty.getPropertyContainer(doc) - .flatMap(UnoProperties::asPropertySet)); + .flatMap(UnoProperties::asPropertySet)); if (propertySet.isEmpty()) { throw new java.lang.IllegalArgumentException("getting UserDefinedProperties as XPropertySet failed"); } @@ -69,16 +66,14 @@ public static Optional getStringValue(XTextDocument doc, String property } /** - * @param property Name of a custom document property in the current document. - * Created if does not exist yet. - * - * @param value The value to be stored. + * @param property Name of a custom document property in the current document. Created if does not exist yet. + * @param value The value to be stored. */ public static void setStringProperty(XTextDocument doc, String property, String value) - throws - IllegalTypeException, - PropertyVetoException, - WrappedTargetException { + throws + IllegalTypeException, + PropertyVetoException, + WrappedTargetException { Objects.requireNonNull(property); Objects.requireNonNull(value); @@ -114,12 +109,12 @@ public static void setStringProperty(XTextDocument doc, String property, String /** * @param property Name of a custom document property in the current document. - * - * Logs warning if does not exist. + *

    + * Logs warning if does not exist. */ public static void remove(XTextDocument doc, String property) - throws - NotRemoveableException { + throws + NotRemoveableException { Objects.requireNonNull(property); @@ -133,18 +128,18 @@ public static void remove(XTextDocument doc, String property) container.get().removeProperty(property); } catch (UnknownPropertyException ex) { LOGGER.warn(String.format("UnoUserDefinedProperty.remove(%s) This property was not there to remove", - property)); + property)); } } /** * @param property Name of a custom document property in the current document. - * - * Keep silent if property did not exist. + *

    + * Keep silent if property did not exist. */ public static void removeIfExists(XTextDocument doc, String property) - throws - NotRemoveableException { + throws + NotRemoveableException { Objects.requireNonNull(property); diff --git a/src/main/java/org/jabref/model/openoffice/util/OOListUtil.java b/src/main/java/org/jabref/model/openoffice/util/OOListUtil.java index 59295c798fe..c61b81655a7 100644 --- a/src/main/java/org/jabref/model/openoffice/util/OOListUtil.java +++ b/src/main/java/org/jabref/model/openoffice/util/OOListUtil.java @@ -1,6 +1,5 @@ package org.jabref.model.openoffice.util; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.function.Function; @@ -10,22 +9,22 @@ public class OOListUtil { public static List map(List list, Function fun) { - return list.stream().map(e -> fun.apply(e)).collect(Collectors.toList()); + return list.stream().map(fun).collect(Collectors.toList()); } - /** Integers 0..(len-1) */ + /** + * Integers 0..(len-1) + */ public static List makeIndices(int len) { return Stream.iterate(0, i -> i + 1).limit(len).collect(Collectors.toList()); } - /** Return indices so that list.get(indices.get(i)) is sorted. */ + /** + * Return indices so that list.get(indices.get(i)) is sorted. + */ public static List order(List list, Comparator comparator) { List indices = makeIndices(list.size()); - Collections.sort(indices, new Comparator() { - @Override public int compare(final Integer a, final Integer b) { - return comparator.compare((U) list.get(a), (U) list.get(b)); - } - }); + indices.sort((a, b) -> comparator.compare(list.get(a), list.get(b))); return indices; } } diff --git a/src/main/java/org/jabref/model/openoffice/util/OOPair.java b/src/main/java/org/jabref/model/openoffice/util/OOPair.java index 9d1596d19ef..006c33e942e 100644 --- a/src/main/java/org/jabref/model/openoffice/util/OOPair.java +++ b/src/main/java/org/jabref/model/openoffice/util/OOPair.java @@ -3,6 +3,7 @@ public class OOPair { public final A a; public final B b; + public OOPair(A a, B b) { this.a = a; this.b = b; diff --git a/src/main/java/org/jabref/model/openoffice/util/OOResult.java b/src/main/java/org/jabref/model/openoffice/util/OOResult.java index c90bc68ad13..afbdeaf617e 100644 --- a/src/main/java/org/jabref/model/openoffice/util/OOResult.java +++ b/src/main/java/org/jabref/model/openoffice/util/OOResult.java @@ -91,12 +91,16 @@ public OOResult mapError(Function fun) { } } - /** Throw away the error part. */ + /** + * Throw away the error part. + */ public Optional getOptional() { return result; } - /** Throw away the result part. */ + /** + * Throw away the result part. + */ public OOVoidResult asVoidResult() { if (isError()) { return OOVoidResult.error(getError()); @@ -104,6 +108,5 @@ public OOVoidResult asVoidResult() { return OOVoidResult.ok(); } } - } diff --git a/src/main/java/org/jabref/model/openoffice/util/OOTuple3.java b/src/main/java/org/jabref/model/openoffice/util/OOTuple3.java index 8742e06764f..cff3079efa1 100644 --- a/src/main/java/org/jabref/model/openoffice/util/OOTuple3.java +++ b/src/main/java/org/jabref/model/openoffice/util/OOTuple3.java @@ -1,13 +1,11 @@ package org.jabref.model.openoffice.util; /** - * This class allows three objects to be packed together, and later accessed as fields `a`, `b` and - * `c`. - * + * This class allows three objects to be packed together, and later accessed as fields `a`, `b` and `c`. + *

    * Can be used to avoid creating a new class for just this purpose. - * + *

    * Can be useful if you do not have `Trifunction` at hand but need to pass three objects at a time. - * */ public class OOTuple3 { From efb0f1c243a2cd715df278abae57ca504df0ef57 Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Date: Wed, 23 Feb 2022 00:53:42 +0100 Subject: [PATCH 101/103] autoreformatted all oo tests, fixed l10n, applied small ide suggestions --- src/main/resources/l10n/JabRef_en.properties | 9 - .../openoffice/style/OOBibStyleTest.java | 298 +++++++++--------- .../style/OOBibStyleTestHelper.java | 230 +++++++------- .../openoffice/style/StyleLoaderTest.java | 8 +- .../model/openoffice/CitationEntryTest.java | 6 +- 5 files changed, 269 insertions(+), 282 deletions(-) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index b2e66d6ff25..2aba054b1ed 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -1087,7 +1087,6 @@ Connection\ lost=Connection lost Could\ not\ update\ bibliography=Could not update bibliography Not\ connected\ to\ document=Not connected to document Problem\ combining\ cite\ markers=Problem combining cite markers -Problem\ generating\ new\ database.=Problem generating new database. Unable\ to\ reload\ style\ file=Unable to reload style file Problem\ during\ separating\ cite\ markers=Problem during separating cite markers @@ -1193,7 +1192,6 @@ Toggle\ relevance=Toggle relevance Toggle\ quality\ assured=Toggle quality assured Toggle\ print\ status=Toggle print status Update\ keywords=Update keywords -Write\ values\ of\ special\ fields\ as\ separate\ fields\ to\ BibTeX=Write values of special fields as separate fields to BibTeX Problem\ connecting=Problem connecting Connection\ to\ OpenOffice/LibreOffice\ has\ been\ lost.\ Please\ make\ sure\ OpenOffice/LibreOffice\ is\ running,\ and\ try\ to\ reconnect.=Connection to OpenOffice/LibreOffice has been lost. Please make sure OpenOffice/LibreOffice is running, and try to reconnect. @@ -1209,10 +1207,7 @@ Removed\ all\ subgroups\ of\ group\ "%0".=Removed all subgroups of group "%0". To\ disable\ the\ memory\ stick\ mode\ rename\ or\ remove\ the\ jabref.xml\ file\ in\ the\ same\ folder\ as\ JabRef.=To disable the memory stick mode rename or remove the jabref.xml file in the same folder as JabRef. Unable\ to\ connect.\ One\ possible\ reason\ is\ that\ JabRef\ and\ OpenOffice/LibreOffice\ are\ not\ both\ running\ in\ either\ 32\ bit\ mode\ or\ 64\ bit\ mode.=Unable to connect. One possible reason is that JabRef and OpenOffice/LibreOffice are not both running in either 32 bit mode or 64 bit mode. Delimiter(s)=Delimiter(s) -When\ downloading\ files,\ or\ moving\ linked\ files\ to\ the\ file\ directory,\ prefer\ the\ BIB\ file\ location\ rather\ than\ the\ file\ directory\ set\ above=When downloading files, or moving linked files to the file directory, prefer the BIB file location rather than the file directory set above When\ downloading\ files,\ or\ moving\ linked\ files\ to\ the\ file\ directory,\ use\ the\ bib\ file\ location.=When downloading files, or moving linked files to the file directory, use the bib file location. -Your\ style\ file\ specifies\ the\ character\ format\ '%0',\ which\ is\ undefined\ in\ your\ current\ OpenOffice/LibreOffice\ document.=Your style file specifies the character format '%0', which is undefined in your current OpenOffice/LibreOffice document. -Your\ style\ file\ specifies\ the\ paragraph\ format\ '%0',\ which\ is\ undefined\ in\ your\ current\ OpenOffice/LibreOffice\ document.=Your style file specifies the paragraph format '%0', which is undefined in your current OpenOffice/LibreOffice document. Searching...=Searching... Please\ enter\ a\ search\ string=Please enter a search string @@ -1876,11 +1871,7 @@ Could\ not\ connect\ to\ Vim\ server.\ Make\ sure\ that\ Vim\ is\ running\ with\ Could\ not\ connect\ to\ a\ running\ gnuserv\ process.\ Make\ sure\ that\ Emacs\ or\ XEmacs\ is\ running,\ and\ that\ the\ server\ has\ been\ started\ (by\ running\ the\ command\ 'server-start'/'gnuserv-start').=Could not connect to a running gnuserv process. Make sure that Emacs or XEmacs is running, and that the server has been started (by running the command 'server-start'/'gnuserv-start'). Error\ pushing\ entries=Error pushing entries -Undefined\ character\ format=Undefined character format -Undefined\ paragraph\ format=Undefined paragraph format - Preamble=Preamble -Edit\ Preamble=Edit Preamble Markings=Markings Use\ selected\ instance=Use selected instance diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java index a6088ef3a63..fb4514f8410 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java @@ -6,7 +6,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -118,10 +117,10 @@ static CitationMarkerEntry makeCitationMarkerEntry(BibEntry entry, String pageInfoQ, boolean isFirstAppearanceOfSource) { return OOBibStyleTestHelper.makeCitationMarkerEntry(entry, - database, - uniqueLetterQ, - pageInfoQ, - isFirstAppearanceOfSource); + database, + uniqueLetterQ, + pageInfoQ, + isFirstAppearanceOfSource); } /* @@ -136,12 +135,12 @@ static String getCitationMarker2(OOBibStyle style, Boolean[] isFirstAppearanceOfSource, String[] pageInfo) { return OOBibStyleTestHelper.getCitationMarker2(style, - entries, - entryDBMap, - inParenthesis, - uniquefiers, - isFirstAppearanceOfSource, - pageInfo); + entries, + entryDBMap, + inParenthesis, + uniquefiers, + isFirstAppearanceOfSource, + pageInfo); } static String getCitationMarker2b(OOBibStyle style, @@ -152,12 +151,12 @@ static String getCitationMarker2b(OOBibStyle style, Boolean[] isFirstAppearanceOfSource, String[] pageInfo) { return OOBibStyleTestHelper.getCitationMarker2b(style, - entries, - entryDBMap, - inParenthesis, - uniquefiers, - isFirstAppearanceOfSource, - pageInfo); + entries, + entryDBMap, + inParenthesis, + uniquefiers, + isFirstAppearanceOfSource, + pageInfo); } /* @@ -168,15 +167,15 @@ static String getCitationMarker2b(OOBibStyle style, void testGetNumCitationMarker() throws IOException { OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, layoutFormatterPreferences); - assertEquals("[1] ", runGetNumCitationMarker2a(style, Arrays.asList(1), -1, true)); + assertEquals("[1] ", runGetNumCitationMarker2a(style, List.of(1), -1, true)); - assertEquals("[1]", runGetNumCitationMarker2a(style, Arrays.asList(1), -1, false)); + assertEquals("[1]", runGetNumCitationMarker2a(style, List.of(1), -1, false)); assertEquals("[1]", runGetNumCitationMarker2b(style, -1, numEntry("key", 1, null))); - assertEquals("[1] ", runGetNumCitationMarker2a(style, Arrays.asList(1), 0, true)); + assertEquals("[1] ", runGetNumCitationMarker2a(style, List.of(1), 0, true)); CitationMarkerNumericEntry e2 = numEntry("key", 1, "pp. 55-56"); - assertEquals(true, e2.getPageInfo().isPresent()); + assertTrue(e2.getPageInfo().isPresent()); assertEquals("pp. 55-56", e2.getPageInfo().get().toString()); OOBibStyleTestHelper.testGetNumCitationMarkerExtra(style); @@ -189,45 +188,45 @@ void testGetNumCitationMarkerUndefined() throws IOException { // unresolved citations look like [??key] assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "]", - runGetNumCitationMarker2b(style, 1, - numEntry("key", 0, null))); + runGetNumCitationMarker2b(style, 1, + numEntry("key", 0, null))); // pageInfo is shown for unresolved citations assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "; p1]", - runGetNumCitationMarker2b(style, 1, - numEntry("key", 0, "p1"))); + runGetNumCitationMarker2b(style, 1, + numEntry("key", 0, "p1"))); // unresolved citations sorted to the front assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "; 2-4]", - runGetNumCitationMarker2b(style, 1, - numEntry("x4", 4, ""), - numEntry("x2", 2, ""), - numEntry("x3", 3, ""), - numEntry("key", 0, ""))); + runGetNumCitationMarker2b(style, 1, + numEntry("x4", 4, ""), + numEntry("x2", 2, ""), + numEntry("x3", 3, ""), + numEntry("key", 0, ""))); assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "; 1-3]", - runGetNumCitationMarker2b(style, 1, - numEntry("x1", 1, ""), - numEntry("x2", 2, ""), - numEntry("y3", 3, ""), - numEntry("key", 0, ""))); + runGetNumCitationMarker2b(style, 1, + numEntry("x1", 1, ""), + numEntry("x2", 2, ""), + numEntry("y3", 3, ""), + numEntry("key", 0, ""))); // multiple unresolved citations are not collapsed assertEquals("[" - + OOBibStyle.UNDEFINED_CITATION_MARKER + "x1" + "; " - + OOBibStyle.UNDEFINED_CITATION_MARKER + "x2" + "; " - + OOBibStyle.UNDEFINED_CITATION_MARKER + "x3" + "]", - runGetNumCitationMarker2b(style, 1, - numEntry("x1", 0, ""), - numEntry("x2", 0, ""), - numEntry("x3", 0, ""))); + + OOBibStyle.UNDEFINED_CITATION_MARKER + "x1" + "; " + + OOBibStyle.UNDEFINED_CITATION_MARKER + "x2" + "; " + + OOBibStyle.UNDEFINED_CITATION_MARKER + "x3" + "]", + runGetNumCitationMarker2b(style, 1, + numEntry("x1", 0, ""), + numEntry("x2", 0, ""), + numEntry("x3", 0, ""))); /* * BIBLIOGRAPHY */ CitationMarkerNumericBibEntry x = numBibEntry("key", Optional.empty()); assertEquals("[" + OOBibStyle.UNDEFINED_CITATION_MARKER + "key" + "] ", - style.getNumCitationMarkerForBibliography(x).toString()); + style.getNumCitationMarkerForBibliography(x).toString()); } @Test @@ -270,22 +269,22 @@ void testGetCitationMarker() throws IOException { assertEquals(-1, style.getMaxAuthorsFirst()); assertEquals("[Boström et al., 2006]", - getCitationMarker2(style, - Collections.singletonList(entry), entryDBMap, - true, null, null, null)); + getCitationMarker2(style, + Collections.singletonList(entry), entryDBMap, + true, null, null, null)); assertEquals("Boström et al. [2006]", - getCitationMarker2(style, - Collections.singletonList(entry), entryDBMap, - false, null, new Boolean[]{false}, null)); + getCitationMarker2(style, + Collections.singletonList(entry), entryDBMap, + false, null, new Boolean[] {false}, null)); assertEquals("[Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006]", - getCitationMarker2(style, - Collections.singletonList(entry), entryDBMap, - true, - null, - new Boolean[]{true}, - null)); + getCitationMarker2(style, + Collections.singletonList(entry), entryDBMap, + true, + null, + new Boolean[] {true}, + null)); } @Test @@ -372,8 +371,8 @@ void testInstitutionAuthorMarker() throws IOException { entryDBMap.put(entry, database); assertEquals("[JabRef Development Team, 2016]", - getCitationMarker2(style, - entries, entryDBMap, true, null, null, null)); + getCitationMarker2(style, + entries, entryDBMap, true, null, null, null)); } @Test @@ -487,12 +486,12 @@ void testGetCitationMarkerInParenthesisUniquefiers() throws IOException { } assertEquals("[Beta, 2000; Beta, 2000; Epsilon, 2001]", - getCitationMarker2b(style, entries, entryDBMap, true, null, null, null)); + getCitationMarker2b(style, entries, entryDBMap, true, null, null, null)); assertEquals("[Beta, 2000a,b; Epsilon, 2001]", - getCitationMarker2(style, entries, entryDBMap, true, - new String[]{"a", "b", ""}, - new Boolean[]{false, false, false}, - null)); + getCitationMarker2(style, entries, entryDBMap, true, + new String[] {"a", "b", ""}, + new Boolean[] {false, false, false}, + null)); } @Test @@ -529,12 +528,12 @@ void testGetCitationMarkerInTextUniquefiers() throws IOException { } assertEquals("Beta [2000]; Beta [2000]; Epsilon [2001]", - getCitationMarker2b(style, entries, entryDBMap, false, null, null, null)); + getCitationMarker2b(style, entries, entryDBMap, false, null, null, null)); assertEquals("Beta [2000a,b]; Epsilon [2001]", - getCitationMarker2(style, entries, entryDBMap, false, - new String[]{"a", "b", ""}, - new Boolean[]{false, false, false}, - null)); + getCitationMarker2(style, entries, entryDBMap, false, + new String[] {"a", "b", ""}, + new Boolean[] {false, false, false}, + null)); } @Test @@ -572,10 +571,10 @@ void testGetCitationMarkerInParenthesisUniquefiersThreeSameAuthor() throws IOExc } assertEquals("[Beta, 2000a,b,c]", - getCitationMarker2(style, entries, entryDBMap, true, - new String[]{"a", "b", "c"}, - new Boolean[]{false, false, false}, - null)); + getCitationMarker2(style, entries, entryDBMap, true, + new String[] {"a", "b", "c"}, + new Boolean[] {false, false, false}, + null)); } @Test @@ -613,14 +612,14 @@ void testGetCitationMarkerInTextUniquefiersThreeSameAuthor() throws IOException } assertEquals("Beta [2000a,b,c]", - getCitationMarker2(style, entries, entryDBMap, false, - new String[]{"a", "b", "c"}, - new Boolean[]{false, false, false}, - null)); + getCitationMarker2(style, entries, entryDBMap, false, + new String[] {"a", "b", "c"}, + new Boolean[] {false, false, false}, + null)); } @Test - // TODO: equals only work when initialized from file, not from reader + // TODO: equals only work when initialized from file, not from reader void testEquals() throws IOException { OOBibStyle style1 = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, layoutFormatterPreferences); @@ -630,7 +629,7 @@ void testEquals() throws IOException { } @Test - // TODO: equals only work when initialized from file, not from reader + // TODO: equals only work when initialized from file, not from reader void testNotEquals() throws IOException { OOBibStyle style1 = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, layoutFormatterPreferences); @@ -675,7 +674,7 @@ void testEmptyStringPropertyAndOxfordComma() throws Exception { entries.add(entry); entryDBMap.put(entry, database); assertEquals("von Beta, Epsilon, & Tau, 2016", - getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); + getCitationMarker2(style, entries, entryDBMap, true, null, null, null)); } @Test @@ -687,7 +686,7 @@ void testIsValidWithDefaultSectionAtTheStart() throws Exception { @Test void testGetCitationMarkerJoinFirst() throws IOException { OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, - layoutFormatterPreferences); + layoutFormatterPreferences); // Question: What should happen if some of the sources is // marked as isFirstAppearanceOfSource? @@ -696,11 +695,11 @@ void testGetCitationMarkerJoinFirst() throws IOException { // Two entries with identical normalizedMarkers and many authors. BibEntry entry1 = new BibEntry() .withField(StandardField.AUTHOR, - "Gustav Bostr\\\"{o}m" - + " and Jaana W\\\"{a}yrynen" - + " and Marine Bod\\'{e}n" - + " and Konstantin Beznosov" - + " and Philippe Kruchten") + "Gustav Bostr\\\"{o}m" + + " and Jaana W\\\"{a}yrynen" + + " and Marine Bod\\'{e}n" + + " and Konstantin Beznosov" + + " and Philippe Kruchten") .withField(StandardField.YEAR, "2006") .withField(StandardField.BOOKTITLE, "A book 1") .withField(StandardField.PUBLISHER, "ACM") @@ -710,11 +709,11 @@ void testGetCitationMarkerJoinFirst() throws IOException { BibEntry entry2 = new BibEntry() .withField(StandardField.AUTHOR, - "Gustav Bostr\\\"{o}m" - + " and Jaana W\\\"{a}yrynen" - + " and Marine Bod\\'{e}n" - + " and Konstantin Beznosov" - + " and Philippe Kruchten") + "Gustav Bostr\\\"{o}m" + + " and Jaana W\\\"{a}yrynen" + + " and Marine Bod\\'{e}n" + + " and Konstantin Beznosov" + + " and Philippe Kruchten") .withField(StandardField.YEAR, "2006") .withField(StandardField.BOOKTITLE, "A book 2") .withField(StandardField.PUBLISHER, "ACM") @@ -725,11 +724,11 @@ void testGetCitationMarkerJoinFirst() throws IOException { // Last Author differs. BibEntry entry3 = new BibEntry() .withField(StandardField.AUTHOR, - "Gustav Bostr\\\"{o}m" - + " and Jaana W\\\"{a}yrynen" - + " and Marine Bod\\'{e}n" - + " and Konstantin Beznosov" - + " and Philippe NotKruchten") + "Gustav Bostr\\\"{o}m" + + " and Jaana W\\\"{a}yrynen" + + " and Marine Bod\\'{e}n" + + " and Konstantin Beznosov" + + " and Philippe NotKruchten") .withField(StandardField.YEAR, "2006") .withField(StandardField.BOOKTITLE, "A book 3") .withField(StandardField.PUBLISHER, "ACM") @@ -747,26 +746,26 @@ void testGetCitationMarkerJoinFirst() throws IOException { if (true) { List citationMarkerEntries = new ArrayList<>(); CitationMarkerEntry cm1 = - makeCitationMarkerEntry(entry1, database, "a", null, true); + makeCitationMarkerEntry(entry1, database, "a", null, true); citationMarkerEntries.add(cm1); CitationMarkerEntry cm2 = - makeCitationMarkerEntry(entry2, database, "b", null, true); + makeCitationMarkerEntry(entry2, database, "b", null, true); citationMarkerEntries.add(cm2); CitationMarkerEntry cm3 = - makeCitationMarkerEntry(entry3, database, "c", null, true); + makeCitationMarkerEntry(entry3, database, "c", null, true); citationMarkerEntries.add(cm3); assertEquals("[Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006a,b" - + "; Boström, Wäyrynen, Bodén, Beznosov & NotKruchten, 2006c]", - style.createCitationMarker(citationMarkerEntries, - true, - NonUniqueCitationMarker.THROWS).toString()); + + "; Boström, Wäyrynen, Bodén, Beznosov & NotKruchten, 2006c]", + style.createCitationMarker(citationMarkerEntries, + true, + NonUniqueCitationMarker.THROWS).toString()); assertEquals("Boström, Wäyrynen, Bodén, Beznosov & Kruchten [2006a,b]" - + "; Boström, Wäyrynen, Bodén, Beznosov & NotKruchten [2006c]", - style.createCitationMarker(citationMarkerEntries, - false, - NonUniqueCitationMarker.THROWS).toString()); + + "; Boström, Wäyrynen, Bodén, Beznosov & NotKruchten [2006c]", + style.createCitationMarker(citationMarkerEntries, + false, + NonUniqueCitationMarker.THROWS).toString()); } // Without pageInfo, only the first is isFirstAppearanceOfSource. @@ -775,21 +774,20 @@ void testGetCitationMarkerJoinFirst() throws IOException { if (true) { List citationMarkerEntries = new ArrayList<>(); CitationMarkerEntry cm1 = - makeCitationMarkerEntry(entry1, database, "a", null, true); + makeCitationMarkerEntry(entry1, database, "a", null, true); citationMarkerEntries.add(cm1); CitationMarkerEntry cm2 = - makeCitationMarkerEntry(entry2, database, "b", null, false); + makeCitationMarkerEntry(entry2, database, "b", null, false); citationMarkerEntries.add(cm2); CitationMarkerEntry cm3 = - makeCitationMarkerEntry(entry3, database, "c", null, false); + makeCitationMarkerEntry(entry3, database, "c", null, false); citationMarkerEntries.add(cm3); assertEquals("[Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006a,b" - + "; Boström et al., 2006c]", - style.createCitationMarker(citationMarkerEntries, - true, - NonUniqueCitationMarker.THROWS).toString()); - + + "; Boström et al., 2006c]", + style.createCitationMarker(citationMarkerEntries, + true, + NonUniqueCitationMarker.THROWS).toString()); } // Without pageInfo, only the second is isFirstAppearanceOfSource. // The second is not joined, because it is a first appearance, thus @@ -798,21 +796,21 @@ void testGetCitationMarkerJoinFirst() throws IOException { if (true) { List citationMarkerEntries = new ArrayList<>(); CitationMarkerEntry cm1 = - makeCitationMarkerEntry(entry1, database, "a", null, false); + makeCitationMarkerEntry(entry1, database, "a", null, false); citationMarkerEntries.add(cm1); CitationMarkerEntry cm2 = - makeCitationMarkerEntry(entry2, database, "b", null, true); + makeCitationMarkerEntry(entry2, database, "b", null, true); citationMarkerEntries.add(cm2); CitationMarkerEntry cm3 = - makeCitationMarkerEntry(entry3, database, "c", null, false); + makeCitationMarkerEntry(entry3, database, "c", null, false); citationMarkerEntries.add(cm3); assertEquals("[Boström et al., 2006a" - + "; Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006b" - + "; Boström et al., 2006c]", - style.createCitationMarker(citationMarkerEntries, - true, - NonUniqueCitationMarker.THROWS).toString()); + + "; Boström, Wäyrynen, Bodén, Beznosov & Kruchten, 2006b" + + "; Boström et al., 2006c]", + style.createCitationMarker(citationMarkerEntries, + true, + NonUniqueCitationMarker.THROWS).toString()); } // Without pageInfo, neither is isFirstAppearanceOfSource. @@ -822,19 +820,19 @@ void testGetCitationMarkerJoinFirst() throws IOException { if (true) { List citationMarkerEntries = new ArrayList<>(); CitationMarkerEntry cm1 = - makeCitationMarkerEntry(entry1, database, "a", null, false); + makeCitationMarkerEntry(entry1, database, "a", null, false); citationMarkerEntries.add(cm1); CitationMarkerEntry cm2 = - makeCitationMarkerEntry(entry2, database, "b", null, false); + makeCitationMarkerEntry(entry2, database, "b", null, false); citationMarkerEntries.add(cm2); CitationMarkerEntry cm3 = - makeCitationMarkerEntry(entry3, database, "c", null, false); + makeCitationMarkerEntry(entry3, database, "c", null, false); citationMarkerEntries.add(cm3); assertEquals("[Boström et al., 2006a,b,c]", - style.createCitationMarker(citationMarkerEntries, - true, - NonUniqueCitationMarker.THROWS).toString()); + style.createCitationMarker(citationMarkerEntries, + true, + NonUniqueCitationMarker.THROWS).toString()); } // With pageInfo: different entries with identical non-null pageInfo: not joined. @@ -842,21 +840,21 @@ void testGetCitationMarkerJoinFirst() throws IOException { if (true) { List citationMarkerEntries = new ArrayList<>(); CitationMarkerEntry cm1 = - makeCitationMarkerEntry(entry1, database, "a", "p1", false); + makeCitationMarkerEntry(entry1, database, "a", "p1", false); citationMarkerEntries.add(cm1); CitationMarkerEntry cm2 = - makeCitationMarkerEntry(entry2, database, "b", "p1", false); + makeCitationMarkerEntry(entry2, database, "b", "p1", false); citationMarkerEntries.add(cm2); CitationMarkerEntry cm3 = - makeCitationMarkerEntry(entry3, database, "c", "p1", false); + makeCitationMarkerEntry(entry3, database, "c", "p1", false); citationMarkerEntries.add(cm3); assertEquals("[Boström et al., 2006a; p1" - + "; Boström et al., 2006b; p1" - + "; Boström et al., 2006c; p1]", - style.createCitationMarker(citationMarkerEntries, - true, - NonUniqueCitationMarker.THROWS).toString()); + + "; Boström et al., 2006b; p1" + + "; Boström et al., 2006c; p1]", + style.createCitationMarker(citationMarkerEntries, + true, + NonUniqueCitationMarker.THROWS).toString()); } // With pageInfo: same entries with identical non-null pageInfo: collapsed. @@ -865,43 +863,43 @@ void testGetCitationMarkerJoinFirst() throws IOException { if (true) { List citationMarkerEntries = new ArrayList<>(); CitationMarkerEntry cm1 = - makeCitationMarkerEntry(entry1, database, "a", "p1", false); + makeCitationMarkerEntry(entry1, database, "a", "p1", false); citationMarkerEntries.add(cm1); CitationMarkerEntry cm2 = - makeCitationMarkerEntry(entry1, database, "a", "p1", false); + makeCitationMarkerEntry(entry1, database, "a", "p1", false); citationMarkerEntries.add(cm2); CitationMarkerEntry cm3 = - makeCitationMarkerEntry(entry1, database, "a", "p1", false); + makeCitationMarkerEntry(entry1, database, "a", "p1", false); citationMarkerEntries.add(cm3); assertEquals("[Boström et al., 2006a; p1]", - style.createCitationMarker(citationMarkerEntries, - true, - NonUniqueCitationMarker.THROWS).toString()); + style.createCitationMarker(citationMarkerEntries, + true, + NonUniqueCitationMarker.THROWS).toString()); } // With pageInfo: same entries with different pageInfo: kept separate. // Empty ("") and missing pageInfos considered equal, thus collapsed. if (true) { List citationMarkerEntries = new ArrayList<>(); CitationMarkerEntry cm1 = - makeCitationMarkerEntry(entry1, database, "a", "p1", false); + makeCitationMarkerEntry(entry1, database, "a", "p1", false); citationMarkerEntries.add(cm1); CitationMarkerEntry cm2 = - makeCitationMarkerEntry(entry1, database, "a", "p2", false); + makeCitationMarkerEntry(entry1, database, "a", "p2", false); citationMarkerEntries.add(cm2); CitationMarkerEntry cm3 = - makeCitationMarkerEntry(entry1, database, "a", "", false); + makeCitationMarkerEntry(entry1, database, "a", "", false); citationMarkerEntries.add(cm3); CitationMarkerEntry cm4 = - makeCitationMarkerEntry(entry1, database, "a", null, false); + makeCitationMarkerEntry(entry1, database, "a", null, false); citationMarkerEntries.add(cm4); assertEquals("[Boström et al., 2006a; p1" - + "; Boström et al., 2006a; p2" - + "; Boström et al., 2006a]", - style.createCitationMarker(citationMarkerEntries, - true, - NonUniqueCitationMarker.THROWS).toString()); + + "; Boström et al., 2006a; p2" + + "; Boström et al., 2006a]", + style.createCitationMarker(citationMarkerEntries, + true, + NonUniqueCitationMarker.THROWS).toString()); } } } diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java index 8a6b4585d19..9bf8d148a70 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java @@ -1,6 +1,5 @@ package org.jabref.logic.openoffice.style; -import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -37,15 +36,15 @@ static class CitationMarkerNumericEntryImpl implements CitationMarkerNumericEntr */ public final static int UNRESOLVED_ENTRY_NUMBER = 0; - private String citationKey; - private Optional num; - private Optional pageInfo; + private final String citationKey; + private final Optional num; + private final Optional pageInfo; public CitationMarkerNumericEntryImpl(String citationKey, int num, Optional pageInfo) { this.citationKey = citationKey; this.num = (num == UNRESOLVED_ENTRY_NUMBER - ? Optional.empty() - : Optional.of(num)); + ? Optional.empty() + : Optional.of(num)); this.pageInfo = PageInfo.normalizePageInfo(pageInfo); } @@ -98,22 +97,21 @@ static String runGetNumCitationMarker2a(OOBibStyle style, List num, int minGroupingCount, boolean inList) { if (inList) { if (num.size() != 1) { - throw new IllegalArgumentException("Numeric label for the bibliography with " - + String.valueOf(num.size()) + " numbers?"); + throw new IllegalArgumentException("Numeric label for the bibliography with " + num.size() + " numbers?"); } int n = num.get(0); CitationMarkerNumericBibEntryImpl x = - new CitationMarkerNumericBibEntryImpl("key", - (n == 0) ? Optional.empty() : Optional.of(n)); + new CitationMarkerNumericBibEntryImpl("key", + (n == 0) ? Optional.empty() : Optional.of(n)); return style.getNumCitationMarkerForBibliography(x).toString(); } else { List input = - num.stream() - .map(n -> - new CitationMarkerNumericEntryImpl("key" + String.valueOf(n), - n, - Optional.empty())) - .collect(Collectors.toList()); + num.stream() + .map(n -> + new CitationMarkerNumericEntryImpl("key" + n, + n, + Optional.empty())) + .collect(Collectors.toList()); return style.getNumCitationMarker2(input, minGroupingCount).toString(); } } @@ -187,15 +185,15 @@ static String getCitationMarker2ab(OOBibStyle style, for (int i = 0; i < entries.size(); i++) { BibEntry entry = entries.get(i); CitationMarkerEntry e = makeCitationMarkerEntry(entry, - entryDBMap.get(entry), - uniquefiers[i], - pageInfo[i], - isFirstAppearanceOfSource[i]); + entryDBMap.get(entry), + uniquefiers[i], + pageInfo[i], + isFirstAppearanceOfSource[i]); citationMarkerEntries.add(e); } return style.createCitationMarker(citationMarkerEntries, - inParenthesis, - nonunique).toString(); + inParenthesis, + nonunique).toString(); } static String getCitationMarker2(OOBibStyle style, @@ -206,13 +204,13 @@ static String getCitationMarker2(OOBibStyle style, Boolean[] isFirstAppearanceOfSource, String[] pageInfo) { return getCitationMarker2ab(style, - entries, - entryDBMap, - inParenthesis, - uniquefiers, - isFirstAppearanceOfSource, - pageInfo, - NonUniqueCitationMarker.THROWS); + entries, + entryDBMap, + inParenthesis, + uniquefiers, + isFirstAppearanceOfSource, + pageInfo, + NonUniqueCitationMarker.THROWS); } static String getCitationMarker2b(OOBibStyle style, @@ -223,149 +221,149 @@ static String getCitationMarker2b(OOBibStyle style, Boolean[] isFirstAppearanceOfSource, String[] pageInfo) { return getCitationMarker2ab(style, - entries, - entryDBMap, - inParenthesis, - uniquefiers, - isFirstAppearanceOfSource, - pageInfo, - NonUniqueCitationMarker.FORGIVEN); + entries, + entryDBMap, + inParenthesis, + uniquefiers, + isFirstAppearanceOfSource, + pageInfo, + NonUniqueCitationMarker.FORGIVEN); } /* * end helper */ - static void testGetNumCitationMarkerExtra(OOBibStyle style) throws IOException { + static void testGetNumCitationMarkerExtra(OOBibStyle style) { // Identical numeric entries are joined. assertEquals("[1; 2]", runGetNumCitationMarker2b(style, 3, - numEntry("x1", 1, null), - numEntry("x2", 2, null), - numEntry("x1", 2, null), - numEntry("x2", 1, null))); + numEntry("x1", 1, null), + numEntry("x2", 2, null), + numEntry("x1", 2, null), + numEntry("x2", 1, null))); // ... unless minGroupingCount <= 0 assertEquals("[1; 1; 2; 2]", runGetNumCitationMarker2b(style, 0, - numEntry("x1", 1, null), - numEntry("x2", 2, null), - numEntry("x1", 2, null), - numEntry("x2", 1, null))); + numEntry("x1", 1, null), + numEntry("x2", 2, null), + numEntry("x1", 2, null), + numEntry("x2", 1, null))); // ... or have different pageInfos assertEquals("[1; p1a; 1; p1b; 2; p2; 3]", runGetNumCitationMarker2b(style, 1, - numEntry("x1", 1, "p1a"), - numEntry("x1", 1, "p1b"), - numEntry("x2", 2, "p2"), - numEntry("x2", 2, "p2"), - numEntry("x3", 3, null), - numEntry("x3", 3, null))); + numEntry("x1", 1, "p1a"), + numEntry("x1", 1, "p1b"), + numEntry("x2", 2, "p2"), + numEntry("x2", 2, "p2"), + numEntry("x3", 3, null), + numEntry("x3", 3, null))); // Consecutive numbers can become a range ... assertEquals("[1-3]", runGetNumCitationMarker2b(style, 1, - numEntry("x1", 1, null), - numEntry("x2", 2, null), - numEntry("x3", 3, null))); + numEntry("x1", 1, null), + numEntry("x2", 2, null), + numEntry("x3", 3, null))); // ... unless minGroupingCount is too high assertEquals("[1; 2; 3]", runGetNumCitationMarker2b(style, 4, - numEntry("x1", 1, null), - numEntry("x2", 2, null), - numEntry("x3", 3, null))); + numEntry("x1", 1, null), + numEntry("x2", 2, null), + numEntry("x3", 3, null))); // ... or if minGroupingCount <= 0 assertEquals("[1; 2; 3]", runGetNumCitationMarker2b(style, 0, - numEntry("x1", 1, null), - numEntry("x2", 2, null), - numEntry("x3", 3, null))); + numEntry("x1", 1, null), + numEntry("x2", 2, null), + numEntry("x3", 3, null))); // ... a pageInfo needs to be emitted assertEquals("[1; p1; 2-3]", runGetNumCitationMarker2b(style, 1, - numEntry("x1", 1, "p1"), - numEntry("x2", 2, null), - numEntry("x3", 3, null))); + numEntry("x1", 1, "p1"), + numEntry("x2", 2, null), + numEntry("x3", 3, null))); // null and "" pageInfos are taken as equal. // Due to trimming, " " is the same as well. assertEquals("[1]", runGetNumCitationMarker2b(style, 1, - numEntry("x1", 1, ""), - numEntry("x1", 1, null), - numEntry("x1", 1, " "))); + numEntry("x1", 1, ""), + numEntry("x1", 1, null), + numEntry("x1", 1, " "))); // pageInfos are trimmed assertEquals("[1; p1]", runGetNumCitationMarker2b(style, 1, - numEntry("x1", 1, "p1"), - numEntry("x1", 1, " p1"), - numEntry("x1", 1, "p1 "))); + numEntry("x1", 1, "p1"), + numEntry("x1", 1, " p1"), + numEntry("x1", 1, "p1 "))); // The citation numbers come out sorted assertEquals("[3-5; 7; 10-12]", runGetNumCitationMarker2b(style, 1, - numEntry("x12", 12, null), - numEntry("x7", 7, null), - numEntry("x3", 3, null), - numEntry("x4", 4, null), - numEntry("x11", 11, null), - numEntry("x10", 10, null), - numEntry("x5", 5, null))); + numEntry("x12", 12, null), + numEntry("x7", 7, null), + numEntry("x3", 3, null), + numEntry("x4", 4, null), + numEntry("x11", 11, null), + numEntry("x10", 10, null), + numEntry("x5", 5, null))); // pageInfos are sorted together with the numbers // (but they inhibit ranges where they are, even if they are identical, // but not empty-or-null) assertEquals("[3; p3; 4; p4; 5; p5; 7; p7; 10; px; 11; px; 12; px]", - runGetNumCitationMarker2b(style, 1, - numEntry("x12", 12, "px"), - numEntry("x7", 7, "p7"), - numEntry("x3", 3, "p3"), - numEntry("x4", 4, "p4"), - numEntry("x11", 11, "px"), - numEntry("x10", 10, "px"), - numEntry("x5", 5, "p5"))); + runGetNumCitationMarker2b(style, 1, + numEntry("x12", 12, "px"), + numEntry("x7", 7, "p7"), + numEntry("x3", 3, "p3"), + numEntry("x4", 4, "p4"), + numEntry("x11", 11, "px"), + numEntry("x10", 10, "px"), + numEntry("x5", 5, "p5"))); // pageInfo sorting (for the same number) assertEquals("[1; 1; a; 1; b]", - runGetNumCitationMarker2b(style, 1, - numEntry("x1", 1, ""), - numEntry("x1", 1, "b"), - numEntry("x1", 1, "a"))); + runGetNumCitationMarker2b(style, 1, + numEntry("x1", 1, ""), + numEntry("x1", 1, "b"), + numEntry("x1", 1, "a"))); // pageInfo sorting (for the same number) is not numeric. assertEquals("[1; p100; 1; p20; 1; p9]", - runGetNumCitationMarker2b(style, 1, - numEntry("x1", 1, "p20"), - numEntry("x1", 1, "p9"), - numEntry("x1", 1, "p100"))); + runGetNumCitationMarker2b(style, 1, + numEntry("x1", 1, "p20"), + numEntry("x1", 1, "p9"), + numEntry("x1", 1, "p100"))); assertEquals("[1-3]", - runGetNumCitationMarker2b(style, 1, - numEntry("x1", 1, null), - numEntry("x2", 2, null), - numEntry("x3", 3, null))); + runGetNumCitationMarker2b(style, 1, + numEntry("x1", 1, null), + numEntry("x2", 2, null), + numEntry("x3", 3, null))); assertEquals("[1; 2; 3]", - runGetNumCitationMarker2b(style, 5, - numEntry("x1", 1, null), - numEntry("x2", 2, null), - numEntry("x3", 3, null))); + runGetNumCitationMarker2b(style, 5, + numEntry("x1", 1, null), + numEntry("x2", 2, null), + numEntry("x3", 3, null))); assertEquals("[1; 2; 3]", - runGetNumCitationMarker2b(style, -1, - numEntry("x1", 1, null), - numEntry("x2", 2, null), - numEntry("x3", 3, null))); + runGetNumCitationMarker2b(style, -1, + numEntry("x1", 1, null), + numEntry("x2", 2, null), + numEntry("x3", 3, null))); assertEquals("[1; 3; 12]", - runGetNumCitationMarker2b(style, 1, - numEntry("x1", 1, null), - numEntry("x12", 12, null), - numEntry("x3", 3, null))); + runGetNumCitationMarker2b(style, 1, + numEntry("x1", 1, null), + numEntry("x12", 12, null), + numEntry("x3", 3, null))); assertEquals("[3-5; 7; 10-12]", - runGetNumCitationMarker2b(style, 1, - numEntry("x12", 12, ""), - numEntry("x7", 7, ""), - numEntry("x3", 3, ""), - numEntry("x4", 4, ""), - numEntry("x11", 11, ""), - numEntry("x10", 10, ""), - numEntry("x5", 5, ""))); + runGetNumCitationMarker2b(style, 1, + numEntry("x12", 12, ""), + numEntry("x7", 7, ""), + numEntry("x3", 3, ""), + numEntry("x4", 4, ""), + numEntry("x11", 11, ""), + numEntry("x10", 10, ""), + numEntry("x5", 5, ""))); } } diff --git a/src/test/java/org/jabref/logic/openoffice/style/StyleLoaderTest.java b/src/test/java/org/jabref/logic/openoffice/style/StyleLoaderTest.java index 9b5a58f4de5..c0150b22318 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/StyleLoaderTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/StyleLoaderTest.java @@ -84,7 +84,7 @@ public void testAddInvalidStyleLeadsToNoMoreStyle() { @Test public void testInitalizeWithOneExternalFile() throws URISyntaxException { String filename = Path.of(StyleLoader.class.getResource(StyleLoader.DEFAULT_AUTHORYEAR_STYLE_PATH).toURI()) - .toFile().getPath(); + .toFile().getPath(); when(preferences.getExternalStyles()).thenReturn(Collections.singletonList(filename)); loader = new StyleLoader(preferences, layoutPreferences, encoding); assertEquals(NUMBER_OF_INTERNAL_STYLES + 1, loader.getStyles().size()); @@ -101,7 +101,7 @@ public void testInitalizeWithIncorrectExternalFile() { @Test public void testInitalizeWithOneExternalFileRemoveStyle() throws URISyntaxException { String filename = Path.of(StyleLoader.class.getResource(StyleLoader.DEFAULT_AUTHORYEAR_STYLE_PATH).toURI()) - .toFile().getPath(); + .toFile().getPath(); when(preferences.getExternalStyles()).thenReturn(Collections.singletonList(filename)); loader = new StyleLoader(preferences, layoutPreferences, encoding); @@ -122,7 +122,7 @@ public void testInitalizeWithOneExternalFileRemoveStyle() throws URISyntaxExcept @Test public void testInitalizeWithOneExternalFileRemoveStyleUpdatesPreferences() throws URISyntaxException { String filename = Path.of(StyleLoader.class.getResource(StyleLoader.DEFAULT_AUTHORYEAR_STYLE_PATH).toURI()) - .toFile().getPath(); + .toFile().getPath(); when(preferences.getExternalStyles()).thenReturn(Collections.singletonList(filename)); loader = new StyleLoader(preferences, layoutPreferences, encoding); @@ -146,7 +146,7 @@ public void testAddSameStyleTwiceLeadsToOneMoreStyle() throws URISyntaxException loader = new StyleLoader(preferences, layoutPreferences, encoding); int beforeAdding = loader.getStyles().size(); String filename = Path.of(StyleLoader.class.getResource(StyleLoader.DEFAULT_AUTHORYEAR_STYLE_PATH).toURI()) - .toFile().getPath(); + .toFile().getPath(); loader.addStyleIfValid(filename); loader.addStyleIfValid(filename); assertEquals(beforeAdding + 1, loader.getStyles().size()); diff --git a/src/test/java/org/jabref/model/openoffice/CitationEntryTest.java b/src/test/java/org/jabref/model/openoffice/CitationEntryTest.java index fd7ec48b9b3..8648d9b5df9 100644 --- a/src/test/java/org/jabref/model/openoffice/CitationEntryTest.java +++ b/src/test/java/org/jabref/model/openoffice/CitationEntryTest.java @@ -11,7 +11,7 @@ class CitationEntryTest { @Test - void testCitationEntryInitalPageInfo() { + void testCitationEntryInitialPageInfo() { CitationEntry citationEntry = new CitationEntry("RefMark", "Context", "Info"); assertTrue(citationEntry.getPageInfo().isPresent()); assertEquals("Info", citationEntry.getPageInfo().get()); @@ -20,7 +20,7 @@ void testCitationEntryInitalPageInfo() { } @Test - void testCitationEntryOptionalInitalPageInfo() { + void testCitationEntryOptionalInitialPageInfo() { CitationEntry citationEntry = new CitationEntry("RefMark", "Context", Optional.of("Info")); assertEquals(Optional.of("Info"), citationEntry.getPageInfo()); @@ -35,7 +35,7 @@ void testCitationEntryInitalPageInfoChanged() { } @Test - void testCitationEntryNoInitalPageInfo() { + void testCitationEntryNoInitialPageInfo() { CitationEntry citationEntry = new CitationEntry("RefMark", "Context"); assertEquals(Optional.empty(), citationEntry.getPageInfo()); } From f4f5b57f3ca679dc790dfc0d71f79944bc5da3ac Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Date: Tue, 8 Mar 2022 21:22:18 +0100 Subject: [PATCH 102/103] Applied some ide suggestions, reworded some variables, reworded-removed-reformatted some comments --- .../DetectOpenOfficeInstallation.java | 11 +- .../ManageCitationsDialogViewModel.java | 4 +- .../org/jabref/gui/openoffice/OOBibBase.java | 209 ++++++++---------- .../gui/openoffice/OOBibBaseConnect.java | 4 - .../logic/openoffice/action/EditMerge.java | 6 +- .../logic/openoffice/action/ExportCited.java | 1 - .../logic/openoffice/action/Update.java | 2 +- .../logic/openoffice/backend/Backend52.java | 13 +- .../backend/NamedRangeReferenceMark.java | 2 - .../logic/openoffice/frontend/OOFrontend.java | 4 +- .../frontend/UpdateBibliography.java | 3 - .../frontend/UpdateCitationMarkers.java | 3 - .../style/OOBibStyleGetCitationMarker.java | 1 - .../style/OOBibStyleGetNumCitationMarker.java | 6 +- .../style/OOFormatBibliography.java | 30 +-- .../openoffice/style/OOPreFormatter.java | 82 ++----- .../logic/openoffice/style/OOProcess.java | 19 +- .../style/OOProcessAuthorYearMarkers.java | 25 +-- .../style/OOProcessCitationKeyMarkers.java | 7 +- .../style/OOProcessNumericMarkers.java | 11 +- .../model/openoffice/ootext/OOTextIntoOO.java | 19 +- .../openoffice/rangesort/RangeSortEntry.java | 2 +- .../model/openoffice/style/CitationGroup.java | 4 - .../openoffice/style/CitationGroups.java | 2 +- .../model/openoffice/style/CitedKey.java | 12 +- .../model/openoffice/style/CitedKeys.java | 12 +- .../openoffice/style/CompareCitation.java | 2 +- .../model/openoffice/uno/UnoProperties.java | 16 -- src/main/resources/l10n/JabRef_en.properties | 2 +- .../openoffice/style/OOBibStyleTest.java | 2 +- .../style/OOBibStyleTestHelper.java | 4 - 31 files changed, 203 insertions(+), 317 deletions(-) diff --git a/src/main/java/org/jabref/gui/openoffice/DetectOpenOfficeInstallation.java b/src/main/java/org/jabref/gui/openoffice/DetectOpenOfficeInstallation.java index 7e80d9c269a..719cdd4b870 100644 --- a/src/main/java/org/jabref/gui/openoffice/DetectOpenOfficeInstallation.java +++ b/src/main/java/org/jabref/gui/openoffice/DetectOpenOfficeInstallation.java @@ -88,10 +88,11 @@ public Optional chooseAmongInstallations(List installDirs) { return Optional.of(installDirs.get(0).toAbsolutePath()); } - String content = Localization.lang("Found more than one OpenOffice/LibreOffice executable.") - + "\n" + Localization.lang("Please choose which one to connect to:"); - - return dialogService.showChoiceDialogAndWait(Localization.lang("Choose OpenOffice/LibreOffice executable"), - content, Localization.lang("Use selected instance"), installDirs); + return dialogService.showChoiceDialogAndWait( + Localization.lang("Choose OpenOffice/LibreOffice executable"), + Localization.lang("Found more than one OpenOffice/LibreOffice executable.") + "\n" + + Localization.lang("Please choose which one to connect to:"), + Localization.lang("Use selected instance"), + installDirs); } } diff --git a/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java b/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java index 3736cb3243c..697212fde54 100644 --- a/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java +++ b/src/main/java/org/jabref/gui/openoffice/ManageCitationsDialogViewModel.java @@ -35,8 +35,8 @@ public ManageCitationsDialogViewModel(OOBibBase ooBase, DialogService dialogServ } public void storeSettings() { - List ciationEntries = citations.stream().map(CitationEntryViewModel::toCitationEntry).collect(Collectors.toList()); - ooBase.guiActionApplyCitationEntries(ciationEntries); + List citationEntries = citations.stream().map(CitationEntryViewModel::toCitationEntry).collect(Collectors.toList()); + ooBase.guiActionApplyCitationEntries(citationEntries); } public ListProperty citationsProperty() { diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase.java index 06a6091452b..e8e7f50205d 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBase.java @@ -57,25 +57,16 @@ class OOBibBase { private static final Logger LOGGER = LoggerFactory.getLogger(OOBibBase.class); - /* variables */ private final DialogService dialogService; - /* - * After inserting a citation, if ooPrefs.getSyncWhenCiting() returns true, - * shall we also update the bibliography? - */ + // After inserting a citation, if ooPrefs.getSyncWhenCiting() returns true, shall we also update the bibliography? private final boolean refreshBibliographyDuringSyncWhenCiting; - /* - * Shall we add "Cited on pages: ..." to resolved bibliography entries? - */ + // Shall we add "Cited on pages: ..." to resolved bibliography entries? private final boolean alwaysAddCitedOnPages; private final OOBibBaseConnect connection; - /* - * Constructor - */ public OOBibBase(Path loPath, DialogService dialogService) throws BootstrapException, @@ -89,7 +80,7 @@ public OOBibBase(Path loPath, DialogService dialogService) } public void guiActionSelectDocument(boolean autoSelectForSingle) { - final String title = Localization.lang("Problem connecting"); + final String errorTitle = Localization.lang("Problem connecting"); try { @@ -97,12 +88,12 @@ public void guiActionSelectDocument(boolean autoSelectForSingle) { } catch (NoDocumentFoundException ex) { OOError.from(ex).showErrorDialog(dialogService); } catch (DisposedException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + OOError.from(ex).setTitle(errorTitle).showErrorDialog(dialogService); } catch (WrappedTargetException | IndexOutOfBoundsException | NoSuchElementException ex) { LOGGER.warn("Problem connecting", ex); - OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + OOError.fromMisc(ex).setTitle(errorTitle).showErrorDialog(dialogService); } if (this.isConnectedToDocument()) { @@ -151,11 +142,11 @@ void showDialog(OOError err) { err.showErrorDialog(dialogService); } - void showDialog(String title, OOError err) { - err.setTitle(title).showErrorDialog(dialogService); + void showDialog(String errorTitle, OOError err) { + err.setTitle(errorTitle).showErrorDialog(dialogService); } - OOVoidResult collectResults(String title, List> results) { + OOVoidResult collectResults(String errorTitle, List> results) { String msg = (results.stream() .filter(OOVoidResult::isError) .map(e -> e.getError().getLocalizedMessage()) @@ -163,7 +154,7 @@ OOVoidResult collectResults(String title, List> r if (msg.isEmpty()) { return OOVoidResult.ok(); } else { - return OOVoidResult.error(new OOError(title, msg)); + return OOVoidResult.error(new OOError(errorTitle, msg)); } } @@ -171,26 +162,24 @@ boolean testDialog(OOVoidResult res) { return res.ifError(ex -> ex.showErrorDialog(dialogService)).isError(); } - boolean testDialog(String title, OOVoidResult res) { - return res.ifError(e -> showDialog(e.setTitle(title))).isError(); + boolean testDialog(String errorTitle, OOVoidResult res) { + return res.ifError(e -> showDialog(e.setTitle(errorTitle))).isError(); } - boolean testDialog(String title, List> results) { - return testDialog(title, collectResults(title, results)); + boolean testDialog(String errorTitle, List> results) { + return testDialog(errorTitle, collectResults(errorTitle, results)); } @SafeVarargs - final boolean testDialog(String title, OOVoidResult... results) { + final boolean testDialog(String errorTitle, OOVoidResult... results) { List> resultList = Arrays.asList(results); - return testDialog(collectResults(title, resultList)); + return testDialog(collectResults(errorTitle, resultList)); } - /* - * + /** * Get the cursor positioned by the user for inserting text. - * */ - OOResult getUserCursorForTextInsertion(XTextDocument doc, String title) { + OOResult getUserCursorForTextInsertion(XTextDocument doc, String errorTitle) { // Get the cursor positioned by the user. XTextCursor cursor = UnoCursor.getViewCursor(doc).orElse(null); @@ -202,10 +191,9 @@ OOResult getUserCursorForTextInsertion(XTextDocument doc, } catch (com.sun.star.uno.RuntimeException ex) { String msg = Localization.lang("Please move the cursor" - + " to the location for the new citation.") - + "\n" + + " to the location for the new citation.") + "\n" + Localization.lang("I cannot insert to the cursors current location."); - return OOResult.error(new OOError(title, msg, ex)); + return OOResult.error(new OOError(errorTitle, msg, ex)); } return OOResult.ok(cursor); } @@ -213,8 +201,7 @@ OOResult getUserCursorForTextInsertion(XTextDocument doc, /** * This may move the view cursor. */ - OOResult getFunctionalTextViewCursor(XTextDocument doc, - String title) { + OOResult getFunctionalTextViewCursor(XTextDocument doc, String errorTitle) { String messageOnFailureToObtain = Localization.lang("Please move the cursor into the document text.") + "\n" @@ -225,11 +212,11 @@ OOResult getFunctionalTextViewCursor(XTextDoc if (result.isError()) { LOGGER.warn(result.getError()); } - return result.mapError(detail -> new OOError(title, messageOnFailureToObtain)); + return result.mapError(detail -> new OOError(errorTitle, messageOnFailureToObtain)); } private static OOVoidResult checkRangeOverlaps(XTextDocument doc, OOFrontend frontend) { - final String title = "checkRangeOverlaps"; + final String errorTitle = "Overlapping ranges"; boolean requireSeparation = false; int maxReportedOverlaps = 10; try { @@ -239,14 +226,14 @@ private static OOVoidResult checkRangeOverlaps(XTextDocument doc, OOFro maxReportedOverlaps) .mapError(OOError::from)); } catch (NoDocumentException ex) { - return OOVoidResult.error(OOError.from(ex).setTitle(title)); + return OOVoidResult.error(OOError.from(ex).setTitle(errorTitle)); } catch (WrappedTargetException ex) { - return OOVoidResult.error(OOError.fromMisc(ex).setTitle(title)); + return OOVoidResult.error(OOError.fromMisc(ex).setTitle(errorTitle)); } } private static OOVoidResult checkRangeOverlapsWithCursor(XTextDocument doc, OOFrontend frontend) { - final String title = "checkRangeOverlapsWithCursor"; + final String errorTitle = "Ranges overlapping with cursor"; List> userRanges; userRanges = frontend.viewCursorRanges(doc); @@ -258,29 +245,28 @@ private static OOVoidResult checkRangeOverlapsWithCursor(XTextDocument userRanges, requireSeparation); } catch (NoDocumentException ex) { - return OOVoidResult.error(OOError.from(ex).setTitle(title)); + return OOVoidResult.error(OOError.from(ex).setTitle(errorTitle)); } catch (WrappedTargetException ex) { - return OOVoidResult.error(OOError.fromMisc(ex).setTitle(title)); + return OOVoidResult.error(OOError.fromMisc(ex).setTitle(errorTitle)); } if (res.isError()) { - final String xtitle = Localization.lang("The cursor is in protected area."); - return OOVoidResult.error(new OOError(xtitle, - xtitle + "\n" - + res.getError().getLocalizedMessage() + "\n")); + final String xtitle = Localization.lang("The cursor is in a protected area."); + return OOVoidResult.error( + new OOError(xtitle, xtitle + "\n" + res.getError().getLocalizedMessage() + "\n")); } return res.mapError(OOError::from); } - /* + /* ****************************************************** * * Tests for preconditions. * - */ + * ******************************************************/ private static OOVoidResult checkIfOpenOfficeIsRecordingChanges(XTextDocument doc) { - String title = Localization.lang("Recording and/or Recorded changes"); + String errorTitle = Localization.lang("Recording and/or Recorded changes"); try { boolean recordingChanges = UnoRedlines.getRecordChanges(doc); int nRedlines = UnoRedlines.countRedlines(doc); @@ -300,12 +286,12 @@ private static OOVoidResult checkIfOpenOfficeIsRecordingChanges(XTextDo msg += "\n"; msg += Localization.lang("Use [Edit]/[Track Changes]/[Manage] to resolve them first."); } - return OOVoidResult.error(new OOError(title, msg)); + return OOVoidResult.error(new OOError(errorTitle, msg)); } } catch (WrappedTargetException ex) { String msg = Localization.lang("Error while checking if Writer" + " is recording changes or has recorded changes."); - return OOVoidResult.error(new OOError(title, msg, ex)); + return OOVoidResult.error(new OOError(errorTitle, msg, ex)); } return OOVoidResult.ok(); } @@ -319,14 +305,14 @@ OOVoidResult styleIsRequired(OOBibStyle style) { } OOResult getFrontend(XTextDocument doc) { - final String title = "getFrontend"; + final String errorTitle = "Unable to get frontend"; try { return OOResult.ok(new OOFrontend(doc)); } catch (NoDocumentException ex) { - return OOResult.error(OOError.from(ex).setTitle(title)); + return OOResult.error(OOError.from(ex).setTitle(errorTitle)); } catch (WrappedTargetException | RuntimeException ex) { - return OOResult.error(OOError.fromMisc(ex).setTitle(title)); + return OOResult.error(OOError.fromMisc(ex).setTitle(errorTitle)); } } @@ -438,24 +424,24 @@ public OOVoidResult checkStylesExistInTheDocument(OOBibStyle style, XTe return collectResults("checkStyleExistsInTheDocument failed", results); } - /* + /* ****************************************************** * * ManageCitationsDialogView * - */ + * ******************************************************/ public Optional> guiActionGetCitationEntries() { final Optional> FAIL = Optional.empty(); - final String title = Localization.lang("Problem collecting citations"); + final String errorTitle = Localization.lang("Problem collecting citations"); OOResult odoc = getXTextDocument(); - if (testDialog(title, odoc.asVoidResult())) { + if (testDialog(errorTitle, odoc.asVoidResult())) { return FAIL; } XTextDocument doc = odoc.get(); - if (testDialog(title, checkIfOpenOfficeIsRecordingChanges(doc))) { - LOGGER.warn(title); + if (testDialog(errorTitle, checkIfOpenOfficeIsRecordingChanges(doc))) { + LOGGER.warn(errorTitle); return FAIL; } @@ -463,14 +449,14 @@ public Optional> guiActionGetCitationEntries() { return Optional.of(ManageCitations.getCitationEntries(doc)); } catch (NoDocumentException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + OOError.from(ex).setTitle(errorTitle).showErrorDialog(dialogService); return FAIL; } catch (DisposedException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + OOError.from(ex).setTitle(errorTitle).showErrorDialog(dialogService); return FAIL; } catch (WrappedTargetException ex) { - LOGGER.warn(title, ex); - OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + LOGGER.warn(errorTitle, ex); + OOError.fromMisc(ex).setTitle(errorTitle).showErrorDialog(dialogService); return FAIL; } } @@ -496,10 +482,10 @@ public Optional> guiActionGetCitationEntries() { */ public void guiActionApplyCitationEntries(List citationEntries) { - final String title = Localization.lang("Problem modifying citation"); + final String errorTitle = Localization.lang("Problem modifying citation"); OOResult odoc = getXTextDocument(); - if (testDialog(title, odoc.asVoidResult())) { + if (testDialog(errorTitle, odoc.asVoidResult())) { return; } XTextDocument doc = odoc.get(); @@ -508,15 +494,15 @@ public void guiActionApplyCitationEntries(List citationEntries) { ManageCitations.applyCitationEntries(doc, citationEntries); } catch (NoDocumentException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + OOError.from(ex).setTitle(errorTitle).showErrorDialog(dialogService); } catch (DisposedException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + OOError.from(ex).setTitle(errorTitle).showErrorDialog(dialogService); } catch (PropertyVetoException | IllegalTypeException | WrappedTargetException | com.sun.star.lang.IllegalArgumentException ex) { - LOGGER.warn(title, ex); - OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + LOGGER.warn(errorTitle, ex); + OOError.fromMisc(ex).setTitle(errorTitle).showErrorDialog(dialogService); } } @@ -530,7 +516,7 @@ public void guiActionApplyCitationEntries(List citationEntries) { * @param entries The entries to cite. * @param database The database the entries belong to (all of them). Used when creating the citation mark. *

    - * Consistency: for each entry in {@entries}: looking it up in {@code syncOptions.get().databases} (if present) should yield {@code database}. + * Consistency: for each entry in {@code entries}: looking it up in {@code syncOptions.get().databases} (if present) should yield {@code database}. * @param style The bibliography style we are using. * @param citationType Indicates whether it is an in-text citation, a citation in parenthesis or an invisible citation. * @param pageInfo A single page-info for these entries. Attributed to the last entry. @@ -543,10 +529,10 @@ public void guiActionInsertEntry(List entries, String pageInfo, Optional syncOptions) { - final String title = "Could not insert citation"; + final String errorTitle = "Could not insert citation"; OOResult odoc = getXTextDocument(); - if (testDialog(title, + if (testDialog(errorTitle, odoc.asVoidResult(), styleIsRequired(style), selectedBibEntryIsRequired(entries, OOError::noEntriesSelectedForCitation))) { @@ -555,20 +541,20 @@ public void guiActionInsertEntry(List entries, XTextDocument doc = odoc.get(); OOResult frontend = getFrontend(doc); - if (testDialog(title, frontend.asVoidResult())) { + if (testDialog(errorTitle, frontend.asVoidResult())) { return; } - OOResult cursor = getUserCursorForTextInsertion(doc, title); - if (testDialog(title, cursor.asVoidResult())) { + OOResult cursor = getUserCursorForTextInsertion(doc, errorTitle); + if (testDialog(errorTitle, cursor.asVoidResult())) { return; } - if (testDialog(title, checkRangeOverlapsWithCursor(doc, frontend.get()))) { + if (testDialog(errorTitle, checkRangeOverlapsWithCursor(doc, frontend.get()))) { return; } - if (testDialog(title, + if (testDialog(errorTitle, checkStylesExistInTheDocument(style, doc), checkIfOpenOfficeIsRecordingChanges(doc))) { return; @@ -579,8 +565,8 @@ public void guiActionInsertEntry(List entries, */ OOResult fcursor = null; if (syncOptions.isPresent()) { - fcursor = getFunctionalTextViewCursor(doc, title); - if (testDialog(title, fcursor.asVoidResult())) { + fcursor = getFunctionalTextViewCursor(doc, errorTitle); + if (testDialog(errorTitle, fcursor.asVoidResult())) { return; } } @@ -612,19 +598,16 @@ public void guiActionInsertEntry(List entries, Update.resyncDocument(doc, style, fcursor.get(), syncOptions.get()); } } catch (NoDocumentException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); - return; + OOError.from(ex).setTitle(errorTitle).showErrorDialog(dialogService); } catch (DisposedException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); - return; + OOError.from(ex).setTitle(errorTitle).showErrorDialog(dialogService); } catch (CreationException | IllegalTypeException | NotRemoveableException | PropertyVetoException | WrappedTargetException ex) { LOGGER.warn("Could not insert entry", ex); - OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); - return; + OOError.fromMisc(ex).setTitle(errorTitle).showErrorDialog(dialogService); } finally { UnoUndo.leaveUndoContext(doc); } @@ -635,10 +618,10 @@ public void guiActionInsertEntry(List entries, */ public void guiActionMergeCitationGroups(List databases, OOBibStyle style) { - final String title = Localization.lang("Problem combining cite markers"); + final String errorTitle = Localization.lang("Problem combining cite markers"); OOResult odoc = getXTextDocument(); - if (testDialog(title, + if (testDialog(errorTitle, odoc.asVoidResult(), styleIsRequired(style), databaseIsRequired(databases, OOError::noDataBaseIsOpen))) { @@ -646,9 +629,9 @@ public void guiActionMergeCitationGroups(List databases, OOBibStyle } XTextDocument doc = odoc.get(); - OOResult fcursor = getFunctionalTextViewCursor(doc, title); + OOResult fcursor = getFunctionalTextViewCursor(doc, errorTitle); - if (testDialog(title, + if (testDialog(errorTitle, fcursor.asVoidResult(), checkStylesExistInTheDocument(style, doc), checkIfOpenOfficeIsRecordingChanges(doc))) { @@ -666,9 +649,9 @@ public void guiActionMergeCitationGroups(List databases, OOBibStyle Update.resyncDocument(doc, style, fcursor.get(), syncOptions); } } catch (NoDocumentException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + OOError.from(ex).setTitle(errorTitle).showErrorDialog(dialogService); } catch (DisposedException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + OOError.from(ex).setTitle(errorTitle).showErrorDialog(dialogService); } catch (CreationException | IllegalTypeException | NotRemoveableException @@ -676,7 +659,7 @@ public void guiActionMergeCitationGroups(List databases, OOBibStyle | WrappedTargetException | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn("Problem combining cite markers", ex); - OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + OOError.fromMisc(ex).setTitle(errorTitle).showErrorDialog(dialogService); } finally { UnoUndo.leaveUndoContext(doc); fcursor.get().restore(doc); @@ -690,10 +673,10 @@ public void guiActionMergeCitationGroups(List databases, OOBibStyle */ public void guiActionSeparateCitations(List databases, OOBibStyle style) { - final String title = Localization.lang("Problem during separating cite markers"); + final String errorTitle = Localization.lang("Problem during separating cite markers"); OOResult odoc = getXTextDocument(); - if (testDialog(title, + if (testDialog(errorTitle, odoc.asVoidResult(), styleIsRequired(style), databaseIsRequired(databases, OOError::noDataBaseIsOpen))) { @@ -701,9 +684,9 @@ public void guiActionSeparateCitations(List databases, OOBibStyle s } XTextDocument doc = odoc.get(); - OOResult fcursor = getFunctionalTextViewCursor(doc, title); + OOResult fcursor = getFunctionalTextViewCursor(doc, errorTitle); - if (testDialog(title, + if (testDialog(errorTitle, fcursor.asVoidResult(), checkStylesExistInTheDocument(style, doc), checkIfOpenOfficeIsRecordingChanges(doc))) { @@ -721,9 +704,9 @@ public void guiActionSeparateCitations(List databases, OOBibStyle s Update.resyncDocument(doc, style, fcursor.get(), syncOptions); } } catch (NoDocumentException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + OOError.from(ex).setTitle(errorTitle).showErrorDialog(dialogService); } catch (DisposedException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + OOError.from(ex).setTitle(errorTitle).showErrorDialog(dialogService); } catch (CreationException | IllegalTypeException | NotRemoveableException @@ -731,7 +714,7 @@ public void guiActionSeparateCitations(List databases, OOBibStyle s | WrappedTargetException | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn("Problem during separating cite markers", ex); - OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + OOError.fromMisc(ex).setTitle(errorTitle).showErrorDialog(dialogService); } finally { UnoUndo.leaveUndoContext(doc); fcursor.get().restore(doc); @@ -745,14 +728,13 @@ public void guiActionSeparateCitations(List databases, OOBibStyle s * * @param returnPartialResult If there are some unresolved keys, shall we return an otherwise nonempty result, or Optional.empty()? */ - public Optional exportCitedHelper(List databases, - boolean returnPartialResult) { + public Optional exportCitedHelper(List databases, boolean returnPartialResult) { final Optional FAIL = Optional.empty(); - final String title = Localization.lang("Unable to generate new library"); + final String errorTitle = Localization.lang("Unable to generate new library"); OOResult odoc = getXTextDocument(); - if (testDialog(title, + if (testDialog(errorTitle, odoc.asVoidResult(), databaseIsRequired(databases, OOError::noDataBaseIsOpenForExport))) { return FAIL; @@ -800,11 +782,11 @@ public Optional exportCitedHelper(List databases, } catch (NoDocumentException ex) { OOError.from(ex).showErrorDialog(dialogService); } catch (DisposedException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + OOError.from(ex).setTitle(errorTitle).showErrorDialog(dialogService); } catch (WrappedTargetException | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn("Problem generating new database.", ex); - OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + OOError.fromMisc(ex).setTitle(errorTitle).showErrorDialog(dialogService); } return FAIL; } @@ -817,12 +799,12 @@ public Optional exportCitedHelper(List databases, */ public void guiActionUpdateDocument(List databases, OOBibStyle style) { - final String title = Localization.lang("Unable to synchronize bibliography"); + final String errorTitle = Localization.lang("Unable to synchronize bibliography"); try { OOResult odoc = getXTextDocument(); - if (testDialog(title, + if (testDialog(errorTitle, odoc.asVoidResult(), styleIsRequired(style))) { return; @@ -830,9 +812,9 @@ public void guiActionUpdateDocument(List databases, OOBibStyle styl XTextDocument doc = odoc.get(); - OOResult fcursor = getFunctionalTextViewCursor(doc, title); + OOResult fcursor = getFunctionalTextViewCursor(doc, errorTitle); - if (testDialog(title, + if (testDialog(errorTitle, fcursor.asVoidResult(), checkStylesExistInTheDocument(style, doc), checkIfOpenOfficeIsRecordingChanges(doc))) { @@ -840,7 +822,7 @@ public void guiActionUpdateDocument(List databases, OOBibStyle styl } OOFrontend frontend = new OOFrontend(doc); - if (testDialog(title, checkRangeOverlaps(doc, frontend))) { + if (testDialog(errorTitle, checkRangeOverlaps(doc, frontend))) { return; } @@ -864,18 +846,17 @@ public void guiActionUpdateDocument(List databases, OOBibStyle styl "Your OpenOffice/LibreOffice document references the citation key '%0'," + " which could not be found in your current library.", unresolvedKeys.get(0)); - dialogService.showErrorDialogAndWait(title, msg); - return; + dialogService.showErrorDialogAndWait(errorTitle, msg); } } catch (NoDocumentException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + OOError.from(ex).setTitle(errorTitle).showErrorDialog(dialogService); } catch (DisposedException ex) { - OOError.from(ex).setTitle(title).showErrorDialog(dialogService); + OOError.from(ex).setTitle(errorTitle).showErrorDialog(dialogService); } catch (CreationException | WrappedTargetException | com.sun.star.lang.IllegalArgumentException ex) { LOGGER.warn("Could not update bibliography", ex); - OOError.fromMisc(ex).setTitle(title).showErrorDialog(dialogService); + OOError.fromMisc(ex).setTitle(errorTitle).showErrorDialog(dialogService); } } } diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java b/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java index d340eaf18ac..24660410fc3 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBaseConnect.java @@ -31,7 +31,6 @@ */ class OOBibBaseConnect { - /* variables */ private final DialogService dialogService; private final XDesktop xDesktop; @@ -42,9 +41,6 @@ class OOBibBaseConnect { */ private XTextDocument xTextDocument; - /* - * Constructor - */ public OOBibBaseConnect(Path loPath, DialogService dialogService) throws BootstrapException, diff --git a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java index a927a205442..dc2058a9107 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java +++ b/src/main/java/org/jabref/logic/openoffice/action/EditMerge.java @@ -36,7 +36,7 @@ public class EditMerge { private EditMerge() { } - /* + /** * @return true if modified document */ public static boolean mergeCitationGroups(XTextDocument doc, OOFrontend frontend, OOBibStyle style) @@ -121,8 +121,8 @@ private static class ScanState { // null if currentGroup.isEmpty() XTextCursor currentGroupCursor; - // A cursor starting at the end of the last CitationGroup in - // currentGroup. null if currentGroup.isEmpty() + // A cursor starting at the end of the last CitationGroup in currentGroup. + // null if currentGroup.isEmpty() XTextCursor cursorBetween; // The last element of currentGroup. diff --git a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java index a5a55fa5b18..4bdc11a7f71 100644 --- a/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java +++ b/src/main/java/org/jabref/logic/openoffice/action/ExportCited.java @@ -59,7 +59,6 @@ public static GenerateDatabaseResult generateDatabase(XTextDocument doc, List synchronizeDocument(XTextDocument doc, syncOptions.alwaysAddCitedOnPages); } - /* + /** * Reread document before sync */ public static List resyncDocument(XTextDocument doc, diff --git a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java index 7899bc21076..e433d18e72f 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java @@ -295,9 +295,6 @@ public CitationGroup createCitationGroup(XTextDocument doc, } } - /** - * - */ public List> combinePageInfos(List joinableGroup) { return combinePageInfosCommon(this.dataModel, joinableGroup); } @@ -369,7 +366,7 @@ public void cleanFillCursorForCitationGroup(CitationGroup group, XTextDocument d namedRange.cleanFillCursor(doc); } - public List getCitationEntries(XTextDocument doc, CitationGroups cgs) + public List getCitationEntries(XTextDocument doc, CitationGroups citationGroups) throws WrappedTargetException, NoDocumentException { @@ -378,8 +375,8 @@ public List getCitationEntries(XTextDocument doc, CitationGroups case JabRef52: // One context per CitationGroup: Backend52 (DataModel.JabRef52) // For DataModel.JabRef60 (Backend60) we need one context per Citation - List citations = new ArrayList<>(cgs.numberOfCitationGroups()); - for (CitationGroup group : cgs.getCitationGroupsUnordered()) { + List citations = new ArrayList<>(citationGroups.numberOfCitationGroups()); + for (CitationGroup group : citationGroups.getCitationGroupsUnordered()) { String name = group.groupId.citationGroupIdAsString(); XTextCursor cursor = (this .getRawCursorForCitationGroup(group, doc) @@ -401,7 +398,7 @@ public List getCitationEntries(XTextDocument doc, CitationGroups } } - /* + /** * Only applies to storage. Citation markers are not changed. */ public void applyCitationEntries(XTextDocument doc, List citationEntries) @@ -423,7 +420,7 @@ public void applyCitationEntries(XTextDocument doc, List citation } break; case JabRef60: - // xx + // ToDo: Implement throw new IllegalStateException("applyCitationEntries for JabRef60 is not implemented yet"); default: throw new IllegalStateException("applyCitationEntries: unhandled dataModel "); 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 0091367c7d8..e816b3bfa97 100644 --- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java +++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java @@ -17,8 +17,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -// was StorageBaseRefMark - class NamedRangeReferenceMark implements NamedRange { private static final String ZERO_WIDTH_SPACE = "\u200b"; diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java index bcf77852ec4..01470867257 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/OOFrontend.java @@ -244,13 +244,13 @@ public void removeCitationGroup(CitationGroup group, XTextDocument doc) this.citationGroups.afterRemoveCitationGroup(group); } - public void removeCitationGroups(List cgs, XTextDocument doc) + public void removeCitationGroups(List citationGroups, XTextDocument doc) throws WrappedTargetException, NoDocumentException, NotRemoveableException { - for (CitationGroup group : cgs) { + for (CitationGroup group : citationGroups) { removeCitationGroup(group, doc); } } 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 68b2aa565a7..99e71e13725 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java @@ -17,9 +17,6 @@ import com.sun.star.text.XTextDocument; import com.sun.star.text.XTextRange; -/* - * Update document: citation marks and bibliography - */ public class UpdateBibliography { private static final String BIB_SECTION_NAME = "JR_bib"; diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java index 0eee3bd6016..d61e0cd8e2e 100644 --- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateCitationMarkers.java @@ -22,9 +22,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/* - * Update document: citation marks and bibliography - */ public class UpdateCitationMarkers { private static final Logger LOGGER = LoggerFactory.getLogger(UpdateCitationMarkers.class); 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 2e5227d080e..e44b3ac9d3f 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java @@ -23,7 +23,6 @@ class OOBibStyleGetCitationMarker { private OOBibStyleGetCitationMarker() { - /**/ } /** diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java index 60b5222cf5b..28ef8ac12cf 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java @@ -12,13 +12,10 @@ class OOBibStyleGetNumCitationMarker { - /* - * The number encoding "this entry is unresolved" - */ + // The number encoding "this entry is unresolved" public final static int UNRESOLVED_ENTRY_NUMBER = 0; private OOBibStyleGetNumCitationMarker() { - /**/ } /** @@ -159,7 +156,6 @@ private static void emitBlock(List block, stringBuilder.append(block.get(j).getNumber().get()); } } - return; } } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java b/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java index ea311193068..38034693d16 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOFormatBibliography.java @@ -29,20 +29,20 @@ private OOFormatBibliography() { /** * @return The formatted bibliography, including its title. */ - public static OOText formatBibliography(CitationGroups cgs, + public static OOText formatBibliography(CitationGroups citationGroups, CitedKeys bibliography, OOBibStyle style, boolean alwaysAddCitedOnPages) { OOText title = style.getFormattedBibliographyTitle(); - OOText body = formatBibliographyBody(cgs, bibliography, style, alwaysAddCitedOnPages); + OOText body = formatBibliographyBody(citationGroups, bibliography, style, alwaysAddCitedOnPages); return OOText.fromString(title.toString() + body.toString()); } /** * @return Formatted body of the bibliography. Excludes the title. */ - public static OOText formatBibliographyBody(CitationGroups cgs, + public static OOText formatBibliographyBody(CitationGroups citationGroups, CitedKeys bibliography, OOBibStyle style, boolean alwaysAddCitedOnPages) { @@ -50,7 +50,7 @@ public static OOText formatBibliographyBody(CitationGroups cgs, StringBuilder stringBuilder = new StringBuilder(); for (CitedKey citedKey : bibliography.values()) { - OOText entryText = formatBibliographyEntry(cgs, citedKey, style, alwaysAddCitedOnPages); + OOText entryText = formatBibliographyEntry(citationGroups, citedKey, style, alwaysAddCitedOnPages); stringBuilder.append(entryText.toString()); } @@ -60,7 +60,7 @@ public static OOText formatBibliographyBody(CitationGroups cgs, /** * @return A paragraph. Includes label and "Cited on pages". */ - public static OOText formatBibliographyEntry(CitationGroups cgs, + public static OOText formatBibliographyEntry(CitationGroups citationGroups, CitedKey citedKey, OOBibStyle style, boolean alwaysAddCitedOnPages) { @@ -79,7 +79,7 @@ public static OOText formatBibliographyEntry(CitationGroups cgs, // Add "Cited on pages" if (citedKey.getLookupResult().isEmpty() || alwaysAddCitedOnPages) { - stringBuilder.append(formatCitedOnPages(cgs, citedKey).toString()); + stringBuilder.append(formatCitedOnPages(citationGroups, citedKey).toString()); } // Add paragraph @@ -154,9 +154,9 @@ private static OOText formatFullReferenceOfBibEntry(Layout layout, * - The links are created as references that show page numbers of the reference marks. * - We do not control the text shown, that is provided by OpenOffice. */ - private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey citedKey) { + private static OOText formatCitedOnPages(CitationGroups citationGroups, CitedKey citedKey) { - if (!cgs.citationGroupsProvideReferenceMarkNameForLinking()) { + if (!citationGroups.citationGroupsProvideReferenceMarkNameForLinking()) { return OOText.fromString(""); } @@ -166,25 +166,25 @@ private static OOText formatCitedOnPages(CitationGroups cgs, CitedKey citedKey) final String suffix = ")"; stringBuilder.append(prefix); - List citationGroups = new ArrayList<>(); - for (CitationPath p : citedKey.getCitationPaths()) { - CitationGroupId groupId = p.group; - Optional group = cgs.getCitationGroup(groupId); + List filteredList = new ArrayList<>(); + for (CitationPath path : citedKey.getCitationPaths()) { + CitationGroupId groupId = path.group; + Optional group = citationGroups.getCitationGroup(groupId); if (group.isEmpty()) { throw new IllegalStateException(); } - citationGroups.add(group.get()); + filteredList.add(group.get()); } // sort the citationGroups according to their indexInGlobalOrder - citationGroups.sort((a, b) -> { + filteredList.sort((a, b) -> { Integer aa = a.getIndexInGlobalOrder().orElseThrow(IllegalStateException::new); Integer bb = b.getIndexInGlobalOrder().orElseThrow(IllegalStateException::new); return (aa.compareTo(bb)); }); int index = 0; - for (CitationGroup group : citationGroups) { + for (CitationGroup group : filteredList) { if (index > 0) { stringBuilder.append(", "); } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOPreFormatter.java b/src/main/java/org/jabref/logic/openoffice/style/OOPreFormatter.java index dc02daf6ee9..caeaf8cce2a 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOPreFormatter.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOPreFormatter.java @@ -8,8 +8,7 @@ import org.jabref.model.strings.StringUtil; /** - * This formatter preprocesses JabRef fields before they are run through the layout of the - * bibliography style. It handles translation of LaTeX italic/bold commands into HTML tags. + * This formatter preprocesses JabRef fields before they are run through the layout of the bibliography style. It handles translation of LaTeX italic/bold commands into HTML tags. */ public class OOPreFormatter implements LayoutFormatter { @@ -46,7 +45,6 @@ public String format(String field) { currentCommand = new StringBuilder(); } else if (!incommand && ((c == '{') || (c == '}'))) { // Swallow braces, necessary for replacing encoded characters - } else if (Character.isLetter(c) || (c == '%') || StringUtil.SPECIAL_COMMAND_CHARS.contains(String.valueOf(c))) { escaped = false; @@ -88,10 +86,7 @@ public String format(String field) { if ((i + 1) == finalResult.length()) { String command = currentCommand.toString(); String result = OOPreFormatter.CHARS.get(command); - /* If found, then use translated version. If not, - * then keep - * the text of the parameter intact. - */ + // If found, then use translated version. If not, then keep the text of the parameter intact. sb.append(Objects.requireNonNullElse(result, command)); } } @@ -104,9 +99,7 @@ public String format(String field) { } else if (Character.isWhitespace(c) || (c == '{') || (c == '}')) { String command = currentCommand.toString(); - // Test if we are dealing with a formatting - // command. - // If so, handle. + // Test if we are dealing with a formatting command. If so, handle. String tag = getHTMLTag(command); if (!tag.isEmpty()) { String part = StringUtil.getPart(finalResult, i, true); @@ -118,14 +111,11 @@ public String format(String field) { argument = part; // handle common case of general latex command String result = OOPreFormatter.CHARS.get(command + argument); - // If found, then use translated version. If not, then keep - // the - // text of the parameter intact. + // If found, then use translated version. If not, then keep the text of the parameter intact. sb.append(Objects.requireNonNullElse(result, argument)); } 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: + // 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: String result = OOPreFormatter.CHARS.get(command); // If the command is unknown, just print it: sb.append(Objects.requireNonNullElse(result, command)); @@ -139,13 +129,10 @@ public String format(String field) { // argument = ""; } else { /* - * TODO: this point is reached, apparently, if a command is - * terminated in a strange way, such as with "$\omega$". - * Also, the command "\&" causes us to get here. The former - * issue is maybe a little difficult to address, since it - * involves the LaTeX math mode. We don't have a complete - * LaTeX parser, so maybe it's better to ignore these - * commands? + * TODO: this point is reached, apparently, if a command is terminated in a strange way, such as + * with "$\omega$". Also, the command "\&" causes us to get here. The former issue is maybe a + * little difficult to address, since it involves the LaTeX math mode. We don't have a complete + * LaTeX parser, so maybe it's better to ignore these commands? */ } @@ -160,44 +147,17 @@ public String format(String field) { private String getHTMLTag(String latexCommand) { String result = ""; switch (latexCommand) { - // Italic - case "textit": - case "it": - case "emph": // Should really separate between emphasized and italic but since in later stages both are converted to italic... - case "em": - result = "i"; - break; - // Bold font - case "textbf": - case "bf": - result = "b"; - break; - // Small capitals - case "textsc": - result = "smallcaps"; // Not a proper HTML tag, but used here for convenience - break; - // Underline - case "underline": - result = "u"; - break; - // Strikeout, sout is the "standard" command, although it is actually based on the package ulem - case "sout": - result = "s"; - break; - // Monospace font - case "texttt": - result = "tt"; - break; - // Superscript - case "textsuperscript": - result = "sup"; - break; - // Subscript - case "textsubscript": - result = "sub"; - break; - default: - break; + // Should really separate between emphasized and italic but since in later stages both are converted to italic... + case "textit", "it", "emph", "em" -> result = "i"; // Italic + case "textbf", "bf" -> result = "b"; // Bold font + case "textsc" -> result = "smallcaps"; // Small caps + // Not a proper HTML tag, but used here for convenience + case "underline" -> result = "u"; // Underline + case "sout" -> result = "s"; // Strikeout + // sout is the "standard" command, although it is actually based on the package ulem + case "texttt" -> result = "tt"; // Monospace font + case "textsuperscript" -> result = "sup"; // Superscript + case "textsubscript" -> result = "sub"; // Subscript } return result; } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java index f8f7de6c7b7..5fff6848133 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java @@ -16,7 +16,6 @@ public class OOProcess { static final Comparator YEAR_AUTHOR_TITLE_COMPARATOR = makeYearAuthorTitleComparator(); private OOProcess() { - /**/ } private static Comparator makeAuthorYearTitleComparator() { @@ -51,25 +50,25 @@ public static Comparator comparatorForMulticite(OOBibStyle style) { } /** - * Fill cgs.bibliography and cgs.citationGroupsUnordered//CitationMarker + * Fill citationGroups.bibliography and cgs.citationGroupsUnordered//CitationMarker * according to style. */ - public static void produceCitationMarkers(CitationGroups cgs, List databases, OOBibStyle style) { + public static void produceCitationMarkers(CitationGroups citationGroups, List databases, OOBibStyle style) { - if (!cgs.hasGlobalOrder()) { - throw new IllegalStateException("produceCitationMarkers: globalOrder is misssing in cgs"); + if (!citationGroups.hasGlobalOrder()) { + throw new IllegalStateException("produceCitationMarkers: globalOrder is misssing in citationGroups"); } - cgs.lookupCitations(databases); - cgs.imposeLocalOrder(comparatorForMulticite(style)); + citationGroups.lookupCitations(databases); + citationGroups.imposeLocalOrder(comparatorForMulticite(style)); // fill CitationGroup.citationMarker if (style.isCitationKeyCiteMarkers()) { - OOProcessCitationKeyMarkers.produceCitationMarkers(cgs, style); + OOProcessCitationKeyMarkers.produceCitationMarkers(citationGroups, style); } else if (style.isNumberEntries()) { - OOProcessNumericMarkers.produceCitationMarkers(cgs, style); + OOProcessNumericMarkers.produceCitationMarkers(citationGroups, style); } else { - OOProcessAuthorYearMarkers.produceCitationMarkers(cgs, style); + OOProcessAuthorYearMarkers.produceCitationMarkers(citationGroups, style); } } diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java index affbc7584ae..d01e3627104 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java @@ -22,7 +22,6 @@ class OOProcessAuthorYearMarkers { private OOProcessAuthorYearMarkers() { - /**/ } /** @@ -46,11 +45,11 @@ private static void createNormalizedCitationMarkers(CitedKeys sortedCitedKeys, O * Clears uniqueLetters before filling. * * On return: Each citedKey in sortedCitedKeys has uniqueLetter set as needed. - * The same values are copied to the corresponding citations in cgs. + * The same values are copied to the corresponding citations in citationGroups. * * Depends on: style, citations and their order. */ - private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroups cgs) { + private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroups citationGroups) { // The entries in the clashingKeys lists preserve // firstAppearance order from sortedCitedKeys.values(). @@ -93,7 +92,7 @@ private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroup nextUniqueLetter++; } } - sortedCitedKeys.distributeUniqueLetters(cgs); + sortedCitedKeys.distributeUniqueLetters(citationGroups); } /* *************************************** @@ -108,9 +107,9 @@ private static void createUniqueLetters(CitedKeys sortedCitedKeys, CitationGroup * * Preconditions: globalOrder, localOrder */ - private static void setIsFirstAppearanceOfSourceInCitations(CitationGroups cgs) { + private static void setIsFirstAppearanceOfSourceInCitations(CitationGroups citationGroups) { Set seenBefore = new HashSet<>(); - for (CitationGroup group : cgs.getCitationGroupsInGlobalOrder()) { + for (CitationGroup group : citationGroups.getCitationGroupsInGlobalOrder()) { for (Citation cit : group.getCitationsInLocalOrder()) { String currentKey = cit.citationKey; if (!seenBefore.contains(currentKey)) { @@ -127,25 +126,25 @@ private static void setIsFirstAppearanceOfSourceInCitations(CitationGroups cgs) * Produce citMarkers for normal * (!isCitationKeyCiteMarkers && !isNumberEntries) styles. * - * @param cgs + * @param citationGroups * @param style Bibliography style. */ - static void produceCitationMarkers(CitationGroups cgs, OOBibStyle style) { + static void produceCitationMarkers(CitationGroups citationGroups, OOBibStyle style) { assert !style.isCitationKeyCiteMarkers(); assert !style.isNumberEntries(); // Citations in (Au1, Au2 2000) form - CitedKeys citedKeys = cgs.getCitedKeysSortedInOrderOfAppearance(); + CitedKeys citedKeys = citationGroups.getCitedKeysSortedInOrderOfAppearance(); createNormalizedCitationMarkers(citedKeys, style); - createUniqueLetters(citedKeys, cgs); - cgs.createPlainBibliographySortedByComparator(OOProcess.AUTHOR_YEAR_TITLE_COMPARATOR); + createUniqueLetters(citedKeys, citationGroups); + citationGroups.createPlainBibliographySortedByComparator(OOProcess.AUTHOR_YEAR_TITLE_COMPARATOR); // Mark first appearance of each citationKey - setIsFirstAppearanceOfSourceInCitations(cgs); + setIsFirstAppearanceOfSourceInCitations(citationGroups); - for (CitationGroup group : cgs.getCitationGroupsInGlobalOrder()) { + for (CitationGroup group : citationGroups.getCitationGroupsInGlobalOrder()) { final boolean inParenthesis = (group.citationType == CitationType.AUTHORYEAR_PAR); final NonUniqueCitationMarker strictlyUnique = NonUniqueCitationMarker.THROWS; diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java index 5329d9ca021..16fe8279123 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessCitationKeyMarkers.java @@ -11,20 +11,19 @@ class OOProcessCitationKeyMarkers { private OOProcessCitationKeyMarkers() { - /**/ } /** * Produce citation markers for the case when the citation * markers are the citation keys themselves, separated by commas. */ - static void produceCitationMarkers(CitationGroups cgs, OOBibStyle style) { + static void produceCitationMarkers(CitationGroups citationGroups, OOBibStyle style) { assert style.isCitationKeyCiteMarkers(); - cgs.createPlainBibliographySortedByComparator(OOProcess.AUTHOR_YEAR_TITLE_COMPARATOR); + citationGroups.createPlainBibliographySortedByComparator(OOProcess.AUTHOR_YEAR_TITLE_COMPARATOR); - for (CitationGroup group : cgs.getCitationGroupsInGlobalOrder()) { + for (CitationGroup group : citationGroups.getCitationGroupsInGlobalOrder()) { String citMarker = style.getCitationGroupMarkupBefore() + String.join(",", OOListUtil.map(group.getCitationsInLocalOrder(), Citation::getCitationKey)) diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java b/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java index deddab66cca..3a6396817e6 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOProcessNumericMarkers.java @@ -12,7 +12,6 @@ class OOProcessNumericMarkers { private OOProcessNumericMarkers() { - /**/ } /** @@ -23,21 +22,21 @@ private OOProcessNumericMarkers() { * Numbering is according to first appearance. * Assumes global order and local order are already applied. * - * @param cgs + * @param citationGroups * @param style * */ - static void produceCitationMarkers(CitationGroups cgs, OOBibStyle style) { + static void produceCitationMarkers(CitationGroups citationGroups, OOBibStyle style) { assert style.isNumberEntries(); if (style.isSortByPosition()) { - cgs.createNumberedBibliographySortedInOrderOfAppearance(); + citationGroups.createNumberedBibliographySortedInOrderOfAppearance(); } else { - cgs.createNumberedBibliographySortedByComparator(OOProcess.AUTHOR_YEAR_TITLE_COMPARATOR); + citationGroups.createNumberedBibliographySortedByComparator(OOProcess.AUTHOR_YEAR_TITLE_COMPARATOR); } - for (CitationGroup group : cgs.getCitationGroupsInGlobalOrder()) { + for (CitationGroup group : citationGroups.getCitationGroupsInGlobalOrder()) { List cits = OOListUtil.map(group.getCitationsInLocalOrder(), e -> e); OOText citMarker = style.getNumCitationMarker2(cits); group.setCitationMarker(Optional.of(citMarker)); diff --git a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java index 6ed9dedebc1..bbe77c33e04 100644 --- a/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java +++ b/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java @@ -447,9 +447,7 @@ static class MyPropertyStack { XPropertySet propertySet = UnoCast.cast(XPropertySet.class, cursor).get(); XPropertySetInfo propertySetInfo = propertySet.getPropertySetInfo(); - /* - * On creation, initialize the property name -- index mapping. - */ + // On creation, initialize the property name -- index mapping. this.goodNameToIndex = new HashMap<>(); int nextIndex = 0; for (Property p : propertySetInfo.getProperties()) { @@ -470,16 +468,13 @@ static class MyPropertyStack { goodNames[entry.getValue()] = entry.getKey(); } - // XMultiPropertySet.setPropertyValues() requires alphabetically sorted property names. - // We adjust here: + // XMultiPropertySet.setPropertyValues() requires alphabetically sorted property names. We adjust here: Arrays.sort(goodNames); for (int i = 0; i < goodSize; i++) { this.goodNameToIndex.put(goodNames[i], i); } - /* - * Get the initial state of the properties and add the first layer. - */ + // Get the initial state of the properties and add the first layer. XMultiPropertyStates mpss = UnoCast.cast(XMultiPropertyStates.class, cursor).get(); PropertyState[] propertyStates; try { @@ -602,10 +597,8 @@ private static List> parseAttributes(String attributes) { return res; } - /* - * We rely on property values being either DIRECT_VALUE or DEFAULT_VALUE (not - * AMBIGUOUS_VALUE). If the cursor covers a homogeneous region, or is collapsed, then this is - * true. + /** + * We rely on property values being either DIRECT_VALUE or DEFAULT_VALUE (not AMBIGUOUS_VALUE). If the cursor covers a homogeneous region, or is collapsed, then this is true. */ private static boolean isPropertyDefault(XTextCursor cursor, String propertyName) throws @@ -744,7 +737,7 @@ private static List> setSuperScript(MyPropertyStack forma formatStack); } - /* + /** * @return true on failure */ public static boolean setParagraphStyle(XTextCursor cursor, String paragraphStyle) { diff --git a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java index 0ed686ee901..a9b834027ff 100644 --- a/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java +++ b/src/main/java/org/jabref/model/openoffice/rangesort/RangeSortEntry.java @@ -9,7 +9,7 @@ public class RangeSortEntry implements RangeSortable { private XTextRange range; private int indexInPosition; - private T content; + private final T content; public RangeSortEntry(XTextRange range, int indexInPosition, T content) { this.range = range; diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java index 30831035533..30cfbdd512e 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroup.java @@ -28,10 +28,6 @@ public class CitationGroup { public final CitationType citationType; public final List citationsInStorageOrder; - /* - * Extra data - */ - /* * A name of a reference mark to link to by formatCitedOnPages. * May be initially empty, if backend does not use reference marks. diff --git a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java index 226867ad274..68dcd714974 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitationGroups.java @@ -258,7 +258,7 @@ public Optional getCitationGroup(CitationGroupId groupId) { return Optional.ofNullable(group); } - /* + /** * @return true if all citation groups have referenceMarkNameForLinking */ public boolean citationGroupsProvideReferenceMarkNameForLinking() { diff --git a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java index 8e5950d9d04..cd3dc74684e 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitedKey.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitedKey.java @@ -119,19 +119,19 @@ void lookupInDatabases(List databases) { this.db = Citation.lookup(databases, this.citationKey); } - void distributeLookupResult(CitationGroups cgs) { - cgs.distributeToCitations(where, Citation::setLookupResult, db); + void distributeLookupResult(CitationGroups citationGroups) { + citationGroups.distributeToCitations(where, Citation::setLookupResult, db); } /* * Make unique using a letter or by numbering */ - void distributeNumber(CitationGroups cgs) { - cgs.distributeToCitations(where, Citation::setNumber, number); + void distributeNumber(CitationGroups citationGroups) { + citationGroups.distributeToCitations(where, Citation::setNumber, number); } - void distributeUniqueLetter(CitationGroups cgs) { - cgs.distributeToCitations(where, Citation::setUniqueLetter, uniqueLetter); + void distributeUniqueLetter(CitationGroups citationGroups) { + citationGroups.distributeToCitations(where, Citation::setUniqueLetter, uniqueLetter); } } diff --git a/src/main/java/org/jabref/model/openoffice/style/CitedKeys.java b/src/main/java/org/jabref/model/openoffice/style/CitedKeys.java index 059c1b6123a..7b95d1ece19 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CitedKeys.java +++ b/src/main/java/org/jabref/model/openoffice/style/CitedKeys.java @@ -63,21 +63,21 @@ public void lookupInDatabases(List databases) { } } - void distributeLookupResults(CitationGroups cgs) { + void distributeLookupResults(CitationGroups citationGroups) { for (CitedKey ck : this.data.values()) { - ck.distributeLookupResult(cgs); + ck.distributeLookupResult(citationGroups); } } - void distributeNumbers(CitationGroups cgs) { + void distributeNumbers(CitationGroups citationGroups) { for (CitedKey ck : this.data.values()) { - ck.distributeNumber(cgs); + ck.distributeNumber(citationGroups); } } - public void distributeUniqueLetters(CitationGroups cgs) { + public void distributeUniqueLetters(CitationGroups citationGroups) { for (CitedKey ck : this.data.values()) { - ck.distributeUniqueLetter(cgs); + ck.distributeUniqueLetter(citationGroups); } } diff --git a/src/main/java/org/jabref/model/openoffice/style/CompareCitation.java b/src/main/java/org/jabref/model/openoffice/style/CompareCitation.java index 966715b11a8..1d27674ba1d 100644 --- a/src/main/java/org/jabref/model/openoffice/style/CompareCitation.java +++ b/src/main/java/org/jabref/model/openoffice/style/CompareCitation.java @@ -10,7 +10,7 @@ */ public class CompareCitation implements Comparator { - private CompareCitedKey citedKeyComparator; + private final CompareCitedKey citedKeyComparator; CompareCitation(Comparator entryComparator, boolean unresolvedComesFirst) { this.citedKeyComparator = new CompareCitedKey(entryComparator, unresolvedComesFirst); diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java b/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java index 74ea8aaa812..80ea0c11c80 100644 --- a/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java +++ b/src/main/java/org/jabref/model/openoffice/uno/UnoProperties.java @@ -22,18 +22,10 @@ public class UnoProperties { private UnoProperties() { } - /* - * asPropertySet - */ - public static Optional asPropertySet(XPropertyContainer propertyContainer) { return UnoCast.cast(XPropertySet.class, propertyContainer); } - /* - * getPropertySetInfo - */ - public static Optional getPropertySetInfo(XPropertySet propertySet) { return (Optional.ofNullable(propertySet) .flatMap(e -> Optional.ofNullable(e.getPropertySetInfo()))); @@ -43,10 +35,6 @@ public static Optional getPropertySetInfo(XPropertyContainer p return Optional.ofNullable(propertyContainer).flatMap(UnoProperties::getPropertySetInfo); } - /* - * getPropertyNames - */ - public static List getPropertyNames(Property[] properties) { Objects.requireNonNull(properties); return (Arrays.stream(properties) @@ -68,10 +56,6 @@ public static List getPropertyNames(XPropertyContainer propertyContainer .orElse(new ArrayList<>())); } - /* - * getPropertyValue - */ - public static Optional getValueAsObject(XPropertySet propertySet, String property) throws WrappedTargetException { diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 2aba054b1ed..32080f04d8a 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -1587,7 +1587,7 @@ Custom=Custom Export\ cited=Export cited Unable\ to\ generate\ new\ library=Unable to generate new library -The\ cursor\ is\ in\ protected\ area.=The cursor is in protected area. +The\ cursor\ is\ in\ a\ protected\ area.=The cursor is in a protected area. JabRefException=JabRefException No\ bibliography\ database\ is\ open\ for\ citation.=No bibliography database is open for citation. diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java index fb4514f8410..fe5d42f79f8 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java @@ -688,7 +688,7 @@ void testGetCitationMarkerJoinFirst() throws IOException { OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH, layoutFormatterPreferences); - // Question: What should happen if some of the sources is + // Question: What should happen if some sources are // marked as isFirstAppearanceOfSource? // This test documents what is happening now. diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java index 9bf8d148a70..4ab0c6ef5d3 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTestHelper.java @@ -22,10 +22,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; class OOBibStyleTestHelper { - /* - * begin Helpers for testing style.getNumCitationMarker2 - */ - /* * Minimal implementation for CitationMarkerNumericEntry */ From c881e09411c115cc22354e16c4606f2926110dd2 Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Date: Fri, 11 Mar 2022 21:58:59 +0100 Subject: [PATCH 103/103] Changed File to Path Co-authored-by: Christoph --- .../org/jabref/gui/openoffice/OOBibBase.java | 2 +- .../gui/openoffice/OpenOfficePanel.java | 2 +- .../logic/openoffice/style/OOBibStyle.java | 22 +++++++++++-------- .../logic/openoffice/style/StyleLoader.java | 6 ++--- .../openoffice/style/OOBibStyleTest.java | 5 ++--- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/jabref/gui/openoffice/OOBibBase.java b/src/main/java/org/jabref/gui/openoffice/OOBibBase.java index e8e7f50205d..5ad5e2634c8 100644 --- a/src/main/java/org/jabref/gui/openoffice/OOBibBase.java +++ b/src/main/java/org/jabref/gui/openoffice/OOBibBase.java @@ -270,7 +270,7 @@ private static OOVoidResult checkIfOpenOfficeIsRecordingChanges(XTextDo try { boolean recordingChanges = UnoRedlines.getRecordChanges(doc); int nRedlines = UnoRedlines.countRedlines(doc); - if (recordingChanges || nRedlines > 0) { + if (recordingChanges || (nRedlines > 0)) { String msg = ""; if (recordingChanges) { msg += Localization.lang("Cannot work with" diff --git a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java index 2b92f52e116..65bf4941713 100644 --- a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java +++ b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java @@ -433,7 +433,7 @@ private void pushEntries(CitationType citationType, boolean addPageInfo) { final String errorDialogTitle = Localization.lang("Error pushing entries"); if (stateManager.getActiveDatabase().isEmpty() - || stateManager.getActiveDatabase().get().getDatabase() == null) { + || (stateManager.getActiveDatabase().get().getDatabase() == null)) { OOError.noDataBaseIsOpenForCiting() .setTitle(errorDialogTitle) .showErrorDialog(dialogService); diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java index 195ddc25410..885d51549e2 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java +++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java @@ -1,7 +1,5 @@ package org.jabref.logic.openoffice.style; -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -9,6 +7,8 @@ import java.io.StringReader; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -136,12 +136,12 @@ public class OOBibStyle implements Comparable { private String name = ""; private Layout defaultBibLayout; private boolean valid; - private File styleFile; + private Path styleFile; private long styleFileModificationTime = Long.MIN_VALUE; private String localCopy; private boolean isDefaultLayoutPresent; - public OOBibStyle(File styleFile, LayoutFormatterPreferences prefs, + public OOBibStyle(Path styleFile, LayoutFormatterPreferences prefs, Charset encoding) throws IOException { this.prefs = Objects.requireNonNull(prefs); this.styleFile = Objects.requireNonNull(styleFile); @@ -149,7 +149,7 @@ public OOBibStyle(File styleFile, LayoutFormatterPreferences prefs, setDefaultProperties(); reload(); fromResource = false; - path = styleFile.getPath(); + path = styleFile.toAbsolutePath().toString(); } public OOBibStyle(String resourcePath, LayoutFormatterPreferences prefs) throws IOException { @@ -227,7 +227,7 @@ public String getPath() { return path; } - public File getFile() { + public Path getFile() { return styleFile; } @@ -263,8 +263,8 @@ public void ensureUpToDate() throws IOException { */ private void reload() throws IOException { if (styleFile != null) { - this.styleFileModificationTime = styleFile.lastModified(); - try (InputStream stream = new FileInputStream(styleFile)) { + this.styleFileModificationTime = Files.getLastModifiedTime(styleFile).toMillis(); + try (InputStream stream = Files.newInputStream(styleFile )) { initialize(stream); } } @@ -280,7 +280,11 @@ private boolean isUpToDate() { if (styleFile == null) { return true; } else { - return styleFile.lastModified() == this.styleFileModificationTime; + try { + return Files.getLastModifiedTime(styleFile).toMillis() == this.styleFileModificationTime; + } catch (IOException e) { + return false; + } } } diff --git a/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java b/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java index 3098e06233c..6fb9cf4f566 100644 --- a/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java +++ b/src/main/java/org/jabref/logic/openoffice/style/StyleLoader.java @@ -1,9 +1,9 @@ package org.jabref.logic.openoffice.style; -import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.charset.Charset; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -59,7 +59,7 @@ public List getStyles() { public boolean addStyleIfValid(String filename) { Objects.requireNonNull(filename); try { - OOBibStyle newStyle = new OOBibStyle(new File(filename), layoutFormatterPreferences, encoding); + OOBibStyle newStyle = new OOBibStyle(Path.of(filename), layoutFormatterPreferences, encoding); if (externalStyles.contains(newStyle)) { LOGGER.info("External style file {} already existing.", filename); } else if (newStyle.isValid()) { @@ -84,7 +84,7 @@ private void loadExternalStyles() { List lists = openOfficePreferences.getExternalStyles(); for (String filename : lists) { try { - OOBibStyle style = new OOBibStyle(new File(filename), layoutFormatterPreferences, encoding); + OOBibStyle style = new OOBibStyle(Path.of(filename), layoutFormatterPreferences, encoding); if (style.isValid()) { // Problem! externalStyles.add(style); } else { diff --git a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java index fe5d42f79f8..3acfecafbe6 100644 --- a/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java +++ b/src/test/java/org/jabref/logic/openoffice/style/OOBibStyleTest.java @@ -1,6 +1,5 @@ package org.jabref.logic.openoffice.style; -import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; @@ -61,8 +60,8 @@ void testAuthorYear() throws IOException { @Test void testAuthorYearAsFile() throws URISyntaxException, IOException { - File defFile = Path.of(OOBibStyleTest.class.getResource(StyleLoader.DEFAULT_AUTHORYEAR_STYLE_PATH).toURI()) - .toFile(); + Path defFile = Path.of(OOBibStyleTest.class.getResource(StyleLoader.DEFAULT_AUTHORYEAR_STYLE_PATH).toURI()); + OOBibStyle style = new OOBibStyle(defFile, layoutFormatterPreferences, StandardCharsets.UTF_8); assertTrue(style.isValid()); assertFalse(style.isInternalStyle());