ssdiff: move comparison engine into its own file.
[gnumeric.git] / src / dialogs / dialog-sheet-order.c
blob242bef9393562ef6560c82310142cf29b97b14fa
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * dialog-sheet-order.c: Dialog to change the order of sheets in the Gnumeric
4 * spreadsheet
6 * Author:
7 * Jody Goldberg <jody@gnome.org>
8 * Andreas J. Guelzow <aguelzow@taliesin.ca>
10 * (C) Copyright 2000, 2001, 2002 Jody Goldberg <jody@gnome.org>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses/>.
26 #include <gnumeric-config.h>
27 #include <glib/gi18n-lib.h>
28 #include <gnumeric.h>
29 #include "dialogs.h"
30 #include "help.h"
32 #include <gui-util.h>
33 #include <wbc-gtk.h>
34 #include <workbook-view.h>
35 #include <workbook.h>
37 /* We shouldn't need workbook-priv.h but we need to know whether undo commands are pending */
38 #include <workbook-priv.h>
40 #include <sheet.h>
41 #include <style-color.h>
42 #include <commands.h>
43 #include <application.h>
44 #include <widgets/gnumeric-cell-renderer-text.h>
45 #include <widgets/gnumeric-cell-renderer-toggle.h>
46 #include <goffice/goffice.h>
48 #include <gtk/gtk.h>
49 #include <string.h>
52 #define SHEET_ORDER_KEY "sheet-order-dialog"
54 typedef struct {
55 WBCGtk *wbcg;
57 GtkBuilder *gui;
58 GtkWidget *dialog;
59 GtkTreeView *sheet_list;
60 GtkListStore *model;
61 GtkWidget *up_btn;
62 GtkWidget *down_btn;
63 GtkWidget *add_btn;
64 GtkWidget *append_btn;
65 GtkWidget *duplicate_btn;
66 GtkWidget *delete_btn;
67 GtkWidget *apply_names_btn;
68 GtkWidget *sort_asc_btn;
69 GtkWidget *sort_desc_btn;
70 GtkWidget *undo_btn;
71 GtkWidget *cancel_btn;
72 GtkWidget *advanced_check;
73 GtkWidget *ccombo_back;
74 GtkWidget *ccombo_fore;
75 GtkWidget *warning;
77 GdkPixbuf *image_padlock;
78 GdkPixbuf *image_padlock_no;
80 GdkPixbuf *image_ltr;
81 GdkPixbuf *image_rtl;
83 GdkPixbuf *image_visible;
85 gboolean initial_colors_set;
87 GtkTreeViewColumn *dir_column;
88 GtkTreeViewColumn *row_max_column;
89 GtkTreeViewColumn *col_max_column;
91 gulong sheet_order_changed_listener;
92 gulong sheet_added_listener;
93 gulong sheet_deleted_listener;
95 gulong model_selection_changed_listener;
96 gulong model_row_insertion_listener;
97 } SheetManager;
99 enum {
100 SHEET_LOCKED,
101 SHEET_LOCK_IMAGE,
102 SHEET_VISIBLE,
103 SHEET_VISIBLE_IMAGE,
104 SHEET_ROW_MAX,
105 SHEET_COL_MAX,
106 SHEET_NAME,
107 SHEET_NEW_NAME,
108 SHEET_POINTER,
109 BACKGROUND_COLOUR,
110 FOREGROUND_COLOUR,
111 SHEET_DIRECTION,
112 SHEET_DIRECTION_IMAGE,
113 NUM_COLUMNS
116 static char *verify_validity (SheetManager *state, gboolean *pchanged);
117 static void dialog_sheet_order_update_sheet_order (SheetManager *state);
120 static void
121 update_undo (SheetManager *state, WorkbookControl *wbc)
124 gtk_widget_set_sensitive (state->undo_btn, TRUE);
127 static void
128 workbook_signals_block (SheetManager *state)
130 WorkbookControl *wbc = GNM_WBC (state->wbcg);
131 Workbook *wb = wb_control_get_workbook (wbc);
133 g_signal_handler_block (G_OBJECT (wb),
134 state->sheet_order_changed_listener);
135 g_signal_handler_block (G_OBJECT (wb),
136 state->sheet_added_listener);
137 g_signal_handler_block (G_OBJECT (wb),
138 state->sheet_deleted_listener);
141 static void
142 workbook_signals_unblock (SheetManager *state)
144 WorkbookControl *wbc = GNM_WBC (state->wbcg);
145 Workbook *wb = wb_control_get_workbook (wbc);
147 g_signal_handler_unblock (G_OBJECT (wb),
148 state->sheet_order_changed_listener);
149 g_signal_handler_unblock (G_OBJECT (wb),
150 state->sheet_added_listener);
151 g_signal_handler_unblock (G_OBJECT (wb),
152 state->sheet_deleted_listener);
155 static void
156 cb_name_edited (GtkCellRendererText *cell,
157 gchar *path_string,
158 gchar *new_text,
159 SheetManager *state)
161 GtkTreeIter iter;
162 GtkTreePath *path;
163 gboolean changed = FALSE;
164 char *error;
166 if (cell != NULL) {
167 path = gtk_tree_path_new_from_string (path_string);
168 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (state->model),
169 &iter, path))
170 gtk_list_store_set (state->model, &iter,
171 SHEET_NEW_NAME, new_text, -1);
172 else
173 g_warning ("Did not get a valid iterator");
174 gtk_tree_path_free (path);
177 error = verify_validity (state, &changed);
179 if (error != NULL) {
180 gtk_widget_set_sensitive (state->apply_names_btn, FALSE);
181 gtk_label_set_text (GTK_LABEL (state->warning), error);
182 } else {
183 gtk_widget_set_sensitive (state->apply_names_btn, changed);
184 gtk_label_set_markup (GTK_LABEL (state->warning),
185 changed ? _("<b>Note:</b> A sheet name change is pending.") : "");
190 typedef struct {
191 char *key;
192 int i;
193 } gtmff_sort_t;
195 static gint
196 gtmff_compare_func (gconstpointer a, gconstpointer b)
198 gtmff_sort_t const *pa = a, *pb = b;
200 return strcmp (pa->key, pb->key);
204 static gboolean
205 gtmff_asc (GtkTreeModel *model, GtkTreePath *path,
206 GtkTreeIter *iter, gpointer data)
208 GSList **l = data;
209 Sheet *this_sheet;
210 char *name;
211 gtmff_sort_t *ptr;
214 ptr = g_new (gtmff_sort_t, 1);
215 gtk_tree_model_get (model, iter,
216 SHEET_POINTER, &this_sheet,
217 SHEET_NAME, &name,
218 -1);
219 ptr->i = this_sheet->index_in_wb;
220 ptr->key = g_utf8_collate_key_for_filename (name, -1);
222 *l = g_slist_insert_sorted (*l, ptr, (GCompareFunc) gtmff_compare_func);
224 return FALSE;
227 static void
228 sort_asc_desc (SheetManager *state, gboolean asc)
230 WorkbookSheetState *old_state;
231 WorkbookControl *wbc = GNM_WBC (state->wbcg);
232 Workbook *wb = wb_control_get_workbook (wbc);
233 GSList *l = NULL, *l_tmp;
234 gint n = 0;
236 gtk_tree_model_foreach (GTK_TREE_MODEL (state->model), gtmff_asc, &l);
238 if (!asc)
239 l = g_slist_reverse (l);
241 workbook_signals_block (state);
243 old_state = workbook_sheet_state_new (wb);
245 for (l_tmp = l; l_tmp != NULL; l_tmp = l_tmp->next) {
246 gtmff_sort_t *ptr = l_tmp->data;
247 GtkTreeIter iter;
248 Sheet *sheet;
250 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (state->model),
251 &iter, NULL, ptr->i);
252 g_free (ptr->key);
253 g_free (ptr);
254 l_tmp->data = NULL;
256 gtk_tree_model_get (GTK_TREE_MODEL (state->model), &iter,
257 SHEET_POINTER, &sheet,
258 -1);
259 workbook_sheet_move (sheet, n - sheet->index_in_wb);
260 n++;
262 g_slist_free (l);
264 /* Now we change the list store */
265 dialog_sheet_order_update_sheet_order (state);
267 cmd_reorganize_sheets (wbc, old_state, NULL);
268 update_undo (state, wbc);
270 workbook_signals_unblock (state);
273 static void
274 cb_asc (G_GNUC_UNUSED GtkWidget *w, SheetManager *state)
276 sort_asc_desc (state, TRUE);
279 static void
280 cb_desc (G_GNUC_UNUSED GtkWidget *w, SheetManager *state)
282 sort_asc_desc (state, FALSE);
285 static gboolean
286 color_equal (const GdkRGBA *color_a, const GnmColor *color_gb)
288 if (color_gb == NULL)
289 return color_a == NULL;
290 /* FIXME: What about ->is_auto? */
291 return color_a && GO_COLOR_FROM_GDK_RGBA (*color_a) == color_gb->go_color;
294 static void
295 cb_color_changed_fore (G_GNUC_UNUSED GOComboColor *go_combo_color,
296 GOColor color, G_GNUC_UNUSED gboolean custom,
297 G_GNUC_UNUSED gboolean by_user,
298 G_GNUC_UNUSED gboolean is_default,
299 SheetManager *state)
301 GList *selected_rows, *l;
302 GtkTreeSelection *selection = gtk_tree_view_get_selection (state->sheet_list);
303 WorkbookSheetState *old_state;
304 WorkbookControl *wbc = GNM_WBC (state->wbcg);
305 Workbook *wb = wb_control_get_workbook (wbc);
306 GdkRGBA gdk_color;
307 GdkRGBA *p_gdk_color;
308 GnmColor *gnm_color;
310 g_return_if_fail (selection != NULL);
312 selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
314 p_gdk_color = (color == 0) ? NULL : go_color_to_gdk_rgba (color, &gdk_color);
315 gnm_color = (color == 0) ? NULL : gnm_color_new_gdk (&gdk_color);
317 old_state = workbook_sheet_state_new (wb);
319 for (l = selected_rows; l != NULL; l = l->next) {
320 Sheet *this_sheet;
321 GtkTreeIter sel_iter;
322 GtkTreePath *path = l->data;
324 gtk_tree_model_get_iter (GTK_TREE_MODEL (state->model), &sel_iter, path);
325 gtk_tree_model_get (GTK_TREE_MODEL (state->model), &sel_iter,
326 SHEET_POINTER, &this_sheet,
327 -1);
328 if (color_equal (p_gdk_color, this_sheet->tab_text_color))
329 continue;
331 gtk_list_store_set (state->model, &sel_iter,
332 FOREGROUND_COLOUR, p_gdk_color,
333 -1);
334 g_object_set (this_sheet,
335 "tab-foreground", gnm_color,
336 NULL);
339 style_color_unref (gnm_color);
340 cmd_reorganize_sheets (wbc, old_state, NULL);
341 update_undo (state, wbc);
343 g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
346 static void
347 cb_color_changed_back (G_GNUC_UNUSED GOComboColor *go_combo_color,
348 GOColor color, G_GNUC_UNUSED gboolean custom,
349 G_GNUC_UNUSED gboolean by_user,
350 G_GNUC_UNUSED gboolean is_default,
351 SheetManager *state)
353 GList *selected_rows, *l;
354 GtkTreeSelection *selection = gtk_tree_view_get_selection (state->sheet_list);
355 WorkbookSheetState *old_state;
356 WorkbookControl *wbc = GNM_WBC (state->wbcg);
357 Workbook *wb = wb_control_get_workbook (wbc);
358 GdkRGBA gdk_color;
359 GdkRGBA *p_gdk_color;
360 GnmColor *gnm_color;
362 g_return_if_fail (selection != NULL);
364 selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
366 p_gdk_color = (color == 0) ? NULL : go_color_to_gdk_rgba (color, &gdk_color);
367 gnm_color = (color == 0) ? NULL : gnm_color_new_gdk (&gdk_color);
369 old_state = workbook_sheet_state_new (wb);
371 for (l = selected_rows; l != NULL; l = l->next) {
372 Sheet *this_sheet;
373 GtkTreeIter sel_iter;
374 GtkTreePath *path = l->data;
376 gtk_tree_model_get_iter (GTK_TREE_MODEL (state->model), &sel_iter, path);
377 gtk_tree_model_get (GTK_TREE_MODEL (state->model), &sel_iter,
378 SHEET_POINTER, &this_sheet,
379 -1);
380 if (color_equal (p_gdk_color, this_sheet->tab_color))
381 continue;
383 gtk_list_store_set (state->model, &sel_iter,
384 BACKGROUND_COLOUR, p_gdk_color,
385 -1);
386 g_object_set (this_sheet,
387 "tab-background", gnm_color,
388 NULL);
391 style_color_unref (gnm_color);
392 cmd_reorganize_sheets (wbc, old_state, NULL);
393 update_undo (state, wbc);
395 g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
398 static gboolean
399 cb_sheet_order_cnt_visible (GtkTreeModel *model,
400 GtkTreePath *path,
401 GtkTreeIter *iter,
402 gpointer data)
404 gint *i = data;
405 gboolean is_visible;
407 gtk_tree_model_get (model, iter,
408 SHEET_VISIBLE, &is_visible,
409 -1);
410 if (is_visible)
411 (*i)++;
413 return FALSE;
416 static gint
417 sheet_order_cnt_visible (SheetManager *state)
419 gint data = 0;
420 gtk_tree_model_foreach (GTK_TREE_MODEL (state->model),
421 cb_sheet_order_cnt_visible,
422 &data);
423 return data;
427 * Refreshes the buttons on a row (un)selection and selects the chosen sheet
428 * for this view.
430 static void
431 cb_selection_changed (G_GNUC_UNUSED GtkTreeSelection *ignored,
432 SheetManager *state)
434 GtkTreeIter iter;
435 Sheet *sheet;
436 gboolean has_iter;
437 GdkRGBA *fore, *back;
438 GtkTreeSelection *selection = gtk_tree_view_get_selection (state->sheet_list);
439 GList *selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
440 gboolean multiple = gtk_tree_model_iter_n_children(GTK_TREE_MODEL (state->model), NULL) > 1;
441 int cnt_sel = g_list_length (selected_rows);
442 gboolean single_sel = (cnt_sel < 2);
444 gtk_widget_set_sensitive (state->sort_asc_btn, multiple);
445 gtk_widget_set_sensitive (state->sort_desc_btn, multiple);
447 if (selected_rows == NULL) {
448 gtk_widget_set_sensitive (state->up_btn, FALSE);
449 gtk_widget_set_sensitive (state->down_btn, FALSE);
450 gtk_widget_set_sensitive (state->delete_btn, FALSE);
451 gtk_widget_set_sensitive (state->ccombo_back, FALSE);
452 gtk_widget_set_sensitive (state->ccombo_fore, FALSE);
453 gtk_widget_set_sensitive (state->add_btn, FALSE);
454 gtk_widget_set_sensitive (state->duplicate_btn, FALSE);
455 return;
458 gtk_tree_model_get_iter (GTK_TREE_MODEL (state->model),
459 &iter, (GtkTreePath *) selected_rows->data);
461 gtk_tree_model_get (GTK_TREE_MODEL (state->model), &iter,
462 SHEET_POINTER, &sheet,
463 BACKGROUND_COLOUR, &back,
464 FOREGROUND_COLOUR, &fore,
465 -1);
466 if (!state->initial_colors_set) {
467 go_combo_color_set_color_gdk (GO_COMBO_COLOR (state->ccombo_back), back);
468 go_combo_color_set_color_gdk (GO_COMBO_COLOR (state->ccombo_fore), fore);
469 state->initial_colors_set = TRUE;
471 if (back != NULL)
472 gdk_rgba_free (back);
473 if (fore != NULL)
474 gdk_rgba_free (fore);
476 gtk_widget_set_sensitive (state->ccombo_back, TRUE);
477 gtk_widget_set_sensitive (state->ccombo_fore, TRUE);
478 gtk_widget_set_sensitive (state->delete_btn, sheet_order_cnt_visible (state) > cnt_sel);
479 gtk_widget_set_sensitive (state->add_btn, single_sel);
480 gtk_widget_set_sensitive (state->duplicate_btn, single_sel);
482 has_iter = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (state->model), &iter);
483 g_return_if_fail (has_iter);
484 gtk_widget_set_sensitive (state->up_btn,
485 single_sel &&
486 !gtk_tree_selection_iter_is_selected (selection, &iter));
487 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (state->model), &iter, NULL,
488 gtk_tree_model_iter_n_children
489 (GTK_TREE_MODEL (state->model), NULL) - 1);
490 gtk_widget_set_sensitive (state->down_btn,
491 single_sel &&
492 !gtk_tree_selection_iter_is_selected (selection, &iter));
494 if (sheet != NULL)
495 wb_view_sheet_focus (
496 wb_control_view (GNM_WBC (state->wbcg)), sheet);
498 g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
501 static void
502 cb_toggled_lock (G_GNUC_UNUSED GtkCellRendererToggle *cell,
503 gchar *path_string,
504 gpointer data)
506 SheetManager *state = data;
507 GtkTreeModel *model = GTK_TREE_MODEL (state->model);
508 GtkTreeIter iter;
509 GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
510 gboolean is_locked = TRUE;
511 Sheet *this_sheet = NULL;
512 WorkbookSheetState *old_state = NULL;
513 WorkbookControl *wbc = GNM_WBC (state->wbcg);
514 Workbook *wb = wb_control_get_workbook (wbc);
516 if (gtk_tree_model_get_iter (model, &iter, path)) {
517 gtk_tree_model_get (model, &iter,
518 SHEET_LOCKED, &is_locked,
519 SHEET_POINTER, &this_sheet,
520 -1);
522 if (is_locked) {
523 gtk_list_store_set
524 (GTK_LIST_STORE (model), &iter, SHEET_LOCKED,
525 FALSE, SHEET_LOCK_IMAGE,
526 state->image_padlock_no, -1);
527 } else {
528 gtk_list_store_set
529 (GTK_LIST_STORE (model), &iter, SHEET_LOCKED,
530 TRUE, SHEET_LOCK_IMAGE,
531 state->image_padlock, -1);
533 } else {
534 g_warning ("Did not get a valid iterator");
535 gtk_tree_path_free (path);
536 return;
538 gtk_tree_path_free (path);
540 old_state = workbook_sheet_state_new (wb);
541 g_object_set (this_sheet,
542 "protected", !is_locked,
543 NULL);
544 cmd_reorganize_sheets (wbc, old_state, this_sheet);
545 update_undo (state, wbc);
548 static void
549 cb_toggled_direction (G_GNUC_UNUSED GtkCellRendererToggle *cell,
550 gchar *path_string,
551 SheetManager *state)
553 GtkTreeModel *model = GTK_TREE_MODEL (state->model);
554 GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
555 GtkTreeIter iter;
556 gboolean is_rtl = TRUE;
557 Sheet *this_sheet = NULL;
558 WorkbookSheetState *old_state = NULL;
559 WorkbookControl *wbc = GNM_WBC (state->wbcg);
560 Workbook *wb = wb_control_get_workbook (wbc);
562 if (gtk_tree_model_get_iter (model, &iter, path)) {
563 gtk_tree_model_get (model, &iter,
564 SHEET_DIRECTION, &is_rtl,
565 SHEET_POINTER, &this_sheet,
566 -1);
567 gtk_list_store_set
568 (GTK_LIST_STORE (model), &iter,
569 SHEET_DIRECTION, !is_rtl,
570 SHEET_DIRECTION_IMAGE,
571 is_rtl ? state->image_ltr : state->image_rtl,
572 -1);
573 } else {
574 g_warning ("Did not get a valid iterator");
575 gtk_tree_path_free (path);
576 return;
579 gtk_tree_path_free (path);
581 old_state = workbook_sheet_state_new (wb);
582 g_object_set (this_sheet,
583 "text-is-rtl", !is_rtl,
584 NULL);
585 cmd_reorganize_sheets (wbc, old_state, this_sheet);
586 update_undo (state, wbc);
589 static void populate_sheet_list (SheetManager *state);
591 static void
592 cb_toggled_visible (G_GNUC_UNUSED GtkCellRendererToggle *cell,
593 gchar *path_string,
594 gpointer data)
596 SheetManager *state = data;
597 GtkTreeModel *model = GTK_TREE_MODEL (state->model);
598 GtkTreeIter iter;
599 GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
600 gboolean is_visible;
601 Sheet *this_sheet;
602 WorkbookSheetState *old_state;
603 WorkbookControl *wbc = GNM_WBC (state->wbcg);
604 Workbook *wb = wb_control_get_workbook (wbc);
605 int cnt;
607 if (!gtk_tree_model_get_iter (model, &iter, path)) {
608 g_warning ("Did not get a valid iterator");
609 gtk_tree_path_free (path);
610 return;
613 gtk_tree_model_get (model, &iter,
614 SHEET_VISIBLE, &is_visible,
615 SHEET_POINTER, &this_sheet,
616 -1);
618 if (is_visible) {
619 cnt = sheet_order_cnt_visible (state);
620 if (cnt <= 1) {
621 go_gtk_notice_dialog (GTK_WINDOW (state->dialog), GTK_MESSAGE_ERROR,
622 _("At least one sheet must remain visible!"));
623 gtk_tree_path_free (path);
624 return;
626 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
627 SHEET_VISIBLE, FALSE,
628 SHEET_VISIBLE_IMAGE, NULL,
629 -1);
631 } else {
632 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
633 SHEET_VISIBLE, TRUE,
634 SHEET_VISIBLE_IMAGE,
635 state->image_visible,
636 -1);
638 gtk_tree_path_free (path);
640 old_state = workbook_sheet_state_new (wb);
641 g_object_set (this_sheet,
642 "visibility",
643 !is_visible ? GNM_SHEET_VISIBILITY_VISIBLE
644 : GNM_SHEET_VISIBILITY_HIDDEN,
645 NULL);
647 cmd_reorganize_sheets (wbc, old_state, this_sheet);
648 update_undo (state, wbc);
650 if (is_visible)
651 populate_sheet_list (state);
654 static gboolean
655 sheet_selection_can_toggle(GtkTreeSelection *selection,
656 GtkTreeModel *model,
657 GtkTreePath *path,
658 gboolean path_currently_selected,
659 G_GNUC_UNUSED gpointer data)
661 GtkTreeIter iter;
662 gboolean is_visible;
664 if (path_currently_selected ||
665 !gtk_tree_model_get_iter (model, &iter, path))
666 return TRUE;
668 gtk_tree_model_get (model, &iter,
669 SHEET_VISIBLE, &is_visible,
670 -1);
672 return is_visible;
675 static void
676 create_sheet_list (SheetManager *state)
678 GtkTreeViewColumn *column;
679 GtkTreeSelection *selection;
680 GtkWidget *scrolled = go_gtk_builder_get_widget (state->gui, "scrolled");
681 GtkCellRenderer *renderer;
683 state->model = gtk_list_store_new (NUM_COLUMNS,
684 G_TYPE_BOOLEAN,
685 GDK_TYPE_PIXBUF,
686 G_TYPE_BOOLEAN,
687 GDK_TYPE_PIXBUF,
688 G_TYPE_INT,
689 G_TYPE_INT,
690 G_TYPE_STRING,
691 G_TYPE_STRING,
692 G_TYPE_POINTER,
693 GDK_TYPE_RGBA,
694 GDK_TYPE_RGBA,
695 G_TYPE_BOOLEAN,
696 GDK_TYPE_PIXBUF);
697 state->sheet_list = GTK_TREE_VIEW (gtk_tree_view_new_with_model
698 (GTK_TREE_MODEL (state->model)));
699 selection = gtk_tree_view_get_selection (state->sheet_list);
700 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
702 renderer = gnumeric_cell_renderer_toggle_new ();
703 g_signal_connect (G_OBJECT (renderer),
704 "toggled",
705 G_CALLBACK (cb_toggled_lock), state);
706 column = gtk_tree_view_column_new_with_attributes
707 /* xgettext : "Lock" is short for locked. Keep this short. */
708 (_("Lock"),
709 renderer,
710 "active", SHEET_LOCKED,
711 "pixbuf", SHEET_LOCK_IMAGE,
712 NULL);
713 gtk_tree_view_append_column (state->sheet_list, column);
715 renderer = gnumeric_cell_renderer_toggle_new ();
716 g_signal_connect (G_OBJECT (renderer),
717 "toggled",
718 G_CALLBACK (cb_toggled_visible), state);
719 column = gtk_tree_view_column_new_with_attributes
720 /* xgettext : "Viz" is short for visibility. Keep this short. */
721 (_("Viz"),
722 renderer,
723 "active", SHEET_VISIBLE,
724 "pixbuf", SHEET_VISIBLE_IMAGE,
725 NULL);
726 gtk_tree_view_append_column (state->sheet_list, column);
728 renderer = gnumeric_cell_renderer_toggle_new ();
729 g_signal_connect (G_OBJECT (renderer), "toggled",
730 G_CALLBACK (cb_toggled_direction), state);
731 column = gtk_tree_view_column_new_with_attributes
732 /* xgettext : "Dir" is short for direction. Keep this short. */
733 (_("Dir"),
734 renderer,
735 "active", SHEET_DIRECTION,
736 "pixbuf", SHEET_DIRECTION_IMAGE,
737 NULL);
738 gtk_tree_view_column_set_visible (column, FALSE);
739 gtk_tree_view_append_column (state->sheet_list, column);
740 state->dir_column = column;
742 column = gtk_tree_view_column_new_with_attributes
743 /*Translators: Table header for column with number of "Rows"*/
744 (C_("sheetlist", "Rows"),
745 gnumeric_cell_renderer_text_new (),
746 "text", SHEET_ROW_MAX,
747 NULL);
748 gtk_tree_view_column_set_visible (column, FALSE);
749 gtk_tree_view_append_column (state->sheet_list, column);
750 state->row_max_column = column;
752 column = gtk_tree_view_column_new_with_attributes
753 /*Translators: Table header for column with number of "Cols"*/
754 (C_("sheetlist", "Cols"),
755 gnumeric_cell_renderer_text_new (),
756 "text", SHEET_COL_MAX,
757 NULL);
758 gtk_tree_view_column_set_visible (column, FALSE);
759 gtk_tree_view_append_column (state->sheet_list, column);
760 state->col_max_column = column;
762 column = gtk_tree_view_column_new_with_attributes (_("Current Name"),
763 gnumeric_cell_renderer_text_new (),
764 "text", SHEET_NAME,
765 "background-rgba",BACKGROUND_COLOUR,
766 "foreground-rgba",FOREGROUND_COLOUR,
767 NULL);
768 gtk_tree_view_append_column (state->sheet_list, column);
770 renderer = gnumeric_cell_renderer_text_new ();
771 g_object_set (G_OBJECT (renderer),
772 "editable", TRUE,
773 "editable-set", TRUE,
774 NULL);
775 column = gtk_tree_view_column_new_with_attributes (_("New Name"),
776 renderer,
777 "text", SHEET_NEW_NAME,
778 "background-rgba",BACKGROUND_COLOUR,
779 "foreground-rgba",FOREGROUND_COLOUR,
780 NULL);
781 gtk_tree_view_append_column (state->sheet_list, column);
782 g_signal_connect (G_OBJECT (renderer), "edited",
783 G_CALLBACK (cb_name_edited), state);
785 gtk_tree_view_set_reorderable (state->sheet_list, TRUE);
787 /* Init the buttons & selection */
788 state->model_selection_changed_listener =
789 g_signal_connect (selection,
790 "changed",
791 G_CALLBACK (cb_selection_changed), state);
792 gtk_tree_selection_set_select_function (selection,
793 sheet_selection_can_toggle,
794 NULL, NULL);
796 gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (state->sheet_list));
799 static void
800 set_sheet_info_at_iter (SheetManager *state, GtkTreeIter *iter, Sheet *sheet)
802 GdkRGBA cback, *color = NULL;
803 GdkRGBA cfore, *text_color = NULL;
805 if (sheet->tab_color)
806 color = go_color_to_gdk_rgba (sheet->tab_color->go_color, &cback);
807 if (sheet->tab_text_color)
808 text_color = go_color_to_gdk_rgba (sheet->tab_text_color->go_color, &cfore);
810 gtk_list_store_set (state->model, iter,
811 SHEET_LOCKED, sheet->is_protected,
812 SHEET_LOCK_IMAGE, (sheet->is_protected
813 ? state->image_padlock
814 : state->image_padlock_no),
815 SHEET_VISIBLE, (sheet->visibility == GNM_SHEET_VISIBILITY_VISIBLE),
816 SHEET_VISIBLE_IMAGE, (sheet->visibility == GNM_SHEET_VISIBILITY_VISIBLE
817 ? state->image_visible
818 : NULL),
819 SHEET_ROW_MAX, gnm_sheet_get_max_rows (sheet),
820 SHEET_COL_MAX, gnm_sheet_get_max_cols (sheet),
821 SHEET_NAME, sheet->name_unquoted,
822 SHEET_NEW_NAME, "",
823 SHEET_POINTER, sheet,
824 BACKGROUND_COLOUR, color,
825 FOREGROUND_COLOUR, text_color,
826 SHEET_DIRECTION, sheet->text_is_rtl,
827 SHEET_DIRECTION_IMAGE, (sheet->text_is_rtl
828 ? state->image_rtl
829 : state->image_ltr),
830 -1);
835 /* Add all of the sheets to the sheet_list */
836 static void
837 populate_sheet_list (SheetManager *state)
839 GtkTreeSelection *selection;
840 GtkTreeIter iter;
841 WorkbookControl *wbc = GNM_WBC (state->wbcg);
842 Workbook *wb = wb_control_get_workbook (wbc);
843 Sheet *cur_sheet = wb_control_cur_sheet (wbc);
844 int i, n = workbook_sheet_count (wb);
845 GtkTreePath *sel_path = NULL;
847 selection = gtk_tree_view_get_selection (state->sheet_list);
849 g_signal_handler_block (selection, state->model_selection_changed_listener);
850 if (state->model_row_insertion_listener)
851 g_signal_handler_block (state->model, state->model_row_insertion_listener);
853 gtk_list_store_clear (state->model);
854 gtk_label_set_text (GTK_LABEL (state->warning), "");
856 for (i = 0 ; i < n ; i++) {
857 Sheet *sheet = workbook_sheet_by_index (wb, i);
859 gtk_list_store_append (state->model, &iter);
860 set_sheet_info_at_iter (state, &iter, sheet);
862 if (sheet == cur_sheet)
863 sel_path = gtk_tree_model_get_path (GTK_TREE_MODEL (state->model),
864 &iter);
867 if (sel_path) {
868 gtk_tree_selection_select_path (selection, sel_path);
869 gtk_tree_path_free (sel_path);
872 if (state->model_row_insertion_listener)
873 g_signal_handler_unblock (state->model, state->model_row_insertion_listener);
874 g_signal_handler_unblock (selection, state->model_selection_changed_listener);
876 /* Init the buttons & selection */
877 cb_selection_changed (NULL, state);
880 static void
881 cb_item_move (SheetManager *state, gnm_iter_search_t iter_search)
883 GtkTreeSelection *selection = gtk_tree_view_get_selection (state->sheet_list);
884 GtkTreeIter a, b;
885 GList *selected_rows;
887 g_return_if_fail (selection != NULL);
888 g_return_if_fail (gtk_tree_selection_count_selected_rows (selection) == 1);
890 selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
891 gtk_tree_model_get_iter (GTK_TREE_MODEL (state->model),
892 &a, (GtkTreePath *) selected_rows->data);
893 g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
895 b = a;
896 if (!iter_search (GTK_TREE_MODEL (state->model), &b))
897 return;
899 gtk_list_store_swap (state->model, &a, &b);
900 cb_selection_changed (NULL, state);
903 static void
904 cb_up (G_GNUC_UNUSED GtkWidget *w, SheetManager *state)
906 cb_item_move (state, gtk_tree_model_iter_previous);
909 static void
910 cb_down (G_GNUC_UNUSED GtkWidget *w, SheetManager *state)
912 cb_item_move (state, gtk_tree_model_iter_next);
915 static void
916 cb_add_clicked (G_GNUC_UNUSED GtkWidget *ignore, SheetManager *state)
918 GtkTreeIter sel_iter, iter;
919 GtkTreeSelection *selection = gtk_tree_view_get_selection (state->sheet_list);
920 GList *selected_rows;
921 int index = -1;
922 WorkbookSheetState *old_state;
923 WorkbookControl *wbc = GNM_WBC (state->wbcg);
924 Workbook *wb = wb_control_get_workbook (wbc);
925 Sheet *sheet, *old_sheet = NULL;
927 g_return_if_fail (selection != NULL);
928 g_return_if_fail (gtk_tree_selection_count_selected_rows (selection) == 1);
930 selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
931 gtk_tree_model_get_iter (GTK_TREE_MODEL (state->model),
932 &sel_iter, (GtkTreePath *) selected_rows->data);
933 g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
935 gtk_tree_model_get (GTK_TREE_MODEL (state->model), &sel_iter,
936 SHEET_POINTER, &old_sheet,
937 -1);
938 index = old_sheet->index_in_wb;
940 workbook_signals_block (state);
942 old_state = workbook_sheet_state_new (wb);
943 workbook_sheet_add (wb, index,
944 gnm_sheet_get_max_cols (old_sheet),
945 gnm_sheet_get_max_rows (old_sheet));
946 cmd_reorganize_sheets (wbc, old_state, NULL);
947 update_undo (state, wbc);
949 workbook_signals_unblock (state);
951 g_signal_handler_block (state->model, state->model_row_insertion_listener);
952 sheet = workbook_sheet_by_index (wb, index);
953 gtk_list_store_insert_before (state->model, &iter, &sel_iter);
954 g_signal_handler_unblock (state->model, state->model_row_insertion_listener);
956 set_sheet_info_at_iter (state, &iter, sheet);
958 cb_selection_changed (NULL, state);
961 static void
962 cb_append_clicked (G_GNUC_UNUSED GtkWidget *ignore, SheetManager *state)
964 WorkbookSheetState *old_state;
965 WorkbookControl *wbc = GNM_WBC (state->wbcg);
966 Workbook *wb = wb_control_get_workbook (wbc);
967 GtkTreeIter iter;
968 Sheet *sheet, *old_sheet;
970 workbook_signals_block (state);
972 old_state = workbook_sheet_state_new (wb);
973 old_sheet = workbook_sheet_by_index (wb, 0);
974 workbook_sheet_add (wb, -1,
975 gnm_sheet_get_max_cols (old_sheet),
976 gnm_sheet_get_max_rows (old_sheet));
977 cmd_reorganize_sheets (wbc, old_state, NULL);
978 update_undo (state, wbc);
980 workbook_signals_unblock (state);
982 sheet = workbook_sheet_by_index (wb, workbook_sheet_count (wb) - 1);
984 g_signal_handler_block (state->model, state->model_row_insertion_listener);
985 gtk_list_store_append (state->model, &iter);
986 g_signal_handler_unblock (state->model, state->model_row_insertion_listener);
988 set_sheet_info_at_iter (state, &iter, sheet);
990 cb_selection_changed (NULL, state);
993 static void
994 cb_duplicate_clicked (G_GNUC_UNUSED GtkWidget *ignore,
995 SheetManager *state)
997 GtkTreeIter sel_iter, iter;
998 GtkTreeSelection *selection = gtk_tree_view_get_selection (state->sheet_list);
999 GList *selected_rows;
1000 WorkbookSheetState *old_state;
1001 int index;
1002 WorkbookControl *wbc = GNM_WBC (state->wbcg);
1003 Workbook *wb = wb_control_get_workbook (wbc);
1004 Sheet *new_sheet, *this_sheet;
1006 g_return_if_fail (selection != NULL);
1007 g_return_if_fail (gtk_tree_selection_count_selected_rows (selection) == 1);
1009 selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
1010 gtk_tree_model_get_iter (GTK_TREE_MODEL (state->model),
1011 &sel_iter, (GtkTreePath *) selected_rows->data);
1012 g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
1014 gtk_tree_model_get (GTK_TREE_MODEL (state->model), &sel_iter,
1015 SHEET_POINTER, &this_sheet,
1016 -1);
1018 workbook_signals_block (state);
1020 old_state = workbook_sheet_state_new (wb);
1021 index = this_sheet->index_in_wb;
1022 new_sheet = sheet_dup (this_sheet);
1023 workbook_sheet_attach_at_pos (wb, new_sheet, index + 1);
1024 g_signal_emit_by_name (G_OBJECT (wb), "sheet_added", 0);
1025 cmd_reorganize_sheets (wbc, old_state, NULL);
1026 update_undo (state, wbc);
1028 workbook_signals_unblock (state);
1030 g_signal_handler_block (state->model, state->model_row_insertion_listener);
1031 gtk_list_store_insert_after (state->model, &iter, &sel_iter);
1032 g_signal_handler_unblock (state->model, state->model_row_insertion_listener);
1034 set_sheet_info_at_iter (state, &iter, new_sheet);
1035 g_object_unref (new_sheet);
1037 cb_selection_changed (NULL, state);
1040 static void
1041 cb_delete_clicked (G_GNUC_UNUSED GtkWidget *ignore,
1042 SheetManager *state)
1044 GtkTreeSelection *selection = gtk_tree_view_get_selection (state->sheet_list);
1045 GList *selected_rows, *l;
1046 WorkbookSheetState *old_state;
1047 WorkbookControl *wbc = GNM_WBC (state->wbcg);
1048 Workbook *wb = wb_control_get_workbook (wbc);
1050 g_return_if_fail (selection != NULL);
1052 selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL);
1054 for (l = selected_rows; l != NULL; l = l->next)
1055 l->data = gtk_tree_row_reference_new (GTK_TREE_MODEL (state->model),
1056 (GtkTreePath *) l->data);
1057 workbook_signals_block (state);
1058 old_state = workbook_sheet_state_new (wb);
1060 for (l = selected_rows; l != NULL; l = l->next) {
1061 GtkTreeRowReference *ref = l->data;
1062 if (gtk_tree_row_reference_valid (ref)) {
1063 GtkTreePath *path = gtk_tree_row_reference_get_path (ref);
1064 GtkTreeIter sel_iter;
1065 Sheet *sheet;
1067 gtk_tree_model_get_iter (GTK_TREE_MODEL (state->model), &sel_iter, path);
1068 gtk_tree_path_free (path);
1069 gtk_tree_model_get (GTK_TREE_MODEL (state->model), &sel_iter,
1070 SHEET_POINTER, &sheet,
1071 -1);
1072 gtk_list_store_remove (state->model, &sel_iter);
1073 workbook_sheet_delete (sheet);
1077 cmd_reorganize_sheets (wbc, old_state, NULL);
1078 update_undo (state, wbc);
1079 workbook_signals_unblock (state);
1081 populate_sheet_list (state);
1082 cb_name_edited (NULL, NULL, NULL, state);
1084 g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_row_reference_free);
1087 static void
1088 cb_cancel_clicked (G_GNUC_UNUSED GtkWidget *ignore,
1089 SheetManager *state)
1091 gtk_widget_destroy (GTK_WIDGET (state->dialog));
1094 static char *
1095 verify_validity (SheetManager *state, gboolean *pchanged)
1097 char *result = NULL;
1098 gboolean changed = FALSE;
1099 GHashTable *names = g_hash_table_new_full (g_str_hash, g_str_equal,
1100 (GDestroyNotify)g_free, NULL);
1101 GtkTreeIter this_iter;
1102 gint n = 0;
1104 while (result == NULL &&
1105 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (state->model),
1106 &this_iter, NULL, n)) {
1107 Sheet *this_sheet;
1108 char *old_name, *new_name, *new_name2;
1110 gtk_tree_model_get (GTK_TREE_MODEL (state->model), &this_iter,
1111 SHEET_POINTER, &this_sheet,
1112 SHEET_NAME, &old_name,
1113 SHEET_NEW_NAME, &new_name,
1114 -1);
1116 new_name2 = g_utf8_casefold (*new_name != 0 ? new_name : old_name, -1);
1117 if (g_hash_table_lookup (names, new_name2)) {
1118 result = g_strdup_printf (_("You may not call more than one sheet \"%s\"."),
1119 *new_name != 0 ? new_name : old_name);
1120 g_free (new_name2);
1121 } else
1122 g_hash_table_insert (names, new_name2, new_name2);
1124 if (*new_name && strcmp (old_name, new_name))
1125 changed = TRUE;
1127 g_free (old_name);
1128 g_free (new_name);
1129 n++;
1132 g_hash_table_destroy (names);
1133 *pchanged = changed;
1134 return result;
1138 static void
1139 cb_apply_names_clicked (G_GNUC_UNUSED GtkWidget *ignore, SheetManager *state)
1141 WorkbookControl *wbc = GNM_WBC (state->wbcg);
1142 Workbook *wb = wb_control_get_workbook (wbc);
1143 WorkbookSheetState *old_state;
1144 GtkTreeIter this_iter;
1145 gint n = 0;
1147 /* Stop listening to changes in the sheet order. */
1148 workbook_signals_block (state);
1150 old_state = workbook_sheet_state_new (wb);
1151 while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (state->model),
1152 &this_iter, NULL, n)) {
1153 Sheet *this_sheet;
1154 char *new_name;
1156 gtk_tree_model_get (GTK_TREE_MODEL (state->model), &this_iter,
1157 SHEET_POINTER, &this_sheet,
1158 SHEET_NEW_NAME, &new_name,
1159 -1);
1161 if (*new_name) {
1162 g_object_set (this_sheet,
1163 "name", new_name,
1164 NULL);
1165 gtk_list_store_set (state->model, &this_iter,
1166 SHEET_NAME, new_name,
1167 SHEET_NEW_NAME, "",
1168 -1);
1171 g_free (new_name);
1172 n++;
1175 cmd_reorganize_sheets (wbc, old_state, NULL);
1176 gtk_label_set_text (GTK_LABEL (state->warning), "");
1177 update_undo (state, wbc);
1179 workbook_signals_unblock (state);
1182 static void
1183 cb_sheet_order_destroy (SheetManager *state)
1185 Workbook *wb = wb_control_get_workbook (GNM_WBC (state->wbcg));
1187 /* Stop to listen to changes in the sheet order. */
1188 if (state->sheet_order_changed_listener)
1189 g_signal_handler_disconnect (G_OBJECT (wb),
1190 state->sheet_order_changed_listener);
1191 if (state->sheet_added_listener)
1192 g_signal_handler_disconnect (G_OBJECT (wb),
1193 state->sheet_added_listener);
1194 if (state->sheet_deleted_listener)
1195 g_signal_handler_disconnect (G_OBJECT (wb),
1196 state->sheet_deleted_listener);
1198 if (state->model != NULL) {
1199 g_object_unref (state->model);
1200 state->model = NULL;
1202 g_object_unref (state->gui);
1203 g_object_set_data (G_OBJECT (wb), SHEET_ORDER_KEY, NULL);
1204 state->gui = NULL;
1206 g_object_unref (state->image_padlock);
1207 state->image_padlock = NULL;
1209 g_object_unref (state->image_padlock_no);
1210 state->image_padlock_no = NULL;
1212 g_object_unref (state->image_visible);
1213 state->image_visible = NULL;
1215 g_object_unref (state->image_rtl);
1216 state->image_rtl = NULL;
1218 g_object_unref (state->image_ltr);
1219 state->image_ltr = NULL;
1221 g_free (state);
1224 static void
1225 dialog_sheet_order_update_sheet_order (SheetManager *state)
1227 GtkTreeIter iter;
1228 Workbook *wb = wb_control_get_workbook (GNM_WBC (state->wbcg));
1229 int i, n_sheets, n_children;
1230 GtkTreeModel *model = GTK_TREE_MODEL (state->model);
1231 GtkTreeSelection *sel = gtk_tree_view_get_selection (state->sheet_list);
1233 n_sheets = workbook_sheet_count (wb);
1234 n_children = gtk_tree_model_iter_n_children (model, NULL);
1236 if (n_sheets != n_children) {
1237 /* This signal also occurs when sheets are added or deleted. We handle this */
1238 /* when those signals arrive. */
1239 return;
1242 for (i = 0; i < n_sheets; i++) {
1243 gchar *name, *new_name;
1244 gboolean is_locked;
1245 gboolean is_visible;
1246 gboolean is_rtl;
1247 GdkRGBA *back, *fore;
1248 Sheet *sheet_wb = workbook_sheet_by_index (wb, i);
1249 Sheet *sheet_model;
1250 gboolean selected;
1251 int j, row_max, col_max;
1253 for (j = i; j < n_children; j++) {
1254 if (!gtk_tree_model_iter_nth_child (model, &iter,
1255 NULL, j))
1256 break;
1257 gtk_tree_model_get (model, &iter, SHEET_POINTER,
1258 &sheet_model, -1);
1259 if (sheet_model == sheet_wb)
1260 break;
1262 if (j == i)
1263 continue;
1265 if (!gtk_tree_model_iter_nth_child (model, &iter, NULL, j))
1266 break;
1267 selected = gtk_tree_selection_iter_is_selected (sel, &iter);
1268 gtk_tree_model_get (model, &iter,
1269 SHEET_LOCKED, &is_locked,
1270 SHEET_VISIBLE, &is_visible,
1271 SHEET_ROW_MAX, &row_max,
1272 SHEET_COL_MAX, &col_max,
1273 SHEET_NAME, &name,
1274 SHEET_NEW_NAME, &new_name,
1275 SHEET_POINTER, &sheet_model,
1276 BACKGROUND_COLOUR, &back,
1277 FOREGROUND_COLOUR, &fore,
1278 SHEET_DIRECTION, &is_rtl,
1279 -1);
1280 gtk_list_store_remove (state->model, &iter);
1281 g_signal_handler_block (state->model, state->model_row_insertion_listener);
1282 gtk_list_store_insert (state->model, &iter, i);
1283 g_signal_handler_unblock (state->model, state->model_row_insertion_listener);
1284 gtk_list_store_set (state->model, &iter,
1285 SHEET_LOCKED, is_locked,
1286 SHEET_LOCK_IMAGE, is_locked ?
1287 state->image_padlock : state->image_padlock_no,
1288 SHEET_VISIBLE, is_visible,
1289 SHEET_VISIBLE_IMAGE, is_visible ?
1290 state->image_visible : NULL,
1291 SHEET_ROW_MAX, row_max,
1292 SHEET_COL_MAX, col_max,
1293 SHEET_NAME, name,
1294 SHEET_NEW_NAME, new_name,
1295 SHEET_POINTER, sheet_model,
1296 BACKGROUND_COLOUR, back,
1297 FOREGROUND_COLOUR, fore,
1298 SHEET_DIRECTION, is_rtl,
1299 SHEET_DIRECTION_IMAGE,
1300 is_rtl ? state->image_rtl : state->image_ltr,
1301 -1);
1302 if (back)
1303 gdk_rgba_free (back);
1304 if (fore)
1305 gdk_rgba_free (fore);
1306 g_free (name);
1307 g_free (new_name);
1308 if (selected)
1309 gtk_tree_selection_select_iter (sel, &iter);
1312 cb_selection_changed (NULL, state);
1315 static void
1316 cb_sheet_order_changed (Workbook *wb, SheetManager *state)
1318 dialog_sheet_order_update_sheet_order (state);
1321 static void
1322 cb_sheet_deleted (Workbook *wb, SheetManager *state)
1324 populate_sheet_list (state);
1327 static void
1328 cb_sheet_added (Workbook *wb, SheetManager *state)
1330 populate_sheet_list (state);
1335 static void
1336 dialog_sheet_order_changed (SheetManager *state)
1338 WorkbookControl *wbc = GNM_WBC (state->wbcg);
1339 Workbook *wb = wb_control_get_workbook (wbc);
1340 WorkbookSheetState *old_state;
1341 GtkTreeIter this_iter;
1342 gint n = 0, changes = 0;
1344 workbook_signals_block (state);
1346 old_state = workbook_sheet_state_new (wb);
1347 while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (state->model),
1348 &this_iter, NULL, n)) {
1349 Sheet *this_sheet;
1350 gtk_tree_model_get (GTK_TREE_MODEL (state->model), &this_iter,
1351 SHEET_POINTER, &this_sheet,
1352 -1);
1353 if (this_sheet->index_in_wb != n) {
1354 changes++;
1355 workbook_sheet_move (this_sheet, n - this_sheet->index_in_wb);
1357 n++;
1360 if (changes > 0) {
1361 cmd_reorganize_sheets (wbc, old_state, NULL);
1362 update_undo (state, wbc);
1363 } else
1364 workbook_sheet_state_free (old_state);
1366 workbook_signals_unblock (state);
1369 static void
1370 cb_dialog_order_changed (G_GNUC_UNUSED GtkListStore *model,
1371 G_GNUC_UNUSED GtkTreePath *path,
1372 G_GNUC_UNUSED GtkTreeIter *iter,
1373 G_GNUC_UNUSED gpointer arg3,
1374 SheetManager *state)
1376 dialog_sheet_order_changed (state);
1379 static gboolean
1380 dialog_sheet_order_changed_idle_handler (SheetManager *state)
1382 dialog_sheet_order_changed (state);
1383 return FALSE;
1387 static void
1388 cb_dialog_order_changed_by_insertion (G_GNUC_UNUSED GtkListStore *model,
1389 G_GNUC_UNUSED GtkTreePath *path,
1390 G_GNUC_UNUSED GtkTreeIter *iter,
1391 SheetManager *state)
1393 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
1394 (GSourceFunc)dialog_sheet_order_changed_idle_handler,
1395 state, NULL);
1398 static void
1399 cb_undo_clicked (G_GNUC_UNUSED GtkWidget *ignore, SheetManager *state)
1401 WorkbookControl *wbc = GNM_WBC (state->wbcg);
1402 Workbook *wb = wb_control_get_workbook (wbc);
1404 command_undo (wbc);
1405 gtk_widget_set_sensitive (state->undo_btn, wb->undo_commands != NULL);
1407 populate_sheet_list (state);
1410 static void
1411 cb_adv_check_toggled (G_GNUC_UNUSED GtkToggleButton *ignored,
1412 SheetManager *state)
1414 gboolean visible = gtk_toggle_button_get_active
1415 (GTK_TOGGLE_BUTTON (state->advanced_check));
1417 gtk_tree_view_column_set_visible (state->dir_column, visible);
1418 gtk_tree_view_column_set_visible (state->col_max_column, visible);
1419 gtk_tree_view_column_set_visible (state->row_max_column, visible);
1422 static void
1423 destroy_cb (GObject *obj)
1425 g_object_set_data (obj, "state", NULL);
1428 void
1429 dialog_sheet_order (WBCGtk *wbcg)
1431 SheetManager *state;
1432 GtkBuilder *gui;
1433 GtkGrid *grid;
1434 GOColorGroup *cg;
1435 Workbook *wb;
1436 GtkWidget *widget;
1437 GdkPixbuf *icon;
1439 g_return_if_fail (wbcg != NULL);
1441 widget = GTK_WIDGET (wbcg_toplevel (wbcg));
1443 gui = gnm_gtk_builder_load ("sheet-order.ui", NULL, GO_CMD_CONTEXT (wbcg));
1444 if (gui == NULL)
1445 return;
1447 wb = wb_control_get_workbook (GNM_WBC (wbcg));
1448 if (g_object_get_data (G_OBJECT (wb), SHEET_ORDER_KEY)) {
1449 GtkWidget *dialog = gtk_message_dialog_new
1450 (wbcg_toplevel (wbcg),
1451 GTK_DIALOG_DESTROY_WITH_PARENT,
1452 GTK_MESSAGE_WARNING,
1453 GTK_BUTTONS_CLOSE,
1454 _("Another view is already managing sheets"));
1455 go_gtk_dialog_run (GTK_DIALOG (dialog), wbcg_toplevel (wbcg));
1456 return;
1458 g_object_set_data (G_OBJECT (wb), SHEET_ORDER_KEY, (gpointer) gui);
1459 state = g_new0 (SheetManager, 1);
1460 state->gui = gui;
1461 state->wbcg = wbcg;
1462 state->dialog = go_gtk_builder_get_widget (gui, "sheet-order-dialog");
1463 state->warning = go_gtk_builder_get_widget (gui, "warning");
1464 state->up_btn = go_gtk_builder_get_widget (gui, "up_button");
1465 state->down_btn = go_gtk_builder_get_widget (gui, "down_button");
1466 state->add_btn = go_gtk_builder_get_widget (gui, "add_button");
1467 state->append_btn = go_gtk_builder_get_widget (gui, "append_button");
1468 state->duplicate_btn = go_gtk_builder_get_widget (gui, "duplicate_button");
1469 state->delete_btn = go_gtk_builder_get_widget (gui, "delete_button");
1471 state->apply_names_btn = go_gtk_builder_get_widget (gui, "ok_button");
1472 state->sort_asc_btn = go_gtk_builder_get_widget (gui, "sort-asc-button");
1473 state->sort_desc_btn = go_gtk_builder_get_widget (gui, "sort-desc-button");
1474 state->undo_btn = go_gtk_builder_get_widget (gui, "undo-button");
1475 state->cancel_btn = go_gtk_builder_get_widget (gui, "cancel_button");
1476 state->advanced_check = go_gtk_builder_get_widget (gui, "advanced-check");
1477 state->initial_colors_set = FALSE;
1478 state->image_padlock = go_gtk_widget_render_icon_pixbuf (widget, "gnumeric-protection-yes", GTK_ICON_SIZE_MENU);
1479 state->image_padlock_no = go_gtk_widget_render_icon_pixbuf (widget, "gnumeric-protection-no", GTK_ICON_SIZE_MENU);
1480 state->image_visible = go_gtk_widget_render_icon_pixbuf (widget, "gnumeric-visible", GTK_ICON_SIZE_MENU);
1481 state->image_ltr = go_gtk_widget_render_icon_pixbuf (widget, "format-text-direction-ltr", GTK_ICON_SIZE_MENU);
1482 state->image_rtl = go_gtk_widget_render_icon_pixbuf (widget, "format-text-direction-rtl", GTK_ICON_SIZE_MENU);
1483 /* Listen for changes in the sheet order. */
1484 state->sheet_order_changed_listener = g_signal_connect (G_OBJECT (wb),
1485 "sheet_order_changed", G_CALLBACK (cb_sheet_order_changed),
1486 state);
1487 state->sheet_added_listener = g_signal_connect (G_OBJECT (wb),
1488 "sheet_added", G_CALLBACK (cb_sheet_added),
1489 state);
1490 state->sheet_deleted_listener = g_signal_connect (G_OBJECT (wb),
1491 "sheet_deleted", G_CALLBACK (cb_sheet_deleted),
1492 state);
1494 grid = GTK_GRID (go_gtk_builder_get_widget (gui,"main-grid"));
1495 cg = go_color_group_fetch ("back_color_group",
1496 wb_control_view (GNM_WBC (wbcg)));
1497 icon = go_gtk_widget_render_icon_pixbuf (widget, "gnumeric-bucket", GTK_ICON_SIZE_LARGE_TOOLBAR);
1498 state->ccombo_back = go_combo_color_new (icon, _("Default"), 0, cg);
1499 g_object_unref (icon);
1500 g_object_unref (cg);
1501 go_combo_color_set_instant_apply (
1502 GO_COMBO_COLOR (state->ccombo_back), TRUE);
1503 gtk_grid_attach (grid, state->ccombo_back, 1, 4, 1, 1);
1504 gtk_widget_set_sensitive (state->ccombo_back, FALSE);
1506 cg = go_color_group_fetch ("fore_color_group",
1507 wb_control_view (GNM_WBC (wbcg)));
1508 icon = go_gtk_widget_render_icon_pixbuf (widget, "font", GTK_ICON_SIZE_LARGE_TOOLBAR);
1509 state->ccombo_fore = go_combo_color_new (icon, _("Default"), 0, cg);
1510 g_object_unref (icon);
1511 g_object_unref (cg);
1512 go_combo_color_set_instant_apply (
1513 GO_COMBO_COLOR (state->ccombo_fore), TRUE);
1514 gtk_grid_attach (grid, state->ccombo_fore, 2, 4, 1, 1);
1515 gtk_widget_set_sensitive (state->ccombo_fore, FALSE);
1517 create_sheet_list (state);
1518 populate_sheet_list (state);
1520 #define CONNECT(o,s,c) g_signal_connect(G_OBJECT(o),s,G_CALLBACK(c),state)
1521 CONNECT (state->up_btn, "clicked", cb_up);
1522 CONNECT (state->down_btn, "clicked", cb_down);
1523 CONNECT (state->sort_asc_btn, "clicked", cb_asc);
1524 CONNECT (state->sort_desc_btn, "clicked", cb_desc);
1525 CONNECT (state->add_btn, "clicked", cb_add_clicked);
1526 CONNECT (state->append_btn, "clicked", cb_append_clicked);
1527 CONNECT (state->duplicate_btn, "clicked", cb_duplicate_clicked);
1528 CONNECT (state->delete_btn, "clicked", cb_delete_clicked);
1529 CONNECT (state->apply_names_btn, "clicked", cb_apply_names_clicked);
1530 CONNECT (state->cancel_btn, "clicked", cb_cancel_clicked);
1531 CONNECT (state->undo_btn, "clicked", cb_undo_clicked);
1532 CONNECT (state->advanced_check, "toggled", cb_adv_check_toggled);
1533 CONNECT (state->ccombo_back, "color_changed", cb_color_changed_back);
1534 CONNECT (state->ccombo_fore, "color_changed", cb_color_changed_fore);
1535 CONNECT (state->model, "rows-reordered", cb_dialog_order_changed);
1536 state->model_row_insertion_listener =
1537 CONNECT (state->model, "row-inserted", cb_dialog_order_changed_by_insertion);
1538 #undef CONNECT
1540 cb_adv_check_toggled (NULL, state);
1542 gnm_init_help_button (
1543 go_gtk_builder_get_widget (state->gui, "help_button"),
1544 GNUMERIC_HELP_LINK_SHEET_MANAGER);
1546 gtk_widget_set_sensitive (state->undo_btn, wb->undo_commands != NULL);
1547 gtk_widget_set_sensitive (state->apply_names_btn, FALSE);
1549 /* a candidate for merging into attach guru */
1550 wbc_gtk_attach_guru (state->wbcg, GTK_WIDGET (state->dialog));
1551 g_object_set_data_full (G_OBJECT (state->dialog),
1552 "state", state, (GDestroyNotify) cb_sheet_order_destroy);
1553 g_signal_connect (G_OBJECT (state->dialog), "destroy", G_CALLBACK (destroy_cb), NULL);
1555 gnm_restore_window_geometry (GTK_WINDOW (state->dialog),
1556 SHEET_ORDER_KEY);
1558 go_gtk_nonmodal_dialog (wbcg_toplevel (state->wbcg),
1559 GTK_WINDOW (state->dialog));
1560 gtk_widget_show_all (GTK_WIDGET (state->dialog));