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

dialogsynchronize.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 "dialogsynchronize.h"
#include "generalconfig.h"
#include "listview.h"
#include "projectutils.h"
#include "progresswindow.h"
#include "compareutils.h"
#include "session.h"
#include "printreferences.h"
#include "gtkwrappers.h"
#include "import.h"
#include "utilities.h"


SynchronizeDialog::SynchronizeDialog (int dummy)
{
  GeneralConfiguration configuration (0);

  synchronizedialog = gtk_dialog_new ();
  gtk_window_set_title (GTK_WINDOW (synchronizedialog), "Synchronize");
  gtk_window_set_type_hint (GTK_WINDOW (synchronizedialog), GDK_WINDOW_TYPE_HINT_DIALOG);

  dialog_vbox1 = GTK_DIALOG (synchronizedialog)->vbox;
  gtk_widget_show (dialog_vbox1);

  vbox1 = gtk_vbox_new (FALSE, 6);
  gtk_widget_show (vbox1);
  gtk_box_pack_start (GTK_BOX (dialog_vbox1), vbox1, TRUE, TRUE, 0);

  scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
  gtk_widget_show (scrolledwindow1);
  gtk_box_pack_start (GTK_BOX (vbox1), scrolledwindow1, TRUE, TRUE, 0);
  gtk_widget_set_size_request (scrolledwindow1, 750, 175);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_SHADOW_IN);

  treeview1 = gtk_tree_view_new ();
  gtk_widget_show (treeview1);
  gtk_container_add (GTK_CONTAINER (scrolledwindow1), treeview1);
  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview1), FALSE);

  hbox3 = gtk_hbox_new (FALSE, 5);
  gtk_widget_show (hbox3);
  gtk_box_pack_start (GTK_BOX (vbox1), hbox3, TRUE, TRUE, 0);

  button_differences = gtk_button_new ();
  gtk_widget_show (button_differences);
  gtk_box_pack_start (GTK_BOX (hbox3), button_differences, FALSE, FALSE, 0);

  alignment2 = gtk_alignment_new (0.5, 0.5, 0, 0);
  gtk_widget_show (alignment2);
  gtk_container_add (GTK_CONTAINER (button_differences), alignment2);

  hbox4 = gtk_hbox_new (FALSE, 2);
  gtk_widget_show (hbox4);
  gtk_container_add (GTK_CONTAINER (alignment2), hbox4);

  image2 = gtk_image_new_from_stock ("gtk-zoom-fit", GTK_ICON_SIZE_BUTTON);
  gtk_widget_show (image2);
  gtk_box_pack_start (GTK_BOX (hbox4), image2, FALSE, FALSE, 0);

  label4 = gtk_label_new_with_mnemonic ("Show _differences");
  gtk_widget_show (label4);
  gtk_box_pack_start (GTK_BOX (hbox4), label4, FALSE, FALSE, 0);

  button_import = gtk_button_new ();
  gtk_widget_show (button_import);
  gtk_box_pack_start (GTK_BOX (hbox3), button_import, FALSE, FALSE, 0);

  alignment3 = gtk_alignment_new (0.5, 0.5, 0, 0);
  gtk_widget_show (alignment3);
  gtk_container_add (GTK_CONTAINER (button_import), alignment3);

  hbox5 = gtk_hbox_new (FALSE, 2);
  gtk_widget_show (hbox5);
  gtk_container_add (GTK_CONTAINER (alignment3), hbox5);

  image3 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_BUTTON);
  gtk_widget_show (image3);
  gtk_box_pack_start (GTK_BOX (hbox5), image3, FALSE, FALSE, 0);

  label5 = gtk_label_new_with_mnemonic ("_Import into project");
  gtk_widget_show (label5);
  gtk_box_pack_start (GTK_BOX (hbox5), label5, FALSE, FALSE, 0);

  button_export = gtk_button_new ();
  gtk_widget_show (button_export);
  gtk_box_pack_start (GTK_BOX (hbox3), button_export, FALSE, FALSE, 0);

  alignment4 = gtk_alignment_new (0.5, 0.5, 0, 0);
  gtk_widget_show (alignment4);
  gtk_container_add (GTK_CONTAINER (button_export), alignment4);

  hbox6 = gtk_hbox_new (FALSE, 2);
  gtk_widget_show (hbox6);
  gtk_container_add (GTK_CONTAINER (alignment4), hbox6);

  image4 = gtk_image_new_from_stock ("gtk-save", GTK_ICON_SIZE_BUTTON);
  gtk_widget_show (image4);
  gtk_box_pack_start (GTK_BOX (hbox6), image4, FALSE, FALSE, 0);

  label6 = gtk_label_new_with_mnemonic ("_Export to file");
  gtk_widget_show (label6);
  gtk_box_pack_start (GTK_BOX (hbox6), label6, FALSE, FALSE, 0);

  dialog_action_area1 = GTK_DIALOG (synchronizedialog)->action_area;
  gtk_widget_show (dialog_action_area1);
  gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END);

  cancelbutton1 = gtk_button_new_from_stock ("gtk-cancel");
  // gtk_widget_show (cancelbutton1);
  gtk_dialog_add_action_widget (GTK_DIALOG (synchronizedialog), cancelbutton1, GTK_RESPONSE_CANCEL);
  GTK_WIDGET_SET_FLAGS (cancelbutton1, GTK_CAN_DEFAULT);

  okbutton1 = gtk_button_new_from_stock ("gtk-ok");
  gtk_widget_show (okbutton1);
  gtk_dialog_add_action_widget (GTK_DIALOG (synchronizedialog), okbutton1, GTK_RESPONSE_OK);
  GTK_WIDGET_SET_FLAGS (okbutton1, GTK_CAN_DEFAULT);

  g_signal_connect ((gpointer) treeview1, "row_activated", 
                    G_CALLBACK (on_treeview1_row_activated), 
                    gpointer (this));
  g_signal_connect_after ((gpointer) treeview1, "move_cursor", 
                    G_CALLBACK (on_treeview1_move_cursor), 
                    gpointer(this));                    
  g_signal_connect ((gpointer) treeview1, "cursor_changed", 
                    G_CALLBACK (on_treeview1_cursor_changed), 
                    gpointer(this));
  g_signal_connect ((gpointer) button_differences, "clicked",
                    G_CALLBACK (on_button_differences_clicked),
                    gpointer(this));
  g_signal_connect ((gpointer) button_import, "clicked",
                    G_CALLBACK (on_button_import_clicked),
                    gpointer(this));
  g_signal_connect ((gpointer) button_export, "clicked",
                    G_CALLBACK (on_button_export_clicked),
                    gpointer(this));

  gtk_widget_grab_focus (treeview1);
  gtk_widget_grab_default (okbutton1);
  
  // Storage, renderer, column and selection.
  store1 = gtk_list_store_new (1, G_TYPE_STRING);
  gtk_tree_view_set_model (GTK_TREE_VIEW (treeview1), GTK_TREE_MODEL (store1));
  g_object_unref (store1);
  GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
  column1 = gtk_tree_view_column_new_with_attributes ("", renderer, "text", 0, NULL);
  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview1), column1);
  select1 = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview1));
  gtk_tree_selection_set_mode (select1, GTK_SELECTION_SINGLE);
  
  // Set buttons insensitive.
  buttons_sensitive (false);
  
  // Do a synchronize operation.
  sync ();
}


