Logo Search packages:      
Sourcecode: bibledit version File versions  Download package

print_parallel_bible.cpp

/*
** Copyright (C) 2003-2006 Teus Benschop.
**  
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**  
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**  
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
*/


#include "libraries.h"
#include <glib.h>
#include "print_parallel_bible.h"
#include "utilities.h"
#include "bible.h"
#include "usfm.h"
#include "usfmtools.h"
#include <config.h>
#include "pdfviewer.h"
#include "xmlutils.h"
#include "paper.h"
#include "formatter.h"
#include "xmlfo-utils.h"
#include "constants.h"
#include "gwrappers.h"
#include "gtkwrappers.h"
#include "directories.h"
#include "fonts.h"
#include "notecaller.h"
#include "xslfofootnote.h"
#include "xslfoendnote.h"
#include "xslfoxref.h"
#include "mapping.h"
#include "portion_utils.h"
#include "projectutils.h"
#include "generalconfig.h"
#include "projectconfig.h"
#include "progresswindow.h"
#include "session.h"


void view_parallel_bible_pdf ()
/*
Formats the references in "references", and highlights all words in
"session->highlights*" and shows them in a pdf viewer.
*/
{
  // Log.
  gw_message ("Printing Parallel Bible");

  // Configuration
  GeneralConfiguration genconfig (0);
  
  // Get the chapters and check them.
  vector<unsigned int> chapters = project_get_chapters (genconfig.project(), genconfig.book());
  if (chapters.empty()) {
    gtkw_dialog_info (NULL, genconfig.book() + "does not exist in this project");
    return;
  }
    
  // Progress system.
  ProgressWindow progresswindow ("Parallel Bible", true);  
  progresswindow.set_text ("Collecting verses");
  progresswindow.set_iterate (0, 1, chapters.size());
  
  // Prepare for the inline text markers.
  ProjectConfiguration projectconfig ("");
  Usfm usfm (projectconfig.stylesheet());
  UsfmInlineMarkers usfm_inline_markers (usfm);

  // Prepare for leaving out footnotes, endnotes and crossreferences.
  XslFoFootnote xslfofootnote (usfm, false);
  XslFoEndnote xslfoendnote (usfm, false);
  XslFoXref xslfoxref (usfm, false);
  
  // Prepare for mapping.
  Mapping mapping (projectconfig.versification(), genconfig.book());
  
  // Storage for final xsl-fo file.
  vector<ustring> xslfo_lines;

  // Start building the xml-fo file.
  // The various elements of this file are created using objects.
  // When the object goes out of scope, it writes the closing elements.
  {
    XmlFoRoot xmlforoot (&xslfo_lines);
    {
      XmlFoLayoutMasterSet layoutmasterset (&xslfo_lines, false);
    }      
    {
      XmlFoPageSequence pagesequence (&xslfo_lines, false);
      {
        XmlFoStaticContent staticcontent (&xslfo_lines);
      }
      {
        XmlFoFlow flow (&xslfo_lines);
        {
          // Messages to be printed first.
          vector<ustring> messages;
          // All the projects to be put in this parallel Bible, together with
          // their related information, like mapping, fonts.
          vector<ustring> project_s_raw = genconfig.parallel_bible_projects ();
          vector<ustring> project_names;
          vector<Mapping> mapping_s;
          vector<ustring> fonts;
          vector<unsigned int> fontsizes;
          vector<unsigned int> lineheights;
          for (unsigned int i = 0; i < project_s_raw.size(); i++) {
            if (project_book_exists(project_s_raw[i], genconfig.book())) {
              // Only include the project if the book exists in that project.
              ProjectConfiguration projectconfig (project_s_raw[i]);
              project_names.push_back(project_s_raw[i]);
              Mapping mapping (projectconfig.versification(), genconfig.book());
              mapping_s.push_back (mapping);
              PrintingFonts printingfonts (project_s_raw[i]);
              fonts.push_back (printingfonts.printing_families_comma_separated ());
              fontsizes.push_back (projectconfig.printing_font_size());
              lineheights.push_back (projectconfig.printing_line_height());
            } else {
              // Give message if book is not in this project.
              messages.push_back ("Project "  + project_s_raw[i] + " was requested to be included, but it does not contain " + genconfig.book() + ". It was left out.");
            }
          }
          // Print any messages.
          if (messages.size() > 0) {
            xslfo_lines.push_back ("<fo:block font-size=\"120%\" font-weight=\"bold\">");
            xslfo_lines.push_back ("Note");            
            xslfo_lines.push_back ("</fo:block>");
          }
          for (unsigned int i = 0; i < messages.size(); i++) {
            xslfo_lines.push_back ("<fo:block>");
            xslfo_lines.push_back (messages[i]);
            xslfo_lines.push_back ("</fo:block>");
          }
          // Variables for portion selection.
          bool portion_print = false;
          bool portion_print_next_verse_off = false;
          unsigned int portion_chapter_from, portion_chapter_to;
          ustring portion_verse_from, portion_verse_to;
          select_portion_get_values (genconfig.project(), genconfig.book(), genconfig.parallel_bible_chapters_verses(),
                                     portion_chapter_from, portion_verse_from, 
                                     portion_chapter_to, portion_verse_to);
          // Produce chunks for the xsl-fo file for all references.
          for (unsigned int ch = 0; ch < chapters.size(); ch++) {
            // Update progress bar.
            progresswindow.iterate();
            if (progresswindow.cancel) return;
            // Go through the verse numbers in this chapter.
            vector<ustring> verses = project_get_verses (genconfig.project(), genconfig.book(), chapters[ch]);
            for (unsigned int vs = 0; vs < verses.size(); vs++) {
              // See whether this chapter.verse is within our portion to print.
              if ((chapters[ch] == portion_chapter_from) && (verses[vs] == portion_verse_from))
                portion_print = true;
              if (portion_print_next_verse_off)
                portion_print = false;
              if ((chapters[ch] == portion_chapter_to) && (verses[vs] == portion_verse_to))
                portion_print_next_verse_off = true;
              if (!portion_print)
                continue;
              // See whether to print verses zero.
              if (!genconfig.parallel_bible_include_verse_zero())
                if (verses[vs] == "0")
                  continue;
              // Add the block to the xsl-fo file.
              // Next line has keep-together.within-page="always", rather than
              // keep-together="always", as the latter one causes things to be 
              // kept together, in in a line, which causes the line to overflow
              // the right margin.
              if (genconfig.parallel_bible_keep_verses_together())
                xslfo_lines.push_back ("<fo:block keep-together.within-page=\"always\">");
              else
                xslfo_lines.push_back ("<fo:block>");
              // XSLFormatter is better than FOP in that it does honour space conditionality,
              // which is initially set at "discard" for the beginning of a 
              // references area, as here. So to get the distance between the 
              // lines right, this is inserted: space-before.conditionality="retain".
              xslfo_lines.push_back ("  <fo:block space-before=\"2mm\" space-before.conditionality=\"retain\">");
              xslfo_lines.push_back (genconfig.book() + " " + convert_to_string (chapters[ch]) + ":" + verses[vs]);
              xslfo_lines.push_back ("  </fo:block>");
              // Map this verse to the original, that is, to Hebrew or Greek.
              vector<int> hebrew_greek_chapters;
              vector<int> hebrew_greek_verses;
              mapping.me_to_original (chapters[ch], verses[vs], hebrew_greek_chapters, hebrew_greek_verses);
              // Get verse text for each version.
              for (unsigned int vsn = 0; vsn <= project_names.size(); vsn++) {
                // Get the verse text.
                ustring line;
                if (vsn == 0) {
                  // First version.
                  line = project_retrieve_verse (genconfig.project(), genconfig.book(), chapters[ch], verses[vs]);
                } else {
                  // Other versions. 
                  // Get mapped chapters / verses.
                  vector<int> mychapters;
                  vector<int> myverses;
                  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 our container.
                    if (!line.empty()) 
                      line.append ("\n");
                    line.append (project_retrieve_verse (project_names [vsn - 1], genconfig.book(), mychapters[mp], convert_to_string (myverses[mp])));
                  }
                }
                // Take out verse number if it is the desired verse number, else leave it in.
                usfm_extract_marker (line);
                if (line.find (verses[vs]) == 0)
                  line.erase (0, verses[vs].length() + 1);
                // Take out footnotes, endnotes, crossreferences.
                xslfofootnote.transform (NULL, line);
                xslfoendnote.transform (NULL, line);
                xslfoxref.transform (NULL, line);              
                // Change <, > and & to their corresponding entities.
                vector <size_t> highlight_positions;
                xml_handle_entities (line, highlight_positions);
                // Deal with inline markers, so that they do not appear in the output
                // as markers, but format the text instead.
                usfm_handle_inline_text (line, &usfm_inline_markers, NULL);
                // This line has font information for each additional project. 
                ustring blockline;
                {
                  blockline = "  <fo:block";
                  if (vsn > 0) {
                    blockline.append (" font-family=\"" + fonts[vsn-1] + "\" font-size=\"" + convert_to_string (fontsizes[vsn-1]) + "pt\" line-height=\"" + convert_to_string (lineheights[vsn-1]) + "%\"");
                  }                  
                  blockline.append (">");
                }
                // We try to somehow show paragraphs also, basically.
                {
                  ParseLine parseline (line);
                  line.clear();
                  for (unsigned int ln = 0; ln < parseline.lines.size(); ln++) {
                    ustring marker = usfm_extract_marker (parseline.lines[ln]);
                    if (!marker.empty()) {
                      if (usfm.is_starting_paragraph (marker))
                        if (ln > 0) {
                          line.append ("</fo:block>\n");
                          line.append (blockline);
                          line.append ("\n");
                        }                        
                    }
                    line.append (parseline.lines[ln]);
                    line.append ("\n");
                  }
                }
                // Extract any marker left in the line.
                {
                  ustring marker;
                  size_t position, length;
                  bool opening_marker;
                  while (usfm_search_marker (line, marker, position, length, opening_marker)) {
                    line.erase (position, length);
                  }
                }
                // Add the block opener.
                xslfo_lines.push_back (blockline);
                ustring project;
                if (vsn == 0)
                  project = genconfig.project();
                else
                  project = project_names[vsn - 1];
                xslfo_lines.push_back ("<fo:inline font-size=\"70%\">" + project + "</fo:inline> ");
                xslfo_lines.push_back (line);
                xslfo_lines.push_back ("  </fo:block>");
              }
              // Close main block.
              xslfo_lines.push_back ("</fo:block>");
            }
          }
        }
      }
    }
  }
  
  // Make a temporary directory where to put the working files and the resulting
  // .pdf file.information. This directory is not removed, because the pdf viewer 
  // needs the .pdf file to be there during viewing or printing.
  string working_directory = gw_build_filename(directories_get_temp(), "parallelbible");
  create_directory (working_directory);
  // Produce filename of .fo file.
  string fofilename = gw_build_filename(working_directory, "document.fo");
  // Write the document.
  write_lines (fofilename, xslfo_lines);
  // Tell user to be patient while we pdfxmltex runs.  
  progresswindow.set_text ("Typesetting pages ...");
  if (progresswindow.cancel) return;
  // Store the additional projects to print.
  {
    Session session (0);
    session.additional_printing_projects (genconfig.parallel_bible_projects ());
  }
  // Convert the xsl-fo document to .pdf.
  NoteCaller dummy (nntNumerical, "", false);
  string pdffilename = gw_build_filename(working_directory, "document.pdf");
  int conversion_result = formatter_convert_to_pdf (fofilename, pdffilename, progresswindow, &dummy, &dummy);
  // Progressbar: ready.
  progresswindow.set_fraction (1);
  progresswindow.set_text ("Ready");
  if (progresswindow.cancel) return;
  // View the .pdf document.
  pdfviewer (pdffilename);
  // Give message if there were errors.
  if (conversion_result != 0) {
    string message = "The formatter had some trouble.\n"
                     "See menu Help - System log for more details.\n"
                     "See the helpfile for a possible solution.";
    gtkw_dialog_error (NULL, message);
  };
  // Log: ready.
  gw_message ("Ready printing the Parallel Bible");
}

Generated by  Doxygen 1.6.0   Back to index