Exemplo n.º 1
0
void XeTeX::write_document_tex_file ()
{
  // Settings.
  extern Settings * settings;
  ProjectConfiguration *projectconfig = settings->projectconfig(settings->genconfig.project_get());
  
  // Style sheet.
  extern Styles * styles;
  Stylesheet * sheet = styles->stylesheet (stylesheet_get_actual ());
  
  document_tex.push_back (_("% Configuration file created by Bibledit-Gtk"));
  document_tex.push_back (_("% You can modify it to suit your needs"));
  document_tex.push_back (_("% After modification, run the following command in this directory:"));
  document_tex.push_back (_("%   xetex document.tex"));
  document_tex.push_back (_("% After that look carefully at the output"));
  document_tex.push_back (_("% If it says that a re-run is required, repeat this command"));

  document_tex.push_back ("");
  document_tex.push_back (_("% Include the ptx2pdf macros"));
  document_tex.push_back ("\\input paratext2.tex");

  document_tex.push_back ("");
  document_tex.push_back (_("% Paper size"));
  document_tex.push_back ("\\PaperWidth=" + convert_to_string (settings->genconfig.paper_width_get()) + "cm");
  document_tex.push_back ("\\PaperHeight=" + convert_to_string (settings->genconfig.paper_height_get()) + "cm");

  if (settings->session.print_crop_marks){
    document_tex.push_back ("");
    document_tex.push_back (_("% Crop marks"));
    document_tex.push_back ("\\CropMarkstrue");
  }

  document_tex.push_back ("");
  document_tex.push_back (_("% The basic unit for the margins; changing this will alter them all"));
  document_tex.push_back ("\\MarginUnit=1cm");

  document_tex.push_back ("");
  document_tex.push_back (_("% Relative sizes of margins, based on the unit above"));
  document_tex.push_back ("\\def\\TopMarginFactor{" + convert_to_string (settings->genconfig.paper_top_margin_get()) + "}");
  document_tex.push_back ("\\def\\BottomMarginFactor{" + convert_to_string (settings->genconfig.paper_bottom_margin_get()) + "}");
  document_tex.push_back ("\\def\\SideMarginFactor{" + convert_to_string (settings->genconfig.paper_outside_margin_get()) + "}");

  if (settings->genconfig.paper_inside_margin_get() != settings->genconfig.paper_outside_margin_get()) {
    document_tex.push_back ("");
    document_tex.push_back (_("% Extra margin for the gutter on the binding side"));
    document_tex.push_back ("\\BindingGuttertrue");
    document_tex.push_back ("\\BindingGutter=" + convert_to_string (settings->genconfig.paper_inside_margin_get() - settings->genconfig.paper_outside_margin_get()) + "cm");
    document_tex.push_back ("");
    document_tex.push_back (_("% Double sided printing"));
    document_tex.push_back ("\\DoubleSidedtrue");
  }

  if (!projectconfig->editor_font_default_get()) {
    PangoFontDescription *font_desc = pango_font_description_from_string(projectconfig->editor_font_name_get().c_str());
    if (font_desc){
      
      // Assemble the string for the font mapping.
      ustring font_mapping = projectconfig->xetex_font_mapping_file_get();
      if (!font_mapping.empty()) {
        if (g_str_has_suffix (font_mapping.c_str(), ".tec")) {
          font_mapping = gw_path_get_basename (font_mapping);
          // Remove the .tec suffix.
          font_mapping.erase (font_mapping.length() - 4, 4);
          // Insert the mapping command.
          font_mapping.insert (0, "mapping=");
        } else {
          gw_warning (_("Font mapping file ") + font_mapping +  _(" should have the .tec suffix - ignoring this file"));
          font_mapping.clear();
        }
      }

      // Assemble the string for the shaping engine.
      ustring shaping_engine;
      switch (XeTeXScriptingEngineType (projectconfig->xetex_shaping_engine_get())) {
        case xtxsetGeneric:                                 break;
        case xtxsetArab:    shaping_engine = "script=arab"; break;
      }

      // Assemble the addition to the font.
      ustring font_addition;
      if (!font_mapping.empty()) {
        if (font_addition.empty())
          font_addition.append (":");
        else 
          font_addition.append (";");
        font_addition.append (font_mapping);
      }
      if (!shaping_engine.empty()) {
        if (font_addition.empty())
          font_addition.append (":");
        else 
          font_addition.append (";");
        font_addition.append (shaping_engine);
      }

      ustring font_family = pango_font_description_get_family (font_desc);
      document_tex.push_back ("");
      document_tex.push_back (_("% Fonts to use for \"plain\", \"bold\", \"italic\", and \"bold italic\" from the stylesheet"));
      document_tex.push_back (_("% (they need not really be italic, etc.)"));
      document_tex.push_back (_("% Add e.g. \":mapping=farsidigits\" to get digits in Farsi, provided the farsidigits.tec TECkit mapping is available"));
      document_tex.push_back (_("% Add e.g. \":script=arab\" to use the arab shaping engine instead of the generic one"));
      document_tex.push_back ("\\def\\regular{\"" + font_family + font_addition + "\"}");
      document_tex.push_back ("\\def\\bold{\"" + font_family + "/B" + font_addition + "\"}");
      document_tex.push_back ("\\def\\italic{\"" + font_family + "/I" + font_addition +  "\"}");
      document_tex.push_back ("\\def\\bolditalic{\"" + font_family + "/BI" + font_addition +  + "\"}");
      pango_font_description_free(font_desc);
    }
  }

  if (projectconfig->right_to_left_get()) {
    document_tex.push_back ("");
    document_tex.push_back (_("% Right-to-left layout mode"));
    document_tex.push_back ("\\RTLtrue");
  }

  document_tex.push_back ("");
  document_tex.push_back (_("% The unit for font sizes in the stylesheet; changing this will scale all text proportionately"));
  document_tex.push_back ("\\FontSizeUnit=1pt");

  document_tex.push_back ("");
  document_tex.push_back (_("% Scaling factor used to adjust line spacing, relative to font size"));
  double line_spacing_factor = 1.0;
  double vertical_space_factor = 1.0;
  if (!projectconfig->editor_font_default_get()){
    line_spacing_factor = projectconfig->text_line_height_get() / 100;
    vertical_space_factor = projectconfig->text_line_height_get() / 100;
  }
  document_tex.push_back ("\\def\\LineSpacingFactor{" + convert_to_string (line_spacing_factor) + "}");
  document_tex.push_back ("\\def\\VerticalSpaceFactor{" + convert_to_string (vertical_space_factor) + "}");

  document_tex.push_back ("");
  document_tex.push_back (_("% Information to include in the running header (at top of pages, except first)"));
  document_tex.push_back (_("% We set the items to print at left/center/right of odd and even pages separately"));
  document_tex.push_back (_("% Possible contents:"));
  document_tex.push_back (_("%   \\rangeref = Scripture reference of the range of text on the page;"));
  document_tex.push_back (_("%   \\firstref = reference of the first verse on the page)"));
  document_tex.push_back (_("%   \\lastref = reference of the last verse on the page)"));
  document_tex.push_back (_("%   \\pagenumber = the page number"));
  document_tex.push_back (_("%   \\empty = print nothing in this position"));
  document_tex.push_back ("\\def\\RHoddleft{\\empty}");
  document_tex.push_back ("\\def\\RHoddcenter{\\empty}");
  document_tex.push_back ("\\def\\RHoddright{\\rangeref}");
  document_tex.push_back ("");
  document_tex.push_back ("\\def\\RHevenleft{\\rangeref}");
  document_tex.push_back ("\\def\\RHevencenter{\\empty}");
  document_tex.push_back ("\\def\\RHevenright{\\empty}");
  document_tex.push_back ("");
  document_tex.push_back ("\\def\\RHtitleleft{\\empty}");
  document_tex.push_back ("\\def\\RHtitlecenter{\\empty}");
  document_tex.push_back ("\\def\\RHtitleright{\\empty}");
  document_tex.push_back ("");
  document_tex.push_back ("\\def\\RFoddcenter{\\pagenumber}");
  document_tex.push_back ("\\def\\RFevencenter{\\pagenumber}");
  document_tex.push_back ("\\def\\RFtitlecenter{\\pagenumber}");

  document_tex.push_back ("");
  document_tex.push_back (_("% Whether to include verse number in running head, or only chapter"));
  document_tex.push_back ("\\VerseRefstrue");

  document_tex.push_back ("");
  document_tex.push_back (_("% Whether to skip printing verse number 1 at start of chapter"));
  document_tex.push_back ("\\OmitVerseNumberOnetrue");

  document_tex.push_back ("");
  document_tex.push_back (_("% Whether to use paragraph indent at drop-cap chapter numbers"));
  document_tex.push_back (_("% \\IndentAtChaptertrue"));

  // Go through the stylesheet looking for note markers.
  for (unsigned int i = 0; i < sheet->styles.size(); i++) {
    bool retrieve_note_data = false;
    StyleV2 * style = sheet->styles[i];
    if (style->type == stFootEndNote) {
      if ((style->subtype == fentFootnote) || (style->subtype == fentEndnote)) {
        retrieve_note_data = true;
      }
    }
    if ((style->type == stFootEndNote) || (style->type == stCrossreference)) {
      if (style->subtype == ctCrossreference) {
        retrieve_note_data = true;
      }
    }
    if (retrieve_note_data) {

      ustring marker = style->marker;
      document_tex.push_back ("");
      document_tex.push_back (_("% Reformat \\") + marker + " notes as a single paragraph");
      document_tex.push_back ("\\ParagraphedNotes{" + marker + "}");

      document_tex.push_back ("");
      NoteNumberingType note_numbering = NoteNumberingType (style->userint1);
      switch (note_numbering) {
        case nntNumerical:
          document_tex.push_back (_("% Numerical callers for \\") + marker + _(" notes"));
          document_tex.push_back ("\\NumericCallers{" + marker + "}");
          break;
        case nntAlphabetical:
          document_tex.push_back (_("% Alphabetical callers for \\") + marker + _(" notes"));
          document_tex.push_back ("\\AutoCallers{" + marker+ "}{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}");
          break;
        case nntUserDefined:
          ustring autocallers;
          for (unsigned int i = 0; i < style->userstring1.size(); i++) {
            if (i)
              autocallers.append (",");
            autocallers.append (style->userstring1.substr (i, 1));
          }
          if (!autocallers.empty()) {
            document_tex.push_back (_("% Special caller sequence for \\") + marker + " notes");
            document_tex.push_back ("\\AutoCallers{" + marker+ "}{" + autocallers + "}");
          }
          break;
      }

      document_tex.push_back ("");
      NoteNumberingRestartType note_restart = NoteNumberingRestartType (style->userint2);
      switch (note_restart) {
        case nnrtNever:
          break;
        case nnrtBook:
          break;
        case nnrtChapter:
          break;
      }
      document_tex.push_back (_("% Reset callers every page for \\") + marker + _(" notes"));
      document_tex.push_back ("\\PageResetCallers{" + marker + "}");

      document_tex.push_back ("");
      document_tex.push_back (_("% Omit callers in the note for \\") + marker + _(" notes"));
      document_tex.push_back (_("% \\OmitCallerInNote{") + marker + "}");

    }
  }

  document_tex.push_back ("");
  document_tex.push_back (_("% The number of columns"));
  document_tex.push_back ("\\TitleColumns=1");
  document_tex.push_back ("\\IntroColumns=1");
  document_tex.push_back ("\\BodyColumns=2");

  document_tex.push_back ("");
  document_tex.push_back (_("% The gutter between double cols, relative to font size"));
  document_tex.push_back ("\\def\\ColumnGutterFactor{15}");

  // Define the Paratext stylesheet to be used as a basis for formatting
  write_stylesheet ();

  // Write the data and add their filenames.
  for (unsigned int i = 0; i < book_ids.size(); i++) {
    ustring filename = convert_to_string (book_ids[i]) + " " + books_id_to_english(book_ids[i]) + ".usfm";
    replace_text (filename, " ", "_");
    write_lines (gw_build_filename (working_directory, filename), book_data[i]);
    document_tex.push_back ("\\ptxfile{" + filename + "}");
  }

  // End of document input.
  document_tex.push_back ("\\end");

  // Write document.text to file.
  write_lines (gw_build_filename (working_directory, "document.tex"), document_tex);
}
void view_parallel_references_pdf(ProjectMemory & main_project, vector < ustring > *extra_projects, vector < Reference > references, bool keep_verses_together_within_page, vector < ustring > *remarks, bool highlight)
/*
 Formats the references in "references", and highlights all words in
 "session->highlights*" and shows them in a pdf viewer.
 There is a pointer to a list of "remarks". Any remarks will be printed first.
 */
{
  // Log.
  gw_message(_("Printing parallel references"));

  // Progress system.
  ProgressWindow progresswindow(_("Printing Parallel References"), false);
  progresswindow.set_iterate(0, 1, references.size());

  // Configuration
  extern Settings *settings;
  ProjectConfiguration *projectconfig = settings->projectconfig(main_project.name);
  ustring stylesheet = stylesheet_get_actual ();

  // Store the additional projects to print.
  vector < ustring > additional_projects;
  if (extra_projects)
    additional_projects = *extra_projects;
  settings->session.additional_printing_projects = additional_projects;

  // Prepare for mapping.
  Mapping mapping(projectconfig->versification_get(), 0);

  // The converter.
  Text2Pdf text2pdf(gw_build_filename(Directories->get_temp(), "document.pdf"), settings->genconfig.print_engine_use_intermediate_text_get());

  // Page.
  text2pdf.page_size_set(settings->genconfig.paper_width_get(), settings->genconfig.paper_height_get());
  text2pdf.page_margins_set(settings->genconfig.paper_inside_margin_get(), settings->genconfig.paper_outside_margin_get(), settings->genconfig.paper_top_margin_get(), settings->genconfig.paper_bottom_margin_get());
  text2pdf.page_one_column_only();

  // Headers.
  if (settings->genconfig.printdate_get()) {
    text2pdf.print_date_in_header();
  }
  // Font, etc., of main project.
  ustring main_font = projectconfig->editor_font_name_get();
  unsigned int main_line_spacing = projectconfig->text_line_height_get();
  if (projectconfig->editor_font_default_get()) {
    main_font.clear();
    main_line_spacing = 100;
  }
  text2pdf.set_font(main_font);
  text2pdf.set_line_spacing(main_line_spacing);
  bool main_right_to_left = projectconfig->right_to_left_get();
  text2pdf.set_right_to_left(main_right_to_left);

  // Start off with inserting any remarks.
  if (remarks) {
    for (unsigned int r = 0; r < remarks->size(); r++) {
      text2pdf.open_paragraph();
      text2pdf.paragraph_set_column_count(1);
      text2pdf.add_text(remarks->at(r));
      text2pdf.close_paragraph();
    }
  }
  // Some variables to avoid excessive session access during highlighting.
  vector < bool > highlight_casesensitives;
  vector < ustring > highlight_words;
  if (highlight) {
    for (unsigned int hl = 0; hl < settings->session.highlights.size(); hl++) {
      highlight_casesensitives.push_back(settings->session.highlights[hl].casesensitive);
      highlight_words.push_back(settings->session.highlights[hl].word);
    }
  }
  // All the projects to be put in this parallel Bible, together with
  // their related information, like mapping, fonts.
  vector < ustring > project_names;
  vector < ProjectMemory > project_memories;
  vector < Mapping > mapping_s;
  vector < ustring > fonts;
  vector < unsigned int >line_spacings;
  vector < bool > right_to_lefts;
  if (extra_projects) {
    vector < ustring > project_s_raw = *extra_projects;
    for (unsigned int i = 0; i < project_s_raw.size(); i++) {
      ProjectMemory projectmemory(project_s_raw[i], true);
      project_memories.push_back(projectmemory);
      ProjectConfiguration *projectconfig = settings->projectconfig(project_s_raw[i]);
      project_names.push_back(project_s_raw[i]);
      Mapping mapping(projectconfig->versification_get(), 0);
      mapping_s.push_back(mapping);
      ustring font = projectconfig->editor_font_name_get();
      unsigned int line_spacing = projectconfig->text_line_height_get();
      if (projectconfig->editor_font_default_get()) {
        font.clear();
        line_spacing = 100;
      }
      fonts.push_back(font);
      line_spacings.push_back(line_spacing);
      right_to_lefts.push_back(projectconfig->right_to_left_get());
    }
  }
  // Produce chunks for all references.
  for (unsigned int rf = 0; rf < references.size(); rf++) {

    // Update progress bar.
    progresswindow.iterate();

    // Whether to keep things on one page.    
    if (keep_verses_together_within_page) {
      text2pdf.open_keep_together();
    }
    // Set main font, etc.
    text2pdf.set_font(main_font);
    text2pdf.set_line_spacing(main_line_spacing);
    text2pdf.set_right_to_left(main_right_to_left);

    // Add the reference to the text.
    text2pdf.add_text(references[rf].human_readable(""));

    // Map this verse to the original, that is, to Hebrew or Greek.
    vector <int> hebrew_greek_chapters;
    vector <int> hebrew_greek_verses;
    mapping.book_change(references[rf].book);
    mapping.me_to_original(references[rf].chapter, references[rf].verse, hebrew_greek_chapters, hebrew_greek_verses);
    // Get verse text for each version.
    for (unsigned int vsn = 0; vsn <= project_names.size(); vsn++) {

      // Add the font, etc., for each project.
      ustring font(main_font);
      unsigned int line_spacing = main_line_spacing;
      bool right_to_left = main_right_to_left;
      if (vsn > 0) {
        font = fonts[vsn - 1];
        line_spacing = line_spacings[vsn - 1];
        right_to_left = right_to_lefts[vsn - 1];
      }
      text2pdf.set_font(font);
      text2pdf.set_line_spacing(line_spacing);
      text2pdf.set_right_to_left(right_to_left);

      // Get the verse text.
      ustring line;
      if (vsn == 0) {
        // First version.
        ProjectBook *projectbook = main_project.get_book_pointer(references[rf].book);
        if (projectbook) {
          ProjectChapter *projectchapter = projectbook->get_chapter_pointer(references[rf].chapter);
          if (projectchapter) {
            ProjectVerse *projectverse = projectchapter->get_verse_pointer(references[rf].verse);
            if (projectverse) {
              line = projectverse->data;
            }
          }
        }
      } else {
        // Other versions. 
        // Get mapped chapters / verses.
        line.clear();
        vector <int> mychapters;
        vector <int> myverses;
        mapping_s[vsn - 1].book_change(references[rf].book);
        mapping_s[vsn - 1].original_to_me(hebrew_greek_chapters, hebrew_greek_verses, mychapters, myverses);
        // Get text of any of the mapped verses.
        for (unsigned int mp = 0; mp < mychapters.size(); mp++) {
          // Get the verse and add it to the usfm code.
          ProjectBook *projectbook = project_memories[vsn - 1].get_book_pointer(references[rf].book);
          if (projectbook) {
            ProjectChapter *projectchapter = projectbook->get_chapter_pointer(mychapters[mp]);
            if (projectchapter) {
              ProjectVerse *projectverse = projectchapter->get_verse_pointer(convert_to_string(myverses[mp]));
              if (projectverse) {
                if (!line.empty()) 
                  line.append (" ");
                line.append (projectverse->data);
              }
            }
          }
        }
      }

      // Add the project name if there are more than one.
      if (!project_names.empty()) {
        ustring project;
        if (vsn == 0)
          project = main_project.name;
        else
          project = project_names[vsn - 1];
        text2pdf.open_paragraph();
        text2pdf.inline_set_font_size_percentage(65);
        text2pdf.add_text(project);
        text2pdf.inline_clear_font_size_percentage();
        text2pdf.add_text(" ");
      } else {
        text2pdf.open_paragraph();
      }

      // Do text replacement.
      text_replacement(line);

      // Positions in the line, and lengths to highlight.
      vector < size_t > highlight_positions;
      vector < size_t > highlight_lengths;

      // Go through all the words to highlight.
      for (unsigned int i2 = 0; i2 < highlight_casesensitives.size(); i2++) {
        // Word to highlight
        ustring highlightword;
        if (highlight_casesensitives[i2])
          highlightword = highlight_words[i2];
        else
          highlightword = highlight_words[i2].casefold();
        // Variabele s holds a shadow string.
        ustring s;
        if (highlight_casesensitives[i2])
          s = line;
        else
          s = line.casefold();
        // Find positions for highlighting.
        size_t offposition = s.find(highlightword);
        while (offposition != string::npos) {
          // Store position and length.
          highlight_positions.push_back(offposition);
          highlight_lengths.push_back(highlightword.length());
          // Look for possible next word to highlight.
          offposition = offposition + highlightword.length() + 1;
          // There is something like a bug in s.find. If the offposition
          // is greater than the length of s, then s.find will return
          // a value below offposition, instead of string::npos as is
          // expected. Workaround.
          if (offposition > s.length())
            break;
          offposition = s.find(highlightword, offposition);
        }
      }
      // Sort the positions from small to bigger.
      xml_sort_positions(highlight_positions, highlight_lengths);
      // Combine overlapping positions.
      xml_combine_overlaps(highlight_positions, highlight_lengths);

      // Insert the code for highlighting.
      for (int i = highlight_positions.size () - 1; i >= 0; i--) {
        for (int i2 = highlight_lengths.size() - 1; i2 >= 0; i2--) {
          line.insert (highlight_positions[i] + i2, INSERTION_FLAG);
        }
      }

      // Add usfm converter to the layout engine, and set various things.
      Usfm2Text usfm2text(&text2pdf, false);
      usfm2text.add_styles(usfm2xslfo_read_stylesheet(stylesheet));

      usfm2text.no_bold();
      usfm2text.no_space_before_or_after();
      usfm2text.no_new_page();
      usfm2text.add_usfm_code(line);
      usfm2text.process();
    }

    // Add a bit of space.
    text2pdf.close_paragraph();
    text2pdf.add_text(" ");
    text2pdf.close_paragraph();

    // Whether to close code keeping things on one page.    
    if (keep_verses_together_within_page) {
      text2pdf.close_keep_together();
    }
  }

  // Hide progeressbar.
  progresswindow.hide();

  // Process the data.
  text2pdf.run();

  // Display the pdf file.
  text2pdf.view();

  // Log: ready.
  gw_message(_("Ready printing the parallel references"));
}