SynchronizeDialog::~SynchronizeDialog ()
{
  gtk_widget_destroy (synchronizedialog);
}


int SynchronizeDialog::run ()
{
  return gtk_dialog_run (GTK_DIALOG (synchronizedialog));
}


void SynchronizeDialog::sync ()
{
  // Clear any previous data.
  problem_projects.clear();
  problem_books.clear();
  problem_results.clear();
  listview_clear_strings (treeview1, store1);
  buttons_sensitive (false);
  // Get all projects.
  vector<ustring> projects = projects_get_all ();
  // Messages container.
  vector <ustring> messages;
  // Any project to sync?
  if (projects.empty()) {
    messages.push_back ("There was no project to synchronize");
    listview_set_strings (treeview1, store1, messages);
    return;
  }
  // Synchronize projects, all books.
  ProgressWindow progresswindow ("Synchronizing", false);
  progresswindow.set_iterate (0, 1, projects.size());
  for (unsigned int p = 0; p < projects.size(); p++) {
    progresswindow.iterate ();
    vector <ustring> books = project_get_books (projects[p]);
    for (unsigned int b = 0; b < books.size(); b++) {
      SynchronizeBook syncbook (projects[p], books[b]);
      if (syncbook.errors || (syncbook.result == sbeOffline)) {
        problem_projects.push_back (projects[p]);
        problem_books.push_back (books[b]);
        problem_results.push_back (syncbook.result);
        ustring msg;
        for (unsigned int i = 0; i < syncbook.messages.size(); i++) {
          if (!msg.empty()) msg.append (" ");
          msg.append (syncbook.messages[i]);
        }
        messages.push_back (msg);
      }
    }
  }  
  // Everything is okay?
  if (problem_projects.empty()) {
    messages.push_back ("Everything appears fine and in sync");
  }
  listview_set_strings (treeview1, store1, messages);
}


