Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ set(ODR_SOURCE_FILES
"src/odr/internal/common/file.cpp"
"src/odr/internal/common/filesystem.cpp"
"src/odr/internal/common/image_file.cpp"
"src/odr/internal/common/list_numbering.cpp"
"src/odr/internal/common/media_file.cpp"
"src/odr/internal/common/path.cpp"
"src/odr/internal/common/random.cpp"
Expand Down Expand Up @@ -155,6 +156,7 @@ set(ODR_SOURCE_FILES
"src/odr/internal/odf/odf_document.cpp"
"src/odr/internal/odf/odf_element_registry.cpp"
"src/odr/internal/odf/odf_file.cpp"
"src/odr/internal/odf/odf_list.cpp"
"src/odr/internal/odf/odf_manifest.cpp"
"src/odr/internal/odf/odf_meta.cpp"
"src/odr/internal/odf/odf_parser.cpp"
Expand Down Expand Up @@ -187,6 +189,7 @@ set(ODR_SOURCE_FILES
"src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_style.cpp"
"src/odr/internal/ooxml/text/ooxml_text_document.cpp"
"src/odr/internal/ooxml/text/ooxml_text_element_registry.cpp"
"src/odr/internal/ooxml/text/ooxml_text_list.cpp"
"src/odr/internal/ooxml/text/ooxml_text_parser.cpp"
"src/odr/internal/ooxml/text/ooxml_text_style.cpp"
"src/odr/internal/ooxml/ooxml_crypto.cpp"
Expand Down
16 changes: 16 additions & 0 deletions apple/include/OdrCoreObjC/ODRDocumentElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ NS_ASSUME_NONNULL_BEGIN

@class ODRFile;

typedef NS_ENUM(NSInteger, ODRListType) {
ODRListTypeUnordered,
ODRListTypeOrdered,
} NS_SWIFT_NAME(ListType);

typedef NS_ENUM(NSInteger, ODRElementType) {
ODRElementTypeNone = 0,

Expand Down Expand Up @@ -195,10 +200,21 @@ NS_SWIFT_NAME(Bookmark)
@property(nonatomic, readonly, copy) NSString *name;
@end

/// `odr::List`.
NS_SWIFT_NAME(List)
@interface ODRList : ODRElement
/// Named apart from `ODRElement.type`, which every element answers.
@property(nonatomic, readonly) ODRListType listType;
@end

/// `odr::ListItem`.
NS_SWIFT_NAME(ListItem)
@interface ODRListItem : ODRElement
@property(nonatomic, readonly) ODRTextStyle *style;
/// The resolved label, or empty where the list style asks for none.
@property(nonatomic, readonly, copy) NSString *marker;
/// The counter behind `marker`, `nil` for an unordered item.
@property(nonatomic, readonly, nullable) NSNumber *number;
@end

/// `odr::Table`.
Expand Down
34 changes: 34 additions & 0 deletions apple/src/ODRDocumentElement.mm
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
ODR_SAME_ENUM(ODRElementTypeSpan, odr::ElementType::span);
ODR_SAME_ENUM(ODRElementTypeLink, odr::ElementType::link);
ODR_SAME_ENUM(ODRElementTypeBookmark, odr::ElementType::bookmark);
ODR_SAME_ENUM(ODRListTypeUnordered, odr::ListType::unordered);
ODR_SAME_ENUM(ODRListTypeOrdered, odr::ListType::ordered);

ODR_SAME_ENUM(ODRElementTypeList, odr::ElementType::list);
ODR_SAME_ENUM(ODRElementTypeListItem, odr::ElementType::list_item);
ODR_SAME_ENUM(ODRElementTypeTable, odr::ElementType::table);
Expand Down Expand Up @@ -127,6 +130,9 @@ + (nullable ODRElement *)elementWithHandle:(odr::Element)handle
case odr::ElementType::bookmark:
klass = [ODRBookmark class];
break;
case odr::ElementType::list:
klass = [ODRList class];
break;
case odr::ElementType::list_item:
klass = [ODRListItem class];
break;
Expand Down Expand Up @@ -540,6 +546,16 @@ - (NSString *)name {

@end

@implementation ODRList

- (ODRListType)listType {
return guarded_value(
[&] { return static_cast<ODRListType>(self.handle.as_list().type()); },
ODRListTypeUnordered);
}

@end

@implementation ODRListItem

- (ODRTextStyle *)style {
Expand All @@ -551,6 +567,24 @@ - (ODRTextStyle *)style {
nil);
}

- (NSString *)marker {
return guarded_value(
[&]() -> NSString * {
return to_nsstring(self.handle.as_list_item().marker());
},
@"");
}

- (nullable NSNumber *)number {
return guarded_value(
[&]() -> NSNumber * {
const std::optional<std::uint32_t> number =
self.handle.as_list_item().number();
return number.has_value() ? @(*number) : nil;
},
nil);
}

@end

@implementation ODRTable
Expand Down
2 changes: 2 additions & 0 deletions jni/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ add_jar(odr_java
"java/app/opendocument/core/Line.java"
"java/app/opendocument/core/LineBreak.java"
"java/app/opendocument/core/Link.java"
"java/app/opendocument/core/ListElement.java"
"java/app/opendocument/core/ListItem.java"
"java/app/opendocument/core/ListType.java"
"java/app/opendocument/core/MasterPage.java"
"java/app/opendocument/core/Measure.java"
"java/app/opendocument/core/NativeLibrary.java"
Expand Down
7 changes: 7 additions & 0 deletions jni/java/app/opendocument/core/Element.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ public Bookmark asBookmark() {
return h == 0 ? null : new Bookmark(h, owner());
}

public ListElement asList() {
long h = asListNative(handle());
return h == 0 ? null : new ListElement(h, owner());
}

public ListItem asListItem() {
long h = asListItemNative(handle());
return h == 0 ? null : new ListItem(h, owner());
Expand Down Expand Up @@ -251,6 +256,8 @@ final List<Element> wrapAll(long[] handles) {

private native long asBookmarkNative(long handle);

private native long asListNative(long handle);

private native long asListItemNative(long handle);

private native long asTableNative(long handle);
Expand Down
15 changes: 15 additions & 0 deletions jni/java/app/opendocument/core/ListElement.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package app.opendocument.core;

/** List element. Mirrors {@code odr::List}; named apart from {@code java.util.List}. */
public final class ListElement extends Element {
ListElement(long handle, Object owner) {
super(handle, owner);
}

/** Named apart from {@link Element#type}, which every element answers. */
public ListType listType() {
return ListType.fromNative(listTypeNative(handle()));
}

private native int listTypeNative(long handle);
}
14 changes: 14 additions & 0 deletions jni/java/app/opendocument/core/ListItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,19 @@ public TextStyle style() {
return styleNative(handle());
}

/** The resolved label, or empty where the list style asks for none. */
public String marker() {
return markerNative(handle());
}

/** The counter behind {@link #marker}, {@code null} for an unordered item. */
public Integer number() {
return numberNative(handle());
}

private native TextStyle styleNative(long handle);

private native String markerNative(long handle);

private native Integer numberNative(long handle);
}
14 changes: 14 additions & 0 deletions jni/java/app/opendocument/core/ListType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package app.opendocument.core;

/** Mirrors {@code odr::ListType}; constant order must match the C++ declaration. */
public enum ListType {
UNORDERED, ORDERED;

static ListType fromNative(int code) {
return code < 0 ? null : values()[code];
}

int toNative() {
return ordinal();
}
}
32 changes: 32 additions & 0 deletions jni/src/jni_document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ ODR_JNI_ELEMENT_AS(Span, as_span)
ODR_JNI_ELEMENT_AS(Text, as_text)
ODR_JNI_ELEMENT_AS(Link, as_link)
ODR_JNI_ELEMENT_AS(Bookmark, as_bookmark)
ODR_JNI_ELEMENT_AS(List, as_list)
ODR_JNI_ELEMENT_AS(ListItem, as_list_item)
ODR_JNI_ELEMENT_AS(Table, as_table)
ODR_JNI_ELEMENT_AS(TableColumn, as_table_column)
Expand Down Expand Up @@ -608,6 +609,15 @@ Java_app_opendocument_core_Bookmark_nameNative(JNIEnv *env, jobject,
});
}

// app.opendocument.core.ListElement

extern "C" JNIEXPORT jint JNICALL
Java_app_opendocument_core_ListElement_listTypeNative(JNIEnv *env, jobject,
jlong handle) {
return guarded(
env, [&] { return static_cast<jint>(element(handle).as_list().type()); });
}

// app.opendocument.core.ListItem

extern "C" JNIEXPORT jobject JNICALL
Expand All @@ -619,6 +629,28 @@ Java_app_opendocument_core_ListItem_styleNative(JNIEnv *env, jobject,
});
}

extern "C" JNIEXPORT jstring JNICALL
Java_app_opendocument_core_ListItem_markerNative(JNIEnv *env, jobject,
jlong handle) {
return guarded(env, [&] {
return to_jstring(env, element(handle).as_list_item().marker());
});
}

extern "C" JNIEXPORT jobject JNICALL
Java_app_opendocument_core_ListItem_numberNative(JNIEnv *env, jobject,
jlong handle) {
return guarded(env, [&] {
std::optional<std::int32_t> number;
if (const std::optional<std::uint32_t> value =
element(handle).as_list_item().number();
value.has_value()) {
number = static_cast<std::int32_t>(*value);
}
return odr_jni::make_integer_opt(env, number);
});
}

// app.opendocument.core.Table

extern "C" JNIEXPORT jlong JNICALL
Expand Down
11 changes: 10 additions & 1 deletion python/src/bind_document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ void odr_python::bind_document(py::module_ &m) {
.value("at_page", odr::AnchorType::at_page)
.value("at_paragraph", odr::AnchorType::at_paragraph);

py::enum_<odr::ListType>(m, "ListType")
.value("unordered", odr::ListType::unordered)
.value("ordered", odr::ListType::ordered);

py::enum_<odr::ValueType>(m, "ValueType")
.value("unknown", odr::ValueType::unknown)
.value("string", odr::ValueType::string)
Expand Down Expand Up @@ -160,6 +164,7 @@ void odr_python::bind_document(py::module_ &m) {
.def("as_span", &odr::Element::as_span, keep_self_alive)
.def("as_text", &odr::Element::as_text, keep_self_alive)
.def("as_link", &odr::Element::as_link, keep_self_alive)
.def("as_list", &odr::Element::as_list, keep_self_alive)
.def("as_bookmark", &odr::Element::as_bookmark, keep_self_alive)
.def("as_list_item", &odr::Element::as_list_item, keep_self_alive)
.def("as_table", &odr::Element::as_table, keep_self_alive)
Expand Down Expand Up @@ -234,8 +239,12 @@ void odr_python::bind_document(py::module_ &m) {

bind_element<odr::Bookmark>(m, "Bookmark").def("name", &odr::Bookmark::name);

bind_element<odr::List>(m, "List").def("list_type", &odr::List::type);

bind_element<odr::ListItem>(m, "ListItem")
.def("style", &odr::ListItem::style, keep_self_alive);
.def("style", &odr::ListItem::style, keep_self_alive)
.def("marker", &odr::ListItem::marker)
.def("number", &odr::ListItem::number);

bind_element<odr::Table>(m, "Table")
.def("first_row", &odr::Table::first_row, keep_self_alive)
Expand Down
17 changes: 17 additions & 0 deletions python/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,29 @@
ODT_CONTENT_XML = """<?xml version="1.0" encoding="UTF-8"?>
<office:document-content
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
office:version="1.2">
<office:automatic-styles>
<text:list-style style:name="Bullets">
<text:list-level-style-bullet text:level="1" text:bullet-char="β€’"/>
</text:list-style>
<text:list-style style:name="Numbers">
<text:list-level-style-number text:level="1" style:num-format="1"
style:num-suffix="."/>
</text:list-style>
</office:automatic-styles>
<office:body>
<office:text>
<text:p>Hello from pyodr!</text:p>
<text:p>Second paragraph</text:p>
<text:list text:style-name="Bullets">
<text:list-item><text:p>Bulleted</text:p></text:list-item>
</text:list>
<text:list text:style-name="Numbers">
<text:list-item><text:p>First</text:p></text:list-item>
<text:list-item><text:p>Second</text:p></text:list-item>
</text:list>
</office:text>
</office:body>
</office:document-content>
Expand Down
24 changes: 24 additions & 0 deletions python/tests/test_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,27 @@ def test_document_filesystem(odt_path):
document = pyodr.open(str(odt_path)).as_document_file().document()
filesystem = document.as_filesystem()
assert filesystem.is_file("/content.xml")


def test_list_markers(odt_path):
document = pyodr.open(str(odt_path)).as_document_file().document()

lists = [
child
for child in document.root_element().children()
if child.type() == pyodr.ElementType.list
]
assert len(lists) == 2

bullets, numbers = (element.as_list() for element in lists)
assert bullets.list_type() == pyodr.ListType.unordered
assert numbers.list_type() == pyodr.ListType.ordered

def items(element):
return [child.as_list_item() for child in element.children()]

assert [item.marker() for item in items(lists[0])] == ["β€’"]
assert [item.number() for item in items(lists[0])] == [None]

assert [item.marker() for item in items(lists[1])] == ["1.", "2."]
assert [item.number() for item in items(lists[1])] == [1, 2]
19 changes: 19 additions & 0 deletions src/odr/document_element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,13 @@ Bookmark Element::as_bookmark() const {
return {m_adapter, m_identifier, m_adapter->bookmark_adapter(m_identifier)};
}

List Element::as_list() const {
if (!exists_()) {
return {};
}
return {m_adapter, m_identifier, m_adapter->list_adapter(m_identifier)};
}

ListItem Element::as_list_item() const {
if (!exists_()) {
return {};
Expand Down Expand Up @@ -456,10 +463,22 @@ std::string Bookmark::name() const {
return exists_() ? m_adapter2->bookmark_name(m_identifier) : "";
}

ListType List::type() const {
return exists_() ? m_adapter2->list_type(m_identifier) : ListType::unordered;
}

TextStyle ListItem::style() const {
return exists_() ? m_adapter2->list_item_style(m_identifier) : TextStyle();
}

std::string ListItem::marker() const {
return exists_() ? m_adapter2->list_item_marker(m_identifier) : "";
}

std::optional<std::uint32_t> ListItem::number() const {
return exists_() ? m_adapter2->list_item_number(m_identifier) : std::nullopt;
}

TableRow Table::first_row() const {
if (!exists_()) {
return {};
Expand Down
Loading
Loading