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

export_utils.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 "utilities.h"
#include "export_utils.h"
#include "bible.h"
#include "usfm.h"
#include "usfmtools.h"
#include "notes_utils.h"
#include "date_time_utils.h"
#include "export_translation_notes.h"
#include "constants.h"
#include "gwrappers.h"
#include "dialogsword.h"
#include "directories.h"
#include "unixwrappers.h"
#include "gtkwrappers.h"
#include "shell.h"
#include "swordnote.h"
#include "xmlutils.h"
#include "languages.h"
#include "osis.h"
#include "mapping.h"
#include "projectutils.h"
#include "books.h"
#include "progresswindow.h"
#include "generalconfig.h"
#include "projectconfig.h"
#include "session.h"


void export_to_usfm (GtkWidget * parent)
// Export the whole project to USFM files.
{
  GeneralConfiguration genconfig (0);
  Session session (0);
  ustring directory = gtkw_file_chooser_select_folder (parent, "Select the folder where to store the files", session.export_usfm_directory());
  if (!directory.empty()) {
    session.export_usfm_directory (directory);
    ustring command = "bibledit --export-project-usfm --gui ";
    command.append ("--project" + shell_quote_space (genconfig.project()));
    command.append ("--directory" + shell_quote_space (directory));
    command.append ("&");
    system (command.c_str());
  }    
}


void export_to_bibleworks (GtkWidget * parent)
/*
Exports a whole project to a file that is fit for being imported by the 
BibleWorks Version Database Compiler.
This done in this manner:
- If an \id line is found, use its ID to get the name of the book in BibleWorks.
- If an chapter tag if found, use its number.
- As soon as an ID is found, put the current chapter at one.
- If a verse is found, add its number.
- Text of tags known not to be printable is thrown out.
- Any other tag's text gets added to the text of the verse.
Yes, this is a bit rough, I know...
*/
{
  // Configuration
  GeneralConfiguration genconfig (0);
  // Get the filename where the data to save to.
  GtkWidget *dialog;
  dialog = gtk_file_chooser_dialog_new ("Save to a file", GTK_WINDOW (parent),
    GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
    GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
  gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog), genconfig.export_to_bibleworks_filename().c_str ());
  int result = gtk_dialog_run (GTK_DIALOG (dialog));
  ustring filename;
  if (result == GTK_RESPONSE_ACCEPT) 
    filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
  gtk_widget_destroy (dialog);  
  if (result == GTK_RESPONSE_ACCEPT) {
    // Store (new) filename.
    genconfig.export_to_bibleworks_filename_set (filename);
    // Progress bar.
    ProgressWindow progresswindow ("Export", true);
    // Start process.
    try
    {
      ProjectConfiguration projectconfig ("");
      Usfm usfm (projectconfig.stylesheet());
      // Write to outputfile.
      WriteText wt (filename);
      // Get all the books and go through them.
      vector<ustring> scripture_books = project_get_books (genconfig.project());
      progresswindow.set_iterate (0, 1, scripture_books.size());
      progresswindow.set_text ("Exporting");
      for (unsigned int bk = 0; bk < scripture_books.size(); bk++) {
        // Progress information.
        progresswindow.iterate();
        if (progresswindow.cancel) return;
        // Get the abbreviation to be used.
        ustring abbreviation;
        unsigned index = books_english_to_id (scripture_books[bk]);
        abbreviation = books_id_to_bibleworks (index);
        // Handle each chapter in the book.
        vector<unsigned int> chapters = project_get_chapters (genconfig.project(), scripture_books[bk]);
        for (unsigned int ch = 0; ch < chapters.size(); ch++) {
          // Do not export chapter 0.
          if (chapters[ch] == 0)
            continue;
          // Get the chapter and handle it.
          vector<ustring> lines;
          lines = project_retrieve_chapter (genconfig.project(), scripture_books[bk], chapters[ch]);
          CategorizeChapterVerse ccv (lines);
          for (unsigned int vs = 0; vs < ccv.verse.size(); vs++) {
            // Do not export verse 0.
            if (ccv.verse[vs] == "0")
              continue;
            // Bibledit does not handle combined verses like 1-4a., etc. So make
            // a simple verse.
            ustring verse = number_in_string (ccv.verse[vs]);
            // Remove the verse number from the line itself, except when the verse
            // was not a simple one, e.g. it was something like verse 1-3.
            size_t position = ccv.line[vs].find (" ");
            if (position != string::npos)
              ccv.line[vs].erase (0, ++position);
            if (verse == ccv.verse[vs]) {
              position = ccv.line[vs].find (" ");
              if (position != string::npos)
                ccv.line[vs].erase (0, ++position);
            }
            CategorizeLine cat_line (ccv.line [vs]);
            // Output verse.
            wt.text(abbreviation);
            wt.text(" ");
            wt.text(convert_to_string (chapters[ch]));
            wt.text(":");
            wt.text(verse);
            wt.text(" ");
            wt.text(cat_line.verse);
            wt.text("\n");
          }
        }
      }
    }
    catch (exception & ex)
    {
      cerr << "Converting to BibleWorks: " << ex.what () << endl;
    }
  }
}


void export_translation_notes (const ustring& filename, ExportNotesFormat format, const vector<unsigned int> & ids_to_display, bool export_all, GtkWidget * parent)
{
  ExportTranslationNotes etn (filename, format, ids_to_display, export_all, parent);
}


void export_to_sword_interactive ()
// Exports a whole project to a SWORD module.
{
  // Dialog for information entry.
  {
    SwordDialog sworddialog (0);
    if (sworddialog.run() != GTK_RESPONSE_OK)
      return;
  }
  GeneralConfiguration genconfig (0);
  export_to_sword_script (genconfig.project(), "", true);
}


void export_to_sword_script (const ustring& project, ustring directory, bool gui)
/*
Exports a whole project to a SWORD module.
At the time of writing this, the information on how to create a module for 
sword was found at http://www.crosswire.org/sword/develop/swordmodule/
Here's how we do the conversion
- A .conf file is created and put in ~/.sword/mods.d/
- We use the "osis" format as this offers most options and seems best supported.
- Create the module with program osis2mod.
- The text will be stored in ~/.sword/modules/texts/bibledit/<name>/
*/
{
  // Check for converter.
  if (!unix_which ("osis2mod")) {
    ustring message = "The SWORD compiler osis2mod was not found.";
    if (gui) gtkw_dialog_error (NULL, message);
    cerr << message << endl;
    return;
  }
  // Directory to store module.
  if (directory.empty())
    directory = g_get_home_dir();
  // Configuration
  GeneralConfiguration genconfig (0);
  // Progress information.
  ProgressWindow * progresswindow = NULL;
  if (gui) progresswindow = new ProgressWindow ("Exporting project", true);
  // Open the project that contains the data.
  ProjectConfiguration projectconfig (project);
  // The temporal directories for the data.
  ustring base_directory = gw_build_filename (directories_get_temp(), "sword");
  remove_directory (base_directory);
  create_directory (base_directory);
  ustring absolute_conf_directory = gw_build_filename (base_directory, "mods.d");
  create_directory (absolute_conf_directory);
  ustring relative_text_directory = gw_build_filename ("modules", "texts", "bibledit", lowerCase (genconfig.project() + projectconfig.sword_name()));
  ustring absolute_text_directory = gw_build_filename (base_directory, relative_text_directory);
  create_directory (absolute_text_directory);
  // Create the configuration file.
  vector<ustring> lines;
  ustring line;
  lines.push_back ("[" + genconfig.project() + projectconfig.sword_name() + "]");
  line = "DataPath=.";
  line.append (G_DIR_SEPARATOR_S + relative_text_directory + G_DIR_SEPARATOR_S);
  lines.push_back (line);
  lines.push_back ("ModDrv=RawText");
  lines.push_back ("SourceType=OSIS");
  lines.push_back ("Encoding=UTF-8");
  lines.push_back ("BlockType=BOOK");
  lines.push_back ("GlobalOptionFilter=OSISStrongs");
  lines.push_back ("GlobalOptionFilter=OSISMorph");
  lines.push_back ("GlobalOptionFilter=OSISFootnotes");
  lines.push_back ("GlobalOptionFilter=OSISHeadings");
  lines.push_back ("GlobalOptionFilter=OSISRedLetterWords");
  lines.push_back ("MinimumVersion=1.5.6");
  lines.push_back ("Lang=" + language_encode (projectconfig.sword_language()));
  lines.push_back ("Version=" + projectconfig.sword_version());
  lines.push_back ("Description=" + genconfig.project() + projectconfig.sword_description());
  lines.push_back ("About=" + genconfig.project() + projectconfig.sword_about());
  lines.push_back ("LCSH=" + projectconfig.sword_lcsh());
  lines.push_back ("DistributionLicense=" + projectconfig.sword_license());
  write_lines (gw_build_filename (absolute_conf_directory, lowerCase (genconfig.project() + projectconfig.sword_name()) + ".conf"), lines);
  lines.clear();
  // Start process of producing the text file.
  ustring inputfile;
  try
  {
    // Prepare for notes and inline text.
    Usfm usfm (projectconfig.stylesheet());
    SwordNote swordnote (usfm, true);
    UsfmInlineMarkers usfm_inline_markers (usfm);
    // Write to inputfile.
    inputfile = gw_build_filename (directories_get_temp(), "sword_osis_input.txt");
    unlink (inputfile.c_str());
    WriteText wt (inputfile);
    // Write out xml headers.
    OsisRoot osisroot (&wt, genconfig.project() + projectconfig.sword_name(), genconfig.project() + projectconfig.sword_description());
    // Get all the books and go through them.
    vector <ustring> scripture_books = project_get_books (genconfig.project());
    if (gui)
      progresswindow->set_iterate (0, 1, scripture_books.size());
    for (unsigned int bk = 0; bk < scripture_books.size(); bk++) {
      // Progress information.
      if (gui) {
        progresswindow->iterate();
        progresswindow->set_text (scripture_books[bk]);
        if (progresswindow->cancel) {
          delete progresswindow;
          return;
        }
      }
      cout << scripture_books[bk] << endl;
      // Signal "new book" to notes system.
      swordnote.new_book ();
      // Open book in osis code.
      OsisBook osisbook (&wt, scripture_books[bk]);
      // Verse mapping. SWORD's versification is according to the King James 
      // Bible, called "English" in our system.
      Mapping mymapping (projectconfig.versification(), scripture_books[bk]);
      Mapping swordmapping ("English", scripture_books[bk]);
      // Go through the book and remap verses, if need be.
      vector<unsigned int> remapped_chapters;
      vector<ustring> remapped_verses;
      vector<ustring> remapped_lines;
      {
        ustring myverse = "0";
        ustring swordverse = "0";
        int mychapter = 0;
        int swordchapter = 0;
        vector <ustring> book_lines = project_retrieve_book (genconfig.project(), scripture_books[bk]);
        for (unsigned int i2 = 0; i2 < book_lines.size(); i2++) {
          ustring line = book_lines[i2];
          ustring marker = usfm_extract_marker (line);
          if (usfm.is_chapter_number (marker)) {
            mychapter = convert_to_int (number_in_string (line));
          } else if (usfm.is_verse_number (marker)) {
            // Extract verse number.
            size_t position = line.find (" ");
            position = CLAMP (position, 0, line.length());
            myverse = line.substr (0, position);
            // Erase verse number from the line.
            position++;
            line.erase (0, position);
            // Remap verse, add original verse in brackets if a difference is found.
            vector<int> originalchapters;
            vector<int> originalverses;
            mymapping.me_to_original (mychapter, myverse, originalchapters, originalverses);
            vector<int> swordchapters;
            vector<int> swordverses;
            swordmapping.original_to_me (originalchapters, originalverses, swordchapters, swordverses);
            swordchapter = swordchapters[0];
            swordverse.clear();
            for (unsigned int i3 = 0; i3 < swordverses.size(); i3++) {
              if (i3 > 0)
                swordverse.append (",");
              swordverse.append (convert_to_string (swordverses[i3]));
            }
            bool chaptermapped = (swordchapters[0] != mychapter);
            bool versemapped = (swordverse != myverse);
            if (versemapped | chaptermapped) {
              line.insert (0, ") ");
              if (versemapped)
                line.insert (0, myverse);
              if (chaptermapped)
                line.insert (0, convert_to_string (mychapter) + ".");
              line.insert (0, "(");
            }
            // Store data.
            remapped_chapters.push_back (swordchapter);
            remapped_verses.push_back (swordverse);
            remapped_lines.push_back (line);
          } else {
            // Store data.
            remapped_chapters.push_back (swordchapter);
            remapped_verses.push_back (swordverse);
            // Store line with marker in it. Needed for formatting.
            remapped_lines.push_back (book_lines[i2]);
          }
        } 
      }
      // Default to opening chapter 0 and verse 0.
      unsigned int current_chapter = 0;
      ustring current_verse = "0";
      OsisChapter * osischapter = new OsisChapter (&wt, osisbook.book, current_chapter);
      OsisVerse * osisverse = new OsisVerse (&wt, osisbook.book, osischapter->chapter, current_verse);
      OsisParagraph * osisparagraph = NULL;
      // Go through all the lines of the remapped book.
      for (unsigned int i2 = 0; i2 < remapped_chapters.size(); i2++) {
        ustring line = remapped_lines[i2];
        // Change certain characters to xml entities.
        vector <size_t> dummy;
        xml_handle_entities (line, dummy);
        // Deal with notes.
        swordnote.transform (line);
        // Deal with inline text.
        usfm_handle_inline_text (line, &usfm_inline_markers, NULL, true);
        // Deal with a new chapter.
        if (remapped_chapters[i2] != current_chapter) {
          // Close verse, chapter.
          delete osisverse;
          delete osischapter;
          // Store new chapter.
          current_chapter = remapped_chapters[i2];
          // Reopen chapter and verse.
          osischapter = new OsisChapter (&wt, osisbook.book, current_chapter);
          current_verse = "0";
          osisverse = new OsisVerse (&wt, osisbook.book, osischapter->chapter, current_verse);
          // Signal new chapter to notes system.
          swordnote.new_chapter ();
        }
        // Handle new verse.
        if (current_verse != remapped_verses[i2]) {
          // Close osis verse.
          delete osisverse;
          // Store new verse.
          current_verse = remapped_verses[i2];
          // Reopen osis verse.
          osisverse = new OsisVerse (&wt, osisbook.book, osischapter->chapter, current_verse);
        }
        // Get the style belonging to the marker.
        ustring marker = usfm_extract_marker (line);
        if (usfm.is_identifier (marker)) {
          // Do nothing with an identifier.
        } else if (usfm.is_comment (marker)) {
          // Skip comments.
        } else if (usfm.is_running_header (marker)) {
          // Skip running headers.
        } else if (usfm.is_starting_paragraph (marker)) {
          // Find out what type of paragraph it is.
          ParagraphType paragraphtype = usfm.paragraph_get_subtype (marker);
          bool close_paragraph = false;
          bool new_paragraph = false;
          ustring title_type;
          switch (paragraphtype) {
            case ptMainTitle:
              close_paragraph = true;
              title_type = "main";
              break;
            case ptSubTitle:
              close_paragraph = true;
              title_type = "sub";
              break;
            case ptSectionHeading:
              close_paragraph = true;
              title_type = "part";
              break;
            case ptNormalParagraph:
              close_paragraph = true;
              new_paragraph = true;
              break;
          }
          // Close if need be.
          if (close_paragraph) {
            if (osisparagraph)
              delete osisparagraph;
            osisparagraph = NULL;
          }
          // Open new one if needed.
          if (new_paragraph) {
            osisparagraph = new OsisParagraph (&wt);
          }
          // Handle titles also.
          if (!title_type.empty()) {
            wt.text ("<title type=\"" + title_type + "\">");
          }
          // Output text.
          wt.text (line);
          // Close title if need be.
          if (!title_type.empty()) {
            wt.text ("</title>");
          }
        } else if (usfm.is_inline_text (marker)) {
          // Inline text, has been dealt with before (therefore should never occur here).
          wt.text (line);
        } else {
          // Fallback for verse marker (removed before), unknown marker, or no marker.
          wt.text (line);
        }
      } 
      // Close paragraph, verse and chapter.      
      if (osisparagraph)
        delete osisparagraph;
      delete osisverse;
      delete osischapter;
    }
  }
  catch (exception & ex)
  {
    cerr << "Export: " << ex.what () << endl;
  }
  // Hide progress.
  if (progresswindow) delete progresswindow;
  // Convert the inputfile using the sword api utility.
  ustring command;
  command = "osis2mod " + absolute_text_directory + " " + inputfile;
  run_shell_progress (command, "osis2mod", gui, "Compiling", true, 3000000);
  // Install it.
  command = "cp -r " + gw_build_filename (base_directory, "*") + " " + genconfig.export_to_sword_install_path();
  system (command.c_str());
  // Compress and save the module.
  ustring zipfile = temporary_file (genconfig.project() + projectconfig.sword_name()) + ".zip";
  unlink (zipfile.c_str());
  command = "cd" + shell_quote_space (base_directory) + "; ";
  command.append ("zip -r" + shell_quote_space (zipfile) + "*");
  system (command.c_str());
  command = "mv" + shell_quote_space (zipfile) + shell_quote_space (genconfig.export_to_sword_module_path());
  system (command.c_str());
}

Generated by  Doxygen 1.6.0   Back to index