spreadsheet_ods/text.rs
1//! Text is stored as a simple String whenever possible.
2//! When there is a more complex structure, a TextTag is constructed
3//! which mirrors the Xml tree structure.
4//!
5//! For construction of a new TextTag structure a few helper structs are
6//! defined.
7//!
8//! ```
9//! use spreadsheet_ods::text::{TextP, TextTag, MetaAuthorName, MetaCreationDate, TextS};
10//! use spreadsheet_ods::style::ParagraphStyleRef;
11//!
12//! let p1_ref = ParagraphStyleRef::from("p1");
13//!
14//! let txt = TextP::new()
15//! .style_name(&p1_ref)
16//! .text("some text")
17//! .tag(MetaAuthorName::new())
18//! .tag(TextS::new())
19//! .tag(MetaCreationDate::new())
20//! .tag(TextS::new())
21//! .text("whatever");
22//! println!("{}", txt.into_xmltag());
23//! ```
24//!
25
26use crate::style::{ParagraphStyleRef, TextStyleRef};
27use crate::xmltree::{XmlContent, XmlTag};
28use std::fmt::{Display, Formatter};
29
30/// TextTags are just XmlTags.
31pub type TextTag = XmlTag;
32/// Content of a TextTag is just some XmlContent.
33pub type TextContent = XmlContent;
34
35text_tag!(TextH, "text:h");
36
37// ok text:class-names 19.770.2,
38// ok text:cond-style-name 19.776,
39// ok text:id 19.809.6,
40// ok text:is-list-header 19.816,
41// ok text:outline-level 19.844.4,
42// ok text:restart-numbering 19.857,
43// ok text:start-value 19.868.2,
44// ok text:style-name 19.874.7,
45// ignore xhtml:about 19.905,
46// ignore xhtml:content 19.906,
47// ignore xhtml:datatype 19.907,
48// ignore xhtml:property 19.908
49// ok xml:id 19.914.
50impl TextH {
51 /// Sets class names aka paragraph styles as formatting.
52 pub fn class_names(mut self, class_names: &[&ParagraphStyleRef]) -> Self {
53 let mut buf = String::new();
54 for n in class_names {
55 buf.push_str(n.as_str());
56 buf.push(' ');
57 }
58 self.xml.set_attr("text:class-names", buf);
59 self
60 }
61
62 /// Sets a conditional style.
63 pub fn condstyle_name(mut self, name: &ParagraphStyleRef) -> Self {
64 self.xml
65 .set_attr("text:condstyle-name", name.as_str().to_string());
66 self
67 }
68
69 /// Identifier for a text passage.
70 pub fn id(mut self, id: &str) -> Self {
71 self.xml.set_attr("text:id", id);
72 self
73 }
74
75 /// Styled as list header.
76 pub fn list_header(mut self, lh: bool) -> Self {
77 self.xml.set_attr("text:is-list-header", lh.to_string());
78 self
79 }
80
81 /// Level of the heading.
82 pub fn outline_level(mut self, l: u8) -> Self {
83 self.xml.set_attr("text:outlinelevel", l.to_string());
84 self
85 }
86
87 /// Numbering reset.
88 pub fn restart_numbering(mut self, r: bool) -> Self {
89 self.xml.set_attr("text:restart-numbering", r.to_string());
90 self
91 }
92
93 /// Numbering start value.
94 pub fn start_value(mut self, l: u8) -> Self {
95 self.xml.set_attr("text:start-value", l.to_string());
96 self
97 }
98
99 /// Style
100 pub fn style_name(mut self, name: &ParagraphStyleRef) -> Self {
101 self.xml
102 .set_attr("text:style-name", name.as_str().to_string());
103 self
104 }
105
106 /// xml-id
107 pub fn xml_id(mut self, id: &str) -> Self {
108 self.xml.set_attr("xml:id", id);
109 self
110 }
111}
112
113text_tag!(TextP, "text:p");
114
115// ok text:class-names 19.770.3,
116// ok text:cond-style-name 19.776,
117// ok text:id 19.809.8,
118// ok text:style-name 19.874.29,
119// ignore xhtml:about 19.905,
120// ignore xhtml:content 19.906,
121// ignore xhtml:datatype 19.907,
122// ignore xhtml:property 19.908
123// ok xml:id 19.914.
124impl TextP {
125 /// Sets class names aka paragraph styles as formatting.
126 pub fn class_names(mut self, class_names: &[&ParagraphStyleRef]) -> Self {
127 let mut buf = String::new();
128 for n in class_names {
129 buf.push_str(n.as_str());
130 buf.push(' ');
131 }
132 self.xml.set_attr("text:class-names", buf);
133 self
134 }
135
136 /// Sets a conditional style.
137 pub fn condstyle_name(mut self, name: &ParagraphStyleRef) -> Self {
138 self.xml
139 .set_attr("text:condstyle-name", name.as_str().to_string());
140 self
141 }
142
143 /// Text id for a text passage.
144 pub fn id(mut self, id: &str) -> Self {
145 self.xml.set_attr("text:id", id);
146 self
147 }
148
149 /// Style for this paragraph.
150 pub fn style_name(mut self, name: &ParagraphStyleRef) -> Self {
151 self.xml
152 .set_attr("text:style-name", name.as_str().to_string());
153 self
154 }
155
156 /// xml-id
157 pub fn xml_id(mut self, id: &str) -> Self {
158 self.xml.set_attr("xml:id", id);
159 self
160 }
161}
162
163// The <text:span> element represents the application of a style to the character data of a portion
164// of text. The content of this element is the text which uses that text style.
165//
166// The <text:span> element can be nested.
167//
168// White space characters contained in this element are collapsed.
169text_tag!(TextSpan, "text:span");
170
171// text:class-names 19.770.4 and
172// text:style-name 19.874.33.
173impl TextSpan {
174 /// A text:class-names attribute specifies a white space separated list of text style names.
175 pub fn class_names(mut self, class_names: &[&TextStyleRef]) -> Self {
176 let mut buf = String::new();
177 for n in class_names {
178 buf.push_str(n.as_str());
179 buf.push(' ');
180 }
181 self.xml.set_attr("text:class-names", buf);
182 self
183 }
184
185 /// The text:style-name attribute specifies style for span which shall be a style with family of
186 /// text.
187 /// If both text:style-name and text:class-names are present, the style referenced by the
188 /// text:style-name attribute is treated as the first style in the list in text:class-names.
189 /// Consumers should support the text:class-names attribute and also should preserve it while
190 /// editing.
191 pub fn style_name(mut self, name: &TextStyleRef) -> Self {
192 self.xml
193 .set_attr("text:style-name", name.as_str().to_string());
194 self
195 }
196}
197
198// The <text:a> element represents a hyperlink.
199//
200// The anchor of a hyperlink is composed of the character data contained by the <text:a> element
201// and any of its descendant elements which constitute the character data of the paragraph which
202// contains the <text:a> element. 6.1.1
203text_tag!(TextA, "text:a");
204
205// obsolete office:name 19.376.9,
206// ??? office:target-frame-name 19.381,
207// ??? office:title 19.383,
208// ok text:style-name 19.874.2,
209// ok text:visited-style-name 19.901,
210// ??? xlink:actuate 19.909,
211// ok xlink:href 19.910.33,
212// ??? xlink:show 19.911 and
213// ??? xlink:type 19.913.
214impl TextA {
215 /// The text:style-name attribute specifies a text style for an unvisited hyperlink.
216 pub fn style_name(mut self, style: &TextStyleRef) -> Self {
217 self.xml
218 .set_attr("text:style-name", style.as_str().to_string());
219 self
220 }
221
222 /// The text:visited-style-name attribute specifies a style for a hyperlink that has been visited.
223 pub fn visited_style_name(mut self, style: &TextStyleRef) -> Self {
224 self.xml
225 .set_attr("text:visited-style-name", style.as_str().to_string());
226 self
227 }
228
229 /// href for a link.
230 pub fn href<S: Into<String>>(mut self, uri: S) -> Self {
231 self.xml.set_attr("xlink:href", uri.into());
232 self
233 }
234}
235
236// The <text:s> element is used to represent the [UNICODE] character “ “ (U+0020, SPACE).
237// This element shall be used to represent the second and all following “ “ (U+0020, SPACE)
238// characters in a sequence of “ “ (U+0020, SPACE) characters.
239//
240// Note: It is not an error if the character preceding the element is not a white space character, but it
241// is good practice to use this element only for the second and all following “ “ (U+0020, SPACE)
242// characters in a sequence.
243text_tag!(TextS, "text:s");
244
245// text:c 19.763.
246impl TextS {
247 /// The text:c attribute specifies the number of “ “ (U+0020, SPACE) characters that a <text:s>
248 /// element represents. A missing text:c attribute is interpreted as a single “ “ (U+0020, SPACE)
249 /// character.
250 pub fn count(mut self, count: u32) -> Self {
251 self.xml.set_attr("text:c", count.to_string());
252 self
253 }
254}
255
256// The <text:tab> element represents the [UNICODE] tab character (HORIZONTAL
257// TABULATION, U+0009).
258//
259// A <text:tab> element specifies that content immediately following it
260// should begin at the next tab stop.
261text_tag!(TextTab, "text:tab");
262
263impl TextTab {
264 /// The text:tab-ref attribute contains the number of the tab-stop to which a tab character refers.
265 /// The position 0 marks the start margin of a paragraph.
266 ///
267 /// Note: The text:tab-ref attribute is only a hint to help non-layout oriented consumers to
268 /// determine the tab/tab-stop association. Layout oriented consumers should determine the tab
269 /// positions based on the style information.
270 pub fn tab_ref(mut self, tab_ref: u32) -> Self {
271 self.xml.set_attr("text:tab-ref", tab_ref.to_string());
272 self
273 }
274}
275
276// The <text:soft-page-break> element represents a soft page break within or between
277// paragraph elements. As a child element of a <table:table> element it represents a soft page break between two
278// table rows. It may appear in front of a <table:table-row> element.
279text_tag!(SoftPageBreak, "text:soft-page-break");
280
281// The <text:date> element displays a date, by default this is the current date. The date can be
282// adjusted to display a date other than the current date.
283text_tag!(MetaDate, "text:date");
284text_tag!(MetaTime, "text:time");
285// text:page-continuation
286text_tag!(MetaPageNumber, "text:page-number");
287// text:sender-firstname
288// text:sender-lastname
289// text:sender-initials
290// text:sender-title
291// text:sender-position
292// text:sender-email
293// text:sender-phone-private
294// text:sender-fax
295// text:sender-company
296// text:sender-phone-work
297// text:sender-street
298// text:sender-city
299// text:sender-postal-code
300// text:sender-country
301// text:sender-state-or-province
302// The <text:author-name> element represents the full name of the author of a document.
303text_tag!(MetaAuthorName, "text:author-name");
304// The <text:author-initials> element represents the initials of the author of a document.
305text_tag!(MetaAuthorInitials, "text:author-initials");
306// text:chapter
307text_tag!(MetaFileName, "text:file-name");
308// text:template-name
309text_tag!(MetaSheetName, "text:sheet-name");
310text_tag!(MetaInitialCreator, "text:initial-creator");
311text_tag!(MetaCreationDate, "text:creation-date");
312text_tag!(MetaCreationTime, "text:creation-time");
313text_tag!(MetaDescription, "text:description");
314// text:user-defined
315text_tag!(MetaPrintTime, "text:print-time");
316text_tag!(MetaPrintDate, "text:print-date");
317text_tag!(MetaPrintedBy, "text:printed-by");
318text_tag!(MetaTitle, "text:title");
319text_tag!(MetaSubject, "text:subject");
320text_tag!(MetaKeywords, "text:keywords");
321text_tag!(MetaEditingCycles, "text:editing-cycles");
322text_tag!(MetaEditingDuration, "text:editing-duration");
323text_tag!(MetaModificationTime, "text:modification-time");
324text_tag!(MetaModificationDate, "text:modification-date");
325text_tag!(MetaCreator, "text:creator");
326text_tag!(MetaPageCount, "text:page-count");
327// text:paragraph-count
328// text:word-count
329text_tag!(MetaCharacterCount, "text:character-count");
330// text:table-count
331// text:image-count
332// text:object-count
333// text:meta-field