[gnumeric] diff: first, very rough, cut at a gui for diff



commit 4261f4911493608c1f60ab0f7662a3111da78c8b
Author: Morten Welinder <terra gnome org>
Date:   Sun Apr 8 21:41:43 2018 -0400

    diff: first, very rough, cut at a gui for diff

 po/POTFILES.in                     |    2 +
 src/GNOME_Gnumeric-gtk.xml.in      |    1 +
 src/dialogs/Makefile.am            |    2 +
 src/dialogs/dialog-sheet-compare.c |  387 ++++++++++++++++++++++++++++++++++++
 src/dialogs/dialogs.h              |    1 +
 src/dialogs/sheet-compare.ui       |  283 ++++++++++++++++++++++++++
 src/wbc-gtk-actions.c              |    6 +
 7 files changed, 682 insertions(+), 0 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index e9d7743..c3d19bf 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -182,6 +182,7 @@ src/dialogs/dialog-row-height.c
 src/dialogs/dialog-scenarios.c
 src/dialogs/dialog-search-replace.c
 src/dialogs/dialog-search.c
+src/dialogs/dialog-sheet-compare.c
 src/dialogs/dialog-sheet-order.c
 src/dialogs/dialog-sheetobject-size.c
 src/dialogs/dialog-shuffle.c
@@ -265,6 +266,7 @@ src/dialogs/dialog-zoom.c
 [type: gettext/glade]src/dialogs/search-replace.ui
 [type: gettext/glade]src/dialogs/search.ui
 [type: gettext/glade]src/dialogs/sheetobject-size.ui
+[type: gettext/glade]src/dialogs/sheet-compare.ui
 [type: gettext/glade]src/dialogs/sheet-order.ui
 [type: gettext/glade]src/dialogs/sheet-rename.ui
 [type: gettext/glade]src/dialogs/sheet-resize.ui
diff --git a/src/GNOME_Gnumeric-gtk.xml.in b/src/GNOME_Gnumeric-gtk.xml.in
index 28a7b4e..f726625 100644
--- a/src/GNOME_Gnumeric-gtk.xml.in
+++ b/src/GNOME_Gnumeric-gtk.xml.in
@@ -208,6 +208,7 @@
         <menuitem action="ToolsScenarioAdd"/>
       </menu>
       <menuitem action="ToolsSimulation"/>
+      <menuitem action="ToolsCompare"/>
       <separator/>
       <menuitem action="ToolsPlugins"/>
     </menu>
diff --git a/src/dialogs/Makefile.am b/src/dialogs/Makefile.am
index df6c68a..4a2b9de 100644
--- a/src/dialogs/Makefile.am
+++ b/src/dialogs/Makefile.am
@@ -64,6 +64,7 @@ libdialogs_la_SOURCES =                                       \
        dialog-scenarios.c                              \
        dialog-search.c                                 \
        dialog-search-replace.c                         \
+       dialog-sheet-compare.c                          \
        dialog-sheet-order.c                            \
        dialog-sheet-rename.c                           \
        dialog-sheet-resize.c                           \
@@ -160,6 +161,7 @@ embedded_uis =                                      \
        scenario-manager.ui                     \
        search-replace.ui                       \
        search.ui                               \
+       sheet-compare.ui                        \
        sheet-order.ui                          \
        sheet-rename.ui                         \
        sheet-resize.ui                         \
