~bibledit/bibledit/ubuntu-cloud-beta

« back to all changes in this revision

Viewing changes to odf/text.cpp

  • Committer: Teus Benschop
  • Date: 2022-10-14 16:03:26 UTC
  • Revision ID: teusjannette@gmail.com-20221014160326-42ybrpft4bblpruk
new upstream version

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
// The other thing is that Java is slow compared to the methods below written in C++.
36
36
 
37
37
 
38
 
odf_text::odf_text (string bible_in)
 
38
odf_text::odf_text (string bible)
39
39
{
40
 
  bible = bible_in;
41
 
  current_text_p_node_opened = false;
42
 
  current_paragraph_style.clear();
43
 
  current_paragraph_content.clear();
44
 
  current_text_style.clear();
45
 
  frame_count = 0;
46
 
  note_text_p_opened = false;
47
 
  note_count = 0;
48
 
  current_note_text_style.clear();
49
 
  image_counter = 0;
 
40
  m_bible = bible;
50
41
 
51
42
  // Unpack the .odt template.
52
43
  string template_odf = filter_url_create_root_path ({"odf", "template.odt"});
59
50
  initialize_content_xml ();
60
51
  initialize_styles_xml ();
61
52
  
62
 
  automatic_note_caller = Database_Config_Bible::getOdtAutomaticNoteCaller(bible);
 
53
  automatic_note_caller = Database_Config_Bible::getOdtAutomaticNoteCaller(m_bible);
63
54
}
64
55
 
65
56
 
121
112
    childnode.append_attribute ("style:font-family-generic") = "roman";
122
113
    childnode.append_attribute ("style:font-pitch") = "variable";
123
114
    
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";
284
275
  
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, "'");
381
372
  }
382
373
 
383
374
  // Update the tab-stops in the header style. The tab stops depend on page and margin dimensions.
384
 
  int centerPosition = convert_to_int (Database_Config_Bible::getPageWidth (bible)) - convert_to_int (Database_Config_Bible::getInnerMargin (bible)) - convert_to_int (Database_Config_Bible::getOuterMargin (bible));
 
375
  int centerPosition = 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));
385
376
 
386
377
  xml_node office_automatic_styles = rootnode.append_child ("office:automatic-styles");
387
378
  {
436
427
    {
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";
449
440
      {
520
511
          text_p.append_child ("text:tab");
521
512
        }
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");
549
540
        }
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") = "";
572
563
{
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();
578
569
}
579
570
 
580
571
 
586
577
  if (text.empty()) return;
587
578
 
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 ();
590
581
  
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());
595
586
  
596
587
  // Write a text span element, nesting the second and later ones.
609
600
  dom_node.text ().set (text.c_str());
610
601
 
611
602
  // Update public paragraph text.
612
 
  current_paragraph_content += text;
 
603
  m_current_paragraph_content += text;
613
604
}
614
605
 
615
606
 
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 ();
660
651
}
661
652
 
662
653
 
677
668
{
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);
683
674
  }
684
675
  
729
720
  }
730
721
 
731
722
  // Text alignment can be: AlignmentLeft, AlignmentCenter, AlignmentRight, AlignmentJustify.
732
 
  string alignmenttext;
 
723
  string alignmenttext {};
733
724
  switch (alignment) {
734
725
    case AlignmentLeft:    alignmenttext = "start";   break;
735
726
    case AlignmentCenter:  alignmenttext = "center";  break;
800
791
// $name: the name of the style, e.g. 'p'.
801
792
void odf_text::update_current_paragraph_style (string name)
802
793
{
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();
877
868
  }
878
869
 
879
870
  if (note) {
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);
882
873
  } else {
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);
885
876
  }
886
877
}
887
878
 
892
883
void odf_text::close_text_style (bool note, bool embed)
893
884
{
894
885
  if (note) {
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 ();
897
888
  } else {
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 ();
900
891
  }
901
892
}
902
893
 
914
905
 
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 ();
918
909
 
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">
924
915
  // </draw:frame>
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";
927
 
  frame_count++;
928
 
  draw_frame_dom_element.append_attribute ("draw:name") = convert_to_string ("frame" + convert_to_string (frame_count)).c_str();
 
918
  m_frame_count++;
 
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)
1035
1026
{
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 ();
1038
1029
 
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();
1041
 
  note_count++;
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();
 
1032
  m_note_count++;
 
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;
1073
1064
 
1074
1065
  // Ensure a note has started.
1075
 
  if (!note_text_p_opened) add_note ("?", "");
 
1066
  if (!m_note_text_p_opened) add_note ("?", "");
1076
1067
 
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 ("");
1080
1071
 
1081
1072
  // Write a text span element, nesting the second and later ones.
1095
1086
void odf_text::close_current_note ()
1096
1087
{
1097
1088
  close_text_style (true, false);
1098
 
  note_text_p_opened = false;
 
1089
  m_note_text_p_opened = false;
1099
1090
}
1100
1091
 
1101
1092
 
1141
1132
  }
1142
1133
 
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 ();
1147
1138
}
1148
1139
 
1149
1140
 
1189
1180
//     <draw:image xlink:href="../bibleimage2.png" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad" draw:filter-name="&lt;All formats&gt;" draw:mime-type="image/png" />
1190
1181
//   </draw:frame>
1191
1182
// </text:p>
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)
1193
1184
{
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();
1201
1191
 
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};
1204
1195
  {
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);
1210
 
 
1211
1201
  }
1212
1202
 
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};
1217
1207
  {
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;
1221
1211
    }
1222
1212
  }
1223
1213
  
1224
1214
  {
1225
 
    image_counter++;
 
1215
    m_image_counter++;
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%";
1249
1239
  
1250
1240
  // Optionally add the caption if given.
1251
1241
  if (!caption.empty()) {
1252
 
    xml_node text_node = current_text_p_node.append_child(node_pcdata);
1253
 
    text_node.set_value(caption.c_str());
 
1242
    new_paragraph (style);
 
1243
    add_text (caption);
 
1244
//    xml_node text_node = current_text_p_node.append_child(node_pcdata);
 
1245
//    text_node.set_value(caption.c_str());
1254
1246
  }
1255
1247
 
1256
1248
  // Save the picture into the Pictures output folder.
1268
1260
 
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 ();
1274
1266
}
1275
1267
 
1276
1268
 
1278
1270
void odf_text::add_tab ()
1279
1271
{
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 ();
1282
1274
  
1283
1275
  // Write a text tab element.
1284
1276
  current_text_p_node.append_child ("text:tab");
1285
1277
 
1286
1278
  // Update public paragraph text.
1287
 
  current_paragraph_content += "\t";
 
1279
  m_current_paragraph_content += "\t";
1288
1280
}