void SynchronizeDialog::on_treeview1_row_activated (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
{
  ((SynchronizeDialog *) user_data)->on_treeview ();
}


gboolean SynchronizeDialog::on_treeview1_move_cursor (GtkTreeView *treeview, GtkMovementStep step, gint count, gpointer user_data)
{
  ((SynchronizeDialog*) user_data)->on_treeview ();
  return false;
}


void SynchronizeDialog::on_treeview1_cursor_changed (GtkTreeView *treeview, gpointer user_data)
{
  ((SynchronizeDialog *) user_data)->on_treeview ();
}


void SynchronizeDialog::on_treeview ()
{
  ustring focus = listview_get_active_string (treeview1);
  vector<ustring> strings = listview_get_strings (treeview1);
  for (unsigned int i = 0; i < strings.size(); i++) {
    if (focus == strings[i]) {
      if (i < problem_projects.size()) {
        bool sensitive = false;
        problem_project = problem_projects[i];
        problem_book = problem_books[i];
        ProjectLinksGet plg (problem_project);
        for (unsigned int i2 = 0; i2 < plg.books.size(); i2++)
          if (problem_book == plg.books[i2])
            problem_file = plg.filenames[i2];
        SynchronizeBookResult result = problem_results[i];
        switch (result) {
          case sbeOkay: {
            break;
          }
          case sbeOffline: {
            break;
          }
          case sbeClash: {
            sensitive = true;
            break;
          }
          case sbeImport: {
            break;
          }
          case sbeExport: {
            break;
          }
        }
        buttons_sensitive (sensitive);
      }
    }
  }
}


void SynchronizeDialog::on_button_differences_clicked (GtkButton *button, gpointer user_data)
{
  ((SynchronizeDialog *) user_data)->on_button_differences ();
}


void SynchronizeDialog::on_button_differences ()
{
  // Configuration
  GeneralConfiguration genconfig (0);
  // Progress system.
  ProgressWindow progresswindow ("Finding differences", true);
  progresswindow.set_text ("Preparing");
  progresswindow.set_fraction (0.3);
  // Copy project to Bibledit's project
  bibleditproject = problem_project + " " + problem_book + " bibledit";
  project_copy (problem_project, bibleditproject);
  // Import the file into the file's project.
  fileproject = problem_project + " " + problem_book + " file";
  project_create (fileproject);
  ImportBookRead ibr (problem_file, "");
  ibr.usfm ();
  CategorizeChapterVerse ccv (ibr.lines);
  project_store_book (fileproject, problem_book, ccv);
  // Copy project to project with differences.
  differencesproject = problem_project + " " + problem_book + " differencees";
  project_copy (problem_project, differencesproject);
  // Remove the books we don't want.
  {
    vector <ustring> books = project_get_books (bibleditproject);
    for (unsigned int i = 0; i < books.size(); i++) {
      if (problem_book != books[i]) {
        project_remove_book (bibleditproject, books[i]);
        project_remove_book (differencesproject, books[i]);
      }
    }
  }
  if (progresswindow.cancel) {
    finalize ();
    return;
  }
  // Do the actual comparison.
  compare_projects (bibleditproject, fileproject, differencesproject, progresswindow);
  if (progresswindow.cancel) {
    finalize ();
    return;
  }
  // Print the differences.
  progresswindow.set_text ("Printing differences");
  ustring currentproject = genconfig.project();
  genconfig.project_set (differencesproject);
  vector<ustring> references;
  compare_get_changes (differencesproject, references);
  bool resynchronize = false;
  if (references.empty()) {
    project_link_book (problem_project, problem_book, problem_file);
    gtkw_dialog_info (NULL, "There were no differences found");
    resynchronize = true;
  } else {
    view_references_pdf (references, progresswindow);
  }
  genconfig.project_set (currentproject);
  // Clear up.
  finalize ();
  // Sync again?
  if (resynchronize)
    sync ();
}


void SynchronizeDialog::on_button_import_clicked (GtkButton *button, gpointer user_data)
{
  ((SynchronizeDialog *) user_data)->on_button_import ();
}


void SynchronizeDialog::on_button_import ()
{
  // Progress system.
  ProgressWindow progresswindow ("Importing", false);
  progresswindow.set_fraction (0.5);
  // Import the file into the file's project.
  ImportBookRead ibr (problem_file, "");
  ibr.usfm ();
  CategorizeChapterVerse ccv (ibr.lines);
  project_store_book (problem_project, problem_book, ccv);
  // Set sync state okay.
  project_link_book (problem_project, problem_book, problem_file);
  // Sync again.
  sync ();
}


void SynchronizeDialog::on_button_export_clicked (GtkButton *button, gpointer user_data)
{
  ((SynchronizeDialog *) user_data)->on_button_export ();
}


void SynchronizeDialog::on_button_export ()
{
  // Progress system.
  ProgressWindow progresswindow ("Exporting", false);
  progresswindow.set_fraction (0.5);
  // Export the book to file.
  vector <ustring> lines = project_retrieve_book (problem_project, problem_book);
  write_lines (problem_file, lines);
  // Set sync state okay.
  project_link_book (problem_project, problem_book, problem_file);
  // Sync again.
  sync ();
}


void SynchronizeDialog::buttons_sensitive (bool sensitive)
{
  gtk_widget_set_sensitive (button_differences, sensitive);
  gtk_widget_set_sensitive (button_import, sensitive);
  gtk_widget_set_sensitive (button_export, sensitive);
}


void SynchronizeDialog::finalize ()
{
  // Delete temporal projects.
  project_delete (bibleditproject);
  project_delete (fileproject);  
  project_delete (differencesproject);
}

Generated by  Doxygen 1.6.0   Back to index