diff --git a/src/dialogs/dialog-sheet-compare.c b/src/dialogs/dialog-sheet-compare.c
new file mode 100644
index 0000000..a2274de
--- /dev/null
+++ b/src/dialogs/dialog-sheet-compare.c
@@ -0,0 +1,387 @@
+/*
+ * dialog-comparet-order.c: Dialog to compare two sheets.
+ *
+ * (C) Copyright 2018 Morten Welinder (terra gnome org)
+ *
+ * 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gnumeric-config.h>
+#include <glib/gi18n-lib.h>
+#include <gnumeric.h>
+#include "sheet-diff.h"
+#include "dialogs.h"
+#include "help.h"
+
+#include <gui-util.h>
+#include <wbc-gtk.h>
+#include <workbook-view.h>
+#include <workbook.h>
+#include <sheet.h>
+#include <ranges.h>
+#include <application.h>
+
+#define SHEET_COMPARE_KEY          "sheet-compare-dialog"
+
+enum {
+       ITEM_DESC,
+       NUM_COLMNS
+};
+
+
+typedef struct {
+       WBCGtk  *wbcg;
+
+       GtkBuilder *gui;
+       GtkWidget *dialog;
+       GtkWidget *notebook;
+
+       GtkWidget *cancel_btn;
+       GtkWidget *compare_btn;
+
+       GtkWidget *sheet_sel_A;
+       GtkWidget *sheet_sel_B;
+       GtkWidget *wb_sel_A;
+       GtkWidget *wb_sel_B;
+
+       GtkTreeView *results_view;
+       GtkTreeStore *results;
+
+       gboolean has_cell_section;
+       GtkTreeIter cell_section_iter;
+
+       gboolean has_style_section;
+       GtkTreeIter style_section_iter;
+} SheetCompare;
+
+
+static void
+cb_sheet_compare_destroy (SheetCompare *state)
+{
+       Workbook *wb = wb_control_get_workbook (GNM_WBC (state->wbcg));
+
+       g_object_unref (state->gui);
+       g_object_set_data (G_OBJECT (wb), SHEET_COMPARE_KEY, NULL);
+       state->gui = NULL;
+
+       g_free (state);
+}
+
+static void
+cb_cancel_clicked (G_GNUC_UNUSED GtkWidget *ignore,
+                  SheetCompare *state)
+{
+           gtk_widget_destroy (GTK_WIDGET (state->dialog));
+}
+
+static void
+reset_sheet_menu (GtkWidget *sheet_sel, Workbook *wb, int def_sheet)
+{
+       GOOptionMenu *om = GO_OPTION_MENU (sheet_sel);
+       GtkMenu *menu;
+       GtkWidget *act = NULL;
+
+       if (wb == g_object_get_data (G_OBJECT (om), "wb"))
+               return;
+       g_object_set_data (G_OBJECT (om), "wb", wb);
+
+       menu = GTK_MENU (gtk_menu_new ());
+       WORKBOOK_FOREACH_SHEET (wb, sheet, {
+               GtkWidget *item =
+                       gtk_check_menu_item_new_with_label
+                       (sheet->name_unquoted);
+               gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (item), TRUE);
+               gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), FALSE);
+               g_object_set_data (G_OBJECT (item), "sheet", sheet);
+               gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+               if (def_sheet-- == 0)
+                       act = item;
+       });
+
+       gtk_widget_show_all (GTK_WIDGET (menu));
+       go_option_menu_set_menu (om, GTK_WIDGET (menu));
+
+       if (act)
+               go_option_menu_select_item (om, GTK_MENU_ITEM (act));
+}
+
+static GtkWidget *
+create_sheet_selector (gboolean qnew)
+{
+       GtkWidget *w = go_option_menu_new ();
+       g_object_set_data (G_OBJECT (w), "qnew", GUINT_TO_POINTER (qnew));
+       return w;
+}
+
+
+static void
+cb_wb_changed (GOOptionMenu *om, SheetCompare *state)
+{
+       GtkWidget *item = go_option_menu_get_history (om);
+       Workbook *wb = g_object_get_data (G_OBJECT (item), "wb");
+       GtkWidget *sheet_sel = g_object_get_data (G_OBJECT (om), "sheet_sel");
+
+       if (wb)
+               reset_sheet_menu (sheet_sel, wb, -1);
+}
+
+static GtkWidget *
+create_wb_selector (SheetCompare *state, GtkWidget *sheet_sel,
+                   Workbook *wb0, gboolean qnew)
+{
+       GtkMenu *menu;
+       GOOptionMenu *om;
+       GList *l, *wbs;
+       GtkWidget *act = NULL;
+
+       om = GO_OPTION_MENU (go_option_menu_new ());
+        menu = GTK_MENU (gtk_menu_new ());
+
+       wbs = gnm_app_workbook_list ();
+       for (l = wbs; l; l = l->next) {
+               Workbook *wb = l->data;
+               GtkWidget *item, *child;
+               const char *uri;
+               char *markup, *shortname, *filename, *dirname, *longname, *duri;
+
+               uri = go_doc_get_uri (GO_DOC (wb));
+               filename = go_filename_from_uri (uri);
+               if (filename) {
+                       shortname = g_filename_display_basename (filename);
+               } else {
+                       shortname = g_filename_display_basename (uri);
+               }
+
+               dirname = g_path_get_dirname (filename);
+               duri = g_uri_unescape_string (dirname, NULL);
+               longname = duri
+                       ? g_filename_display_name (duri)
+                       : g_strdup (uri);
+
+               markup = g_markup_printf_escaped
+                       (_("%s\n<small>%s</small>"),
+                        shortname, longname);
+
+               item = gtk_menu_item_new_with_label ("");
+               child = gtk_bin_get_child (GTK_BIN (item));
+               gtk_label_set_markup (GTK_LABEL (child), markup);
+               gtk_label_set_ellipsize (GTK_LABEL (child), PANGO_ELLIPSIZE_MIDDLE);
+
+               g_free (markup);
+               g_free (shortname);
+               g_free (dirname);
+               g_free (longname);
+               g_free (duri);
+               g_free (filename);
+
+               gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+               g_object_set_data (G_OBJECT (item), "wb", wb);
+               if (wb == wb0)
+                       act = item;
+       }
+
+       gtk_widget_show_all (GTK_WIDGET (menu));
+       go_option_menu_set_menu (om, GTK_WIDGET (menu));
+
+       if (act)
+               go_option_menu_select_item (om, GTK_MENU_ITEM (act));
+
+       reset_sheet_menu (sheet_sel, WORKBOOK (wbs->data),
+                         qnew ? 1 : 0);
+
+       g_object_set_data (G_OBJECT (om), "sheet_sel", sheet_sel);
+
+       g_signal_connect (G_OBJECT (om), "changed",
+                          G_CALLBACK (cb_wb_changed), state);
+
+       return GTK_WIDGET (om);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void
+dsc_cell_changed (gpointer user, GnmCell const *oc, GnmCell const *nc)
+{
+       SheetCompare *state = user;
+       GtkTreeIter iter;
+       char *text;
+       const char *loc;
+
+       if (!state->has_cell_section) {
+               gtk_tree_store_insert (state->results,
+                                      &state->cell_section_iter,
+                                      NULL, -1);
+               gtk_tree_store_set (state->results,
+                                   &state->cell_section_iter,
+                                   ITEM_DESC, _("Cells"),
+                                   -1);
+               state->has_cell_section = TRUE;
+       }
+
+       loc = cell_name (oc ? oc : nc);
+       if (oc && nc)
+               text = g_strdup_printf (_("Cell %s changed"), loc);
+       else if (oc)
+               text = g_strdup_printf (_("Cell %s removed."), loc);
+       else if (nc)
+               text = g_strdup_printf (_("Cell %s added."), loc);
+       else
+               g_assert_not_reached ();
+       gtk_tree_store_insert (state->results, &iter,
+                              &state->cell_section_iter,
+                              -1);
+       gtk_tree_store_set (state->results, &iter,
+                           ITEM_DESC, text,
+                           -1);
+       g_free (text);
+}
+
+static void
+dsc_style_changed (gpointer user, GnmRange const *r,
+                  G_GNUC_UNUSED GnmStyle const *os,
+                  G_GNUC_UNUSED GnmStyle const *ns)
+{
+       SheetCompare *state = user;
+       GtkTreeIter iter;
+       char *text;
+
+       if (!state->has_style_section) {
+               gtk_tree_store_insert (state->results,
+                                      &state->style_section_iter,
+                                      NULL, -1);
+               gtk_tree_store_set (state->results,
+                                   &state->style_section_iter,
+                                   ITEM_DESC, _("Formatting"),
+                                   -1);
+               state->has_style_section = TRUE;
+       }
+
+       text = g_strdup_printf (_("Style for range %s changed"),
+                               range_as_string (r));
+       gtk_tree_store_insert (state->results, &iter,
+                              &state->style_section_iter,
+                              -1);
+       gtk_tree_store_set (state->results, &iter,
+                           ITEM_DESC, text,
+                           -1);
+       g_free (text);
+}
+
+static const GnmDiffActions dsc_actions = {
+       .cell_changed = dsc_cell_changed,
+       .style_changed = dsc_style_changed,
+};
+
+static void
+cb_compare_clicked (G_GNUC_UNUSED GtkWidget *ignore,
+                   SheetCompare *state)
+{
+       GtkTreeView *tv = state->results_view;
+       GtkTreeStore *ts = gtk_tree_store_new (NUM_COLMNS, G_TYPE_STRING);
+       GtkWidget *w;
+       Sheet *sheet_A, *sheet_B;
+
+       if (gtk_tree_view_get_n_columns (tv) == 0) {
+               GtkTreeViewColumn *tvc;
+
+               tvc = gtk_tree_view_column_new_with_attributes
+                       (_("Description"),
+                        gtk_cell_renderer_text_new (),
+                        "text", ITEM_DESC, NULL);
+               gtk_tree_view_append_column (tv, tvc);
+       }
+
+       w = go_option_menu_get_history (GO_OPTION_MENU (state->sheet_sel_A));
+       sheet_A = w ? g_object_get_data (G_OBJECT (w), "sheet") : NULL;
+       w = go_option_menu_get_history (GO_OPTION_MENU (state->sheet_sel_B));
+       sheet_B = w ? g_object_get_data (G_OBJECT (w), "sheet") : NULL;
+
+       if (sheet_A && sheet_B) {
+               state->results = ts;
+               gnm_diff_sheets (&dsc_actions, state, sheet_A, sheet_B);
+               state->results = NULL;
+       }
+
+       gtk_tree_view_set_model (tv, GTK_TREE_MODEL (ts));
+       g_object_unref (ts);
+
+       gtk_notebook_set_current_page (GTK_NOTEBOOK (state->notebook), 1);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void
+dialog_sheet_compare (WBCGtk *wbcg)
+{
+       SheetCompare *state;
+       GtkBuilder *gui;
+       Workbook *wb;
+
+       g_return_if_fail (wbcg != NULL);
+
+       wb = wb_control_get_workbook (GNM_WBC (wbcg));
+
+       gui = gnm_gtk_builder_load ("sheet-compare.ui", NULL, GO_CMD_CONTEXT (wbcg));
+        if (gui == NULL)
+                return;
+
+       /* Only pop up one copy per workbook */
+       if (gnm_dialog_raise_if_exists (wbcg, SHEET_COMPARE_KEY))
+               return;
+
+
+       g_object_set_data (G_OBJECT (wb), SHEET_COMPARE_KEY, (gpointer) gui);
+       state = g_new0 (SheetCompare, 1);
+       state->gui = gui;
+       state->wbcg = wbcg;
+       state->dialog = go_gtk_builder_get_widget (gui, "sheet-compare-dialog");
+       state->notebook = go_gtk_builder_get_widget (gui, "notebook");
+       state->cancel_btn = go_gtk_builder_get_widget (gui, "cancel_button");
+       state->compare_btn = go_gtk_builder_get_widget (gui, "compare_button");
+       state->results_view = GTK_TREE_VIEW (go_gtk_builder_get_widget (gui, "results_treeview"));
+
+       state->sheet_sel_A = create_sheet_selector (FALSE);
+       state->wb_sel_A = create_wb_selector (state, state->sheet_sel_A,
+                                             wb, FALSE);
+       go_gtk_widget_replace (go_gtk_builder_get_widget (gui, "sheet_selector_A"),
+                              state->sheet_sel_A);
+       go_gtk_widget_replace (go_gtk_builder_get_widget (gui, "wb_selector_A"),
+                              state->wb_sel_A);
+
+       state->sheet_sel_B = create_sheet_selector (TRUE);
+       state->wb_sel_B = create_wb_selector (state, state->sheet_sel_B,
+                                             wb, TRUE);
+       go_gtk_widget_replace (go_gtk_builder_get_widget (gui, "sheet_selector_B"),
+                              state->sheet_sel_B);
+       go_gtk_widget_replace (go_gtk_builder_get_widget (gui, "wb_selector_B"),
+                              state->wb_sel_B);
+
+#define CONNECT(o,s,c) g_signal_connect(G_OBJECT(o),s,G_CALLBACK(c),state)
+       CONNECT (state->cancel_btn, "clicked", cb_cancel_clicked);
+       CONNECT (state->compare_btn, "clicked", cb_compare_clicked);
+#undef CONNECT
+
+       /* a candidate for merging into attach guru */
+       wbc_gtk_attach_guru (state->wbcg, GTK_WIDGET (state->dialog));
+       g_object_set_data_full (G_OBJECT (state->dialog),
+                               "state", state,
+                               (GDestroyNotify) cb_sheet_compare_destroy);
+
+       gnm_restore_window_geometry (GTK_WINDOW (state->dialog),
+                                    SHEET_COMPARE_KEY);
+
+       go_gtk_nonmodal_dialog (wbcg_toplevel (state->wbcg),
+                               GTK_WINDOW (state->dialog));
+       gtk_widget_show_all (GTK_WIDGET (state->dialog));
+}
diff --git a/src/dialogs/dialogs.h b/src/dialogs/dialogs.h
index 6a045f9..b7c478c 100644
--- a/src/dialogs/dialogs.h
+++ b/src/dialogs/dialogs.h
@@ -57,6 +57,7 @@ void   dialog_autosave        (WBCGtk *wbcg);
 gboolean dialog_autosave_prompt        (WBCGtk *wbcg);
 void     dialog_autoformat     (WBCGtk *wbcg);
 void     dialog_consolidate    (WBCGtk *wbcg);
+void     dialog_sheet_compare   (WBCGtk *wbcg);
 void     dialog_sheet_order    (WBCGtk *wbcg);
 void     dialog_sheet_resize    (WBCGtk *wbcg);
 void     dialog_sheet_rename    (WBCGtk *wbcg, Sheet *sheet);
diff --git a/src/dialogs/sheet-compare.ui b/src/dialogs/sheet-compare.ui
new file mode 100644
index 0000000..fff66ad
--- /dev/null
+++ b/src/dialogs/sheet-compare.ui
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
+<interface>
+  <requires lib="gtk+" version="3.8"/>
+  <object class="GtkAdjustment" id="results_hadjustment">
+    <property name="upper">100</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="results_vadjustment">
+    <property name="upper">100</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkDialog" id="sheet-compare-dialog">
+    <property name="can_focus">False</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="vbox1">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="button_box1">
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="compare_button">
+                <property name="label" translatable="yes">Compare</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="cancel_button">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkNotebook" id="notebook">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <child>
+              <object class="GtkGrid" id="grid1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="row_spacing">6</property>
+                <property name="column_spacing">12</property>
+                <child>
+                  <object class="GtkSeparator" id="separator1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">2</property>
+                    <property name="top_attach">0</property>
+                    <property name="height">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Workbook</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Workbook</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">3</property>
+                    <property name="top_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label3">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Sheet</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label4">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Sheet</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">3</property>
+                    <property name="top_attach">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="wb_selector_A">
+                    <property name="label" translatable="yes">button</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="wb_selector_B">
+                    <property name="label" translatable="yes">button</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">4</property>
+                    <property name="top_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="sheet_selector_A">
+                    <property name="label" translatable="yes">button</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="sheet_selector_B">
+                    <property name="label" translatable="yes">button</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">4</property>
+                    <property name="top_attach">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label5">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">First Sheet</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">0</property>
+                    <property name="width">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label6">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Second Sheet</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">3</property>
+                    <property name="top_attach">0</property>
+                    <property name="width">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkSeparator" id="separator2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">1</property>
+                    <property name="width">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkSeparator" id="separator3">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">3</property>
+                    <property name="top_attach">1</property>
+                    <property name="width">2</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="options_tab">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Options</property>
+              </object>
+              <packing>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkScrolledWindow" id="scrolled_window1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hadjustment">results_hadjustment</property>
+                <property name="vadjustment">results_vadjustment</property>
+                <property name="vscrollbar_policy">always</property>
+                <property name="shadow_type">in</property>
+                <child>
+                  <object class="GtkTreeView" id="results_treeview">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="hadjustment">results_hadjustment</property>
+                    <property name="vadjustment">results_vadjustment</property>
+                    <child internal-child="selection">
+                      <object class="GtkTreeSelection" id="tree_selection1"/>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="results_tab">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Results</property>
+              </object>
+              <packing>
+                <property name="position">1</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child type="tab">
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/src/wbc-gtk-actions.c b/src/wbc-gtk-actions.c
index 8f6525d..65bab45 100644
--- a/src/wbc-gtk-actions.c
+++ b/src/wbc-gtk-actions.c
@@ -914,6 +914,7 @@ static GNM_ACTION_DEF (cb_tools_solver)         { dialog_solver (wbcg, wbcg_cur_
 static GNM_ACTION_DEF (cb_tools_scenario_add)  { dialog_scenario_add (wbcg); }
 static GNM_ACTION_DEF (cb_tools_scenarios)     { dialog_scenarios (wbcg); }
 static GNM_ACTION_DEF (cb_tools_simulation)    { dialog_simulation (wbcg, wbcg_cur_sheet (wbcg)); }
+static GNM_ACTION_DEF (cb_tools_compare)       { dialog_sheet_compare (wbcg); }
 static GNM_ACTION_DEF (cb_tools_anova_one_factor) { dialog_anova_single_factor_tool (wbcg, wbcg_cur_sheet 
(wbcg)); }
 static GNM_ACTION_DEF (cb_tools_anova_two_factor) { dialog_anova_two_factor_tool (wbcg, wbcg_cur_sheet 
(wbcg)); }
 static GNM_ACTION_DEF (cb_tools_chi_square_independence) { dialog_chi_square_tool (wbcg, wbcg_cur_sheet 
(wbcg), TRUE); }
@@ -2912,6 +2913,11 @@ static GnmActionEntry const actions[] = {
                   "simulation to find out probable outputs and risks related to them"),
          .callback = G_CALLBACK (cb_tools_simulation)
        },
+       { .name = "ToolsCompare",
+         .label = N_("Compare Sheets..."),
+         .tooltip = N_("Find differences between two sheets"),
+         .callback = G_CALLBACK (cb_tools_compare)
+       },
 
 /* Tools -> Scenarios */
        { .name = "ToolsScenarios",


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]