Esempio n. 1
0
ustring stylesheet_import(const ustring & filename)
// Imports a new stylesheet from "filename".
// It expects a file in the format as it is given in the export function.
{
  // See that the sheet is a recognized one.
  // Derive the name of the new stylesheet from the filename.
  ustring name;
  for (unsigned int i = 0; i < (sizeof(RECOGNIZED_SUFFIXES) / sizeof(*RECOGNIZED_SUFFIXES)); i++) {
    if (g_str_has_suffix(filename.c_str(), RECOGNIZED_SUFFIXES[i])) {
      name = gw_path_get_basename(filename);
      name.erase(name.length() - strlen(RECOGNIZED_SUFFIXES[i]), strlen(RECOGNIZED_SUFFIXES[i]));
    }
  }
  if (name.empty()) {
    gtkw_dialog_error(NULL, _("Unrecognized stylesheet: ") + filename);
    return "";
  }
  // Check whether it already exists.
  if (stylesheet_exists(name)) {
    gtkw_dialog_error(NULL, _("Stylesheet already exists: ") + name);
    return "";
  }
  // Get the path of the new stylesheet.
  ustring path = stylesheet_xml_filename(name);
  // Copy the file.
  unix_cp(filename, path);
  // Upgrade the stylesheet.
  stylesheets_upgrade();
  // Return the name of the stylesheet we imported;
  return name;
}
Esempio n. 2
0
void gtkw_show_uri (ustring uri, bool internet)
{
  ustring prefix;
  if (internet) prefix = "http://";
  else prefix = "file://";
  
  // Handle if Windows.
#ifdef WIN32
// False start on fixing error in Windows: it doesn't require slashes to be forward.
//	uri = Directories->backslashes_to_forwardslashes(uri);
  DEBUG("Showing URI " + uri)
  GwSpawn spawn(uri);
  spawn.run();
  // Got rid of outpost for this one
  //windowsoutpost_open_url(uri);
  return;
// Maybe need to quote the filenames
//    uri = "\"" + uri + "\"";
#endif
  uri = prefix + uri;
  DEBUG("Showing URI " + uri)
  // Handle Unix.
  GError *error = NULL;
  if (!gtk_show_uri (NULL, uri.c_str(), GDK_CURRENT_TIME, &error)) {
    ustring message = _("Trying to open ") + uri + ": " + error->message;
    cerr << message << endl;
    gtkw_dialog_error(NULL, message);
    g_error_free(error);
  }
}
Esempio n. 3
0
void FiltersDialog::on_button_new()
{
  // Enter the name of the new script.
  EntryDialog namedialog(_("New script"), _("Enter the name of the new script"), "");
  if (namedialog.run() != GTK_RESPONSE_OK)
    return;

  if (script_available(namedialog.entered_value)) {
    gtkw_dialog_error(filterdialog, _("This one already exists"));
    return;
  }
  // Enter the type of the new script.
  vector < ustring > types;
  for (unsigned int i = 0; i < stEnd; i++)
    types.push_back(script_get_named_type((ScriptType) i));
  RadiobuttonDialog typedialog(_("Script type"), _("Select the type of the script"), types, 0, false);
  if (typedialog.run() != GTK_RESPONSE_OK)
    return;

  // Handle the rest.
  g_file_set_contents(script_get_path(namedialog.entered_value, (ScriptType) typedialog.selection).c_str(), "", -1, NULL);
  load_filters(namedialog.entered_value);
}
ExportTranslationNotes::ExportTranslationNotes(const ustring & filename, const vector < unsigned int >&ids_to_display, bool export_all)
// Exports the notes from the database.
/*
The exported xml file will look so:

<?xml version="1.0" encoding="UTF-8"?>
<bibledit-notes version="3">
  <note>
    <reference>
    </reference>
    <project>
    </project>
    <category>
    </category>
    <text>
    </text>
    <date-created>
    </date-created>
    <date-modified>
    </date-modified>
    <user>
    </user>
  </note>
</bibledit-notes>

This is subject to change as bibledit's notes system develops.
*/
:progresswindow("Exporting notes", true)
{
  // Save variables.
  my_export_all = export_all;

  // Start process.
  try {

    // Write to outputfile.
    WriteText wt(filename);
    my_wt = &wt;

    // Opening lines.
    wt.text("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
    wt.text("<bibledit-notes version=\"4\">\n");

    // Connect to index database.
    // Note: The index is not the source of the notes.
    // This implies that, if the index is not up-to-date, 
    // then the export will not be correct.
    error = NULL;
    rc = sqlite3_open(notes_index_filename().c_str(), &db);
    if (rc)
      throw runtime_error(sqlite3_errmsg(db));
    sqlite3_busy_timeout(db, 1000);
    
    // Currently this is the notes table schema:
    // id integer, reference text, project text, category text, casefolded text, created integer, modified integer

    // Get the number of notes.
    SqliteReader sqlitereader(0);
    rc = sqlite3_exec(db, "select count(*) from notes;", sqlitereader.callback, &sqlitereader, &error);
    if (rc != SQLITE_OK) {
      throw runtime_error(error);
    }
    if (!sqlitereader.ustring0.empty()) {
      notes_count = convert_to_int (sqlitereader.ustring0[0]);
    }
    progresswindow.set_iterate(0, 1, notes_count);

    // Exporting everything or a selection?
    set < gint > ids(ids_to_display.begin(), ids_to_display.end());
    my_ids = &ids;

    // Go through all the notes.
    note_counter = 0;
    rc = sqlite3_exec(db, "select reference, project, category, casefolded, created, modified from notes;", data_callback, this, &error);
    if (rc != SQLITE_OK) {
      throw runtime_error(error);
    }
    // Closing lines.
    wt.text("</bibledit-notes>\n");

  }
  catch(exception & ex) {
    if (!progresswindow.cancel) {
      gtkw_dialog_error(NULL, ex.what());
      gw_critical(ex.what());
    }
  }
}
void GotoReferenceDialog::show_bad_reference()
{
  ustring message = "No such reference: ";
  message.append(gtk_entry_get_text(GTK_ENTRY(entry_free)));
  gtkw_dialog_error(dialog, message);
}
Esempio n. 6
0
void WindowMerge::merge_edited_into_master(bool approve)
// This merges the edited data into the master data, and does error checking.
{
  // Bail out if there's nothing to merge.
  if (main_project_data == edited_project_data) {
    gtkw_dialog_info(NULL, _("Both the chapters already are the same"));
    return;
  }

  // Get the available snapshots of the master and edited projects.
  vector <unsigned int> masterseconds = snapshots_get_seconds (current_master_project, book, chapter);
  vector <unsigned int> editedseconds = snapshots_get_seconds (current_edited_project, book, chapter);

  // We need to look for the common ancestor.
  // It needs a fast routine that goes through the history as little as possible.

  // Make a combined set of the times and flags.
  vector <bool> combinedflags;
  vector <unsigned int> combinedseconds;
  for (unsigned int i = 0; i < masterseconds.size(); i++) {
    combinedflags.push_back (true);
    combinedseconds.push_back (masterseconds[i]);    
  }
  for (unsigned int i = 0; i < editedseconds.size(); i++) {
    combinedflags.push_back (false);
    combinedseconds.push_back (editedseconds[i]);    
  }
  // Sort the combined set on the time, most recent ones first.
  quick_sort (combinedseconds, combinedflags, 0, combinedseconds.size());
  {
    vector <bool> flags = combinedflags;
    vector <unsigned int> seconds = combinedseconds;
    combinedflags.clear();
    combinedseconds.clear();
    for (int i = flags.size() - 1; i >= 0; i--) {
      combinedflags.push_back (flags[i]);
      combinedseconds.push_back (seconds[i]);
    }
  }

  // Go through the history of both projects, extract the state in history,
  // and compare them in order to find the common ancestor.
  vector <ustring> mastertexts;
  vector <ustring> editedtexts;
  ustring common_ancestor;
  for (unsigned int i = 0; i < combinedseconds.size(); i++) {
    unsigned int second = combinedseconds[i];
    bool master = combinedflags[i];
    if (master) {
      mastertexts.push_back(snapshots_get_chapter(current_master_project, book, chapter, second));
    } else {
      editedtexts.push_back(snapshots_get_chapter(current_edited_project, book, chapter, second));
    }
    for (unsigned int m = 0; m < mastertexts.size(); m++) {
      for (unsigned int e = 0; e < editedtexts.size(); e++) {
        if (common_ancestor.empty()) {
          if (mastertexts[m] == editedtexts[e]) {
            common_ancestor = mastertexts[m];
          }
        }
      }
    }
    if (!common_ancestor.empty()) {
      break;
    }
  }  

  // If no common ancestor was found, give message and bail out.
  if (common_ancestor.empty()) {
    gtkw_dialog_error(NULL, _("Can't merge because a common ancestor was not found"));
    return;
  }
  // Do the merge in a temporal directory.
  workingdirectory = gw_build_filename(Directories->get_temp(), "merge");
  unix_rmdir(workingdirectory);
  gw_mkdir_with_parents(workingdirectory);

  /*
     Merge works with file1, file2 and file3.

     merge [ options ] file1 file2 file3

     merge incorporates all changes that lead from file2 to file3 into file1.
     The result ordinarily goes into file1.
     merge is useful for combining separate changes to an original. 
     Suppose file2 is the original, and both file1 and file3 are modifications of file2. 
     Then merge combines both changes.
   */
  ustring file1 = gw_build_filename(workingdirectory, "file1");
  ustring file2 = gw_build_filename(workingdirectory, "file2");
  ustring file3 = gw_build_filename(workingdirectory, "file3");

  /*
     merge has problems when two consecutive lines are changed, 
     one line in one file and the other line in the other file. 
     Therefore data is going to be cut on the spaces, 
     so that there is one word per line. 
     Each new line is indicated too so as to facilitate joining the loose bits again.
     Another advantage of this is that the merge operation becomes finer grained.
   */

  // Write the data for the common ancestor.
  g_file_set_contents(file2.c_str(), merge_split_data(common_ancestor).c_str(), -1, NULL);

  // Write the data for the main project.
  g_file_set_contents(file1.c_str(), merge_split_data(main_project_data).c_str(), -1, NULL);

  // Write the data for the edited project.
  g_file_set_contents(file3.c_str(), merge_split_data(edited_project_data).c_str(), -1, NULL);

  // Do the three-way merge.
  {
    GwSpawn spawn("merge");
    spawn.workingdirectory(workingdirectory);
    spawn.arg(file1);
    spawn.arg(file2);
    spawn.arg(file3);
    spawn.run();
  }

  // Read the result of the merge.
  ustring merge_result;
  {
    gchar *contents;
    g_file_get_contents(file1.c_str(), &contents, NULL, NULL);
    if (contents) {
      merge_result = contents;
      g_free(contents);
    }
  }

  // Make conflicts human readable.
  merge_result = merge_conflicts_2_human_readable_text(merge_result);

  // Join the bits again.
  merge_result = merge_join_data(merge_result);

  // If there are conflicts, resolve them.
  if (merge_result.find(merge_conflict_markup(1)) != string::npos) {
    MergeDialog dialog(merge_result);
    if (dialog.run() == GTK_RESPONSE_OK) {
      merge_result = dialog.reconciled_text;
    }
  }
  // If there are still conflicts, give a message and bail out.
  if (merge_result.find(merge_conflict_markup(1)) != string::npos) {
    gtkw_dialog_error(NULL, _("The chapters were not merged"));
    return;
  }

  if (approve) {

    // Setup the approval system.
    approval_setup(main_project_data, merge_result);

  } else {

    // Store the merge result in both chapters.  
    ParseLine parseline(merge_result);
    CategorizeChapterVerse ccv(parseline.lines);
    project_store_chapter(current_master_project, book, ccv);
    project_store_chapter(current_edited_project, book, ccv);
    // A normal snapshot may be removed over time, so we need a persistent one to enable future merges.
    snapshots_shoot_chapter (current_master_project, book, chapter, 0, true);
    snapshots_shoot_chapter (current_edited_project, book, chapter, 0, true);

    // Message ok.
    gtkw_dialog_info(NULL, _("The chapters were successfully merged"));

  }
}