35
35
// The other thing is that Java is slow compared to the methods below written in C++.
38
odf_text::odf_text (string bible_in)
38
odf_text::odf_text (string bible)
41
current_text_p_node_opened = false;
42
current_paragraph_style.clear();
43
current_paragraph_content.clear();
44
current_text_style.clear();
46
note_text_p_opened = false;
48
current_note_text_style.clear();
51
42
// Unpack the .odt template.
52
43
string template_odf = filter_url_create_root_path ({"odf", "template.odt"});
121
112
childnode.append_attribute ("style:font-family-generic") = "roman";
122
113
childnode.append_attribute ("style:font-pitch") = "variable";
124
string fontname = Database_Config_Bible::getExportFont (bible);
115
string fontname = Database_Config_Bible::getExportFont (m_bible);
125
116
childnode = office_font_face_decls.append_child ("style:font-face");
126
117
childnode.append_attribute ("style:name") = fontname.c_str();
127
118
fontname.insert (0, "'");
282
273
childnode.append_attribute ("style:font-family-generic") = "roman";
283
274
childnode.append_attribute ("style:font-pitch") = "variable";
285
string fontname = Database_Config_Bible::getExportFont (bible);
276
string fontname = Database_Config_Bible::getExportFont (m_bible);
286
277
childnode = office_font_face_decls.append_child ("style:font-face");
287
278
childnode.append_attribute ("style:name") = fontname.c_str();
288
279
fontname.insert (0, "'");
437
428
xml_node style_page_layout_properties = style_page_layout.append_child ("style:page-layout-properties");
438
429
// Take the page size and margins from the Bible's settings.
439
style_page_layout_properties.append_attribute ("fo:page-width") = convert_to_string (Database_Config_Bible::getPageWidth (bible) + "mm").c_str();
440
style_page_layout_properties.append_attribute ("fo:page-height") = convert_to_string (Database_Config_Bible::getPageHeight (bible) + "mm").c_str();
430
style_page_layout_properties.append_attribute ("fo:page-width") = convert_to_string (Database_Config_Bible::getPageWidth (m_bible) + "mm").c_str();
431
style_page_layout_properties.append_attribute ("fo:page-height") = convert_to_string (Database_Config_Bible::getPageHeight (m_bible) + "mm").c_str();
441
432
style_page_layout_properties.append_attribute ("style:num-format") = "1";
442
433
style_page_layout_properties.append_attribute ("style:print-orientation") = "portrait";
443
style_page_layout_properties.append_attribute ("fo:margin-top") = convert_to_string (Database_Config_Bible::getTopMargin (bible) + "mm").c_str();
444
style_page_layout_properties.append_attribute ("fo:margin-bottom") = convert_to_string (Database_Config_Bible::getBottomMargin (bible) + "mm").c_str();
445
style_page_layout_properties.append_attribute ("fo:margin-left") = convert_to_string (Database_Config_Bible::getInnerMargin (bible) + "mm").c_str();
446
style_page_layout_properties.append_attribute ("fo:margin-right") = convert_to_string (Database_Config_Bible::getOuterMargin (bible) + "mm").c_str();
434
style_page_layout_properties.append_attribute ("fo:margin-top") = convert_to_string (Database_Config_Bible::getTopMargin (m_bible) + "mm").c_str();
435
style_page_layout_properties.append_attribute ("fo:margin-bottom") = convert_to_string (Database_Config_Bible::getBottomMargin (m_bible) + "mm").c_str();
436
style_page_layout_properties.append_attribute ("fo:margin-left") = convert_to_string (Database_Config_Bible::getInnerMargin (m_bible) + "mm").c_str();
437
style_page_layout_properties.append_attribute ("fo:margin-right") = convert_to_string (Database_Config_Bible::getOuterMargin (m_bible) + "mm").c_str();
447
438
style_page_layout_properties.append_attribute ("style:writing-mode") = "lr-tb";
448
439
style_page_layout_properties.append_attribute ("style:footnote-max-height") = "0cm";
520
511
text_p.append_child ("text:tab");
522
513
// Whether and how to put the date in the running headers.
523
if (Database_Config_Bible::getDateInHeader (bible)) {
514
if (Database_Config_Bible::getDateInHeader (m_bible)) {
524
515
xml_node node = text_p.append_child ("text:date");
525
516
node.append_attribute ("style:data-style-name") = "N81";
526
517
node.append_attribute ("text:date-value") = "";
548
539
text_p.append_child ("text:tab");
550
541
// Whether and how to put the date in the running headers.
551
if (Database_Config_Bible::getDateInHeader (bible)) {
542
if (Database_Config_Bible::getDateInHeader (m_bible)) {
552
543
xml_node node = text_p.append_child ("text:date");
553
544
node.append_attribute ("style:data-style-name") = "N81";
554
545
node.append_attribute ("text:date-value") = "";
573
564
current_text_p_node = office_text_node.append_child ("text:p");
574
565
current_text_p_node_style_name = current_text_p_node.append_attribute ("text:style-name") = style.c_str();
575
current_text_p_node_opened = true;
576
current_paragraph_style = style;
577
current_paragraph_content.clear();
566
m_current_text_p_node_opened = true;
567
m_current_paragraph_style = style;
568
m_current_paragraph_content.clear();
586
577
if (text.empty()) return;
588
579
// Ensure a paragraph has started.
589
if (!current_text_p_node_opened) new_paragraph ();
580
if (!m_current_text_p_node_opened) new_paragraph ();
591
582
// Temporal styles array should have at least one style for the code below to work.
592
583
// So ensure it has at least one style.
593
vector <string> styles (current_text_style.begin (), current_text_style.end ());
584
vector <string> styles (m_current_text_style.begin (), m_current_text_style.end ());
594
585
if (styles.empty()) styles.push_back (string());
596
587
// Write a text span element, nesting the second and later ones.
654
645
// Always clear the paragraph-opened-flag,
655
646
// because we don't want subsequent text to be added to this page break,
656
647
// since it would be nearly invisible, and thus text would mysteriously get lost.
657
current_text_p_node_opened = false;
658
current_paragraph_style.clear ();
659
current_paragraph_content.clear ();
648
m_current_text_p_node_opened = false;
649
m_current_paragraph_style.clear ();
650
m_current_paragraph_content.clear ();
678
669
// Whether to align verse numbers in poetry to the left of the margin,
679
670
// and if so, whether this is one of the defined poetry styles.
680
bool is_poetry_q_style = false;
681
if (Database_Config_Bible::getOdtPoetryVersesLeft (bible)) {
671
bool is_poetry_q_style {false};
672
if (Database_Config_Bible::getOdtPoetryVersesLeft (m_bible)) {
682
673
is_poetry_q_style = filter::usfm::is_standard_q_poetry (name);
800
791
// $name: the name of the style, e.g. 'p'.
801
792
void odf_text::update_current_paragraph_style (string name)
803
if (!current_text_p_node_opened) new_paragraph ();
794
if (!m_current_text_p_node_opened) new_paragraph ();
804
795
current_text_p_node.remove_attribute (current_text_p_node_style_name);
805
796
current_text_p_node_style_name = current_text_p_node.append_attribute ("text:style-name");
806
797
current_text_p_node_style_name = convert_style_name (name).c_str();
880
if (!embed) current_note_text_style.clear();
881
current_note_text_style.push_back (marker);
871
if (!embed) m_current_note_text_style.clear();
872
m_current_note_text_style.push_back (marker);
883
if (!embed) current_text_style.clear ();
884
current_text_style.push_back (marker);
874
if (!embed) m_current_text_style.clear ();
875
m_current_text_style.push_back (marker);
892
883
void odf_text::close_text_style (bool note, bool embed)
895
if (!embed) current_note_text_style.clear();
896
if (!current_note_text_style.empty ()) current_note_text_style.pop_back ();
886
if (!embed) m_current_note_text_style.clear();
887
if (!m_current_note_text_style.empty ()) m_current_note_text_style.pop_back ();
898
if (!embed) current_text_style.clear();
899
if (!current_text_style.empty()) current_text_style.pop_back ();
889
if (!embed) m_current_text_style.clear();
890
if (!m_current_text_style.empty()) m_current_text_style.pop_back ();
915
906
// The frame goes in an existing paragraph (text:p) element, just like a 'text:span' element.
916
907
// Ensure that a paragraph is open.
917
if (!current_text_p_node_opened) new_paragraph ();
908
if (!m_current_text_p_node_opened) new_paragraph ();
919
910
// The frame looks like this, in content.xml:
920
911
// <draw:frame draw:style-name="fr1" draw:name="frame1" text:anchor-type="paragraph" svg:y="0cm" fo:min-width="0.34cm" draw:z-index="0">
925
916
xml_node draw_frame_dom_element = current_text_p_node.append_child ("draw:frame");
926
917
draw_frame_dom_element.append_attribute ("draw:style-name") = "chapterframe";
928
draw_frame_dom_element.append_attribute ("draw:name") = convert_to_string ("frame" + convert_to_string (frame_count)).c_str();
919
draw_frame_dom_element.append_attribute ("draw:name") = convert_to_string ("frame" + convert_to_string (m_frame_count)).c_str();
929
920
draw_frame_dom_element.append_attribute ("text:anchor-type") = "paragraph";
930
921
draw_frame_dom_element.append_attribute ("svg:y") = "0cm";
931
922
draw_frame_dom_element.append_attribute ("fo:min-width") = "0.34cm";
1034
1025
void odf_text::add_note (string caller, string style, bool endnote)
1036
1027
// Ensure that a paragraph is open, so that the note can be added to it.
1037
if (!current_text_p_node_opened) new_paragraph ();
1028
if (!m_current_text_p_node_opened) new_paragraph ();
1039
1030
xml_node text_note_dom_element = current_text_p_node.append_child ("text:note");
1040
text_note_dom_element.append_attribute ("text:id") = convert_to_string ("ftn" + convert_to_string (note_count)).c_str();
1042
note_text_p_opened = true;
1031
text_note_dom_element.append_attribute ("text:id") = convert_to_string ("ftn" + convert_to_string (m_note_count)).c_str();
1033
m_note_text_p_opened = true;
1043
1034
string noteclass;
1044
1035
if (endnote) noteclass = "endnote";
1045
1036
else noteclass = "footnote";
1072
1063
if (text == "") return;
1074
1065
// Ensure a note has started.
1075
if (!note_text_p_opened) add_note ("?", "");
1066
if (!m_note_text_p_opened) add_note ("?", "");
1077
1068
// Temporal styles array should have at least one style for the code below to work.
1078
vector <string> styles (current_note_text_style.begin(), current_note_text_style.end());
1069
vector <string> styles (m_current_note_text_style.begin(), m_current_note_text_style.end());
1079
1070
if (styles.empty ()) styles.push_back ("");
1081
1072
// Write a text span element, nesting the second and later ones.
1143
1134
// Make paragraph null, so that adding subsequent text creates a new paragraph.
1144
current_text_p_node_opened = false;
1145
current_paragraph_style.clear ();
1146
current_paragraph_content.clear ();
1135
m_current_text_p_node_opened = false;
1136
m_current_paragraph_style.clear ();
1137
m_current_paragraph_content.clear ();
1189
1180
// <draw:image xlink:href="../bibleimage2.png" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad" draw:filter-name="<All formats>" draw:mime-type="image/png" />
1190
1181
// </draw:frame>
1192
void odf_text::add_image ([[maybe_unused]] string alt, string src, string caption)
1183
void odf_text::add_image (string style, [[maybe_unused]] string alt, string src, string caption)
1194
1185
// The parent paragraph for the image has the "p" style.
1195
const char * style = "p";
1196
1186
current_text_p_node = office_text_node.append_child ("text:p");
1197
current_text_p_node_style_name = current_text_p_node.append_attribute ("text:style-name") = style;
1198
current_text_p_node_opened = true;
1199
current_paragraph_style = style;
1200
current_paragraph_content.clear();
1187
current_text_p_node_style_name = current_text_p_node.append_attribute ("text:style-name") = "p";
1188
m_current_text_p_node_opened = true;
1189
m_current_paragraph_style = style;
1190
m_current_paragraph_content.clear();
1202
1192
// Get the width and height of the image in pixels.
1203
int image_width_pixels = 0, image_height_pixels = 0;
1193
int image_width_pixels {0};
1194
int image_height_pixels {0};
1205
Database_BibleImages database_bibleimages;
1196
Database_BibleImages database_bibleimages {};
1206
1197
string path = filter_url_create_root_path ({filter_url_temp_dir (), "image_contents"});
1207
1198
string contents = database_bibleimages.get(src);
1208
1199
filter_url_file_put_contents(path, contents);
1209
1200
filter_image_get_sizes (path, image_width_pixels, image_height_pixels);
1213
1203
// Determine the width of the available space so the image width will be equal to that.
1214
1204
// Then the image height depends on the ratio of the image width and height in pixels.
1215
int available_width_mm = 0;
1216
int available_height_mm = 50;
1205
int available_width_mm {0};
1206
int available_height_mm {50};
1218
available_width_mm = convert_to_int (Database_Config_Bible::getPageWidth (bible)) - convert_to_int (Database_Config_Bible::getInnerMargin (bible)) - convert_to_int (Database_Config_Bible::getOuterMargin (bible));
1208
available_width_mm = convert_to_int (Database_Config_Bible::getPageWidth (m_bible)) - convert_to_int (Database_Config_Bible::getInnerMargin (m_bible)) - convert_to_int (Database_Config_Bible::getOuterMargin (m_bible));
1219
1209
if (image_width_pixels && image_height_pixels) {
1220
1210
available_height_mm = available_width_mm * image_height_pixels / image_width_pixels;
1226
1216
xml_node draw_frame_node = current_text_p_node.append_child("draw:frame");
1227
1217
draw_frame_node.append_attribute("draw:style-name") = "fr1";
1228
draw_frame_node.append_attribute("draw:name") = ("Image" + convert_to_string(image_counter)).c_str();
1218
draw_frame_node.append_attribute("draw:name") = ("Image" + convert_to_string(m_image_counter)).c_str();
1229
1219
draw_frame_node.append_attribute("text:anchor-type") = "char";
1230
1220
draw_frame_node.append_attribute("svg:width") = (convert_to_string (available_width_mm) + "mm").c_str();
1231
1221
// draw_frame_node.append_attribute("style:rel-width") = "100%";
1269
1261
// Close the current paragraph.
1270
1262
// Goal: Any text that will be added will be output into a new paragraph.
1271
current_text_p_node_opened = false;
1272
current_paragraph_style.clear ();
1273
current_paragraph_content.clear ();
1263
m_current_text_p_node_opened = false;
1264
m_current_paragraph_style.clear ();
1265
m_current_paragraph_content.clear ();
1278
1270
void odf_text::add_tab ()
1280
1272
// Ensure a paragraph has started.
1281
if (!current_text_p_node_opened) new_paragraph ();
1273
if (!m_current_text_p_node_opened) new_paragraph ();
1283
1275
// Write a text tab element.
1284
1276
current_text_p_node.append_child ("text:tab");
1286
1278
// Update public paragraph text.
1287
current_paragraph_content += "\t";
1279
m_current_paragraph_content += "\t";