dialog-cell-sort.c 32.6 KB
Newer Older
1 2 3
/*
 * dialog-cell-sort.c:  Implements Cell Sort dialog boxes.
 *
4 5
 * Authors:
 *  JP Rosevear   <jpr@arcavia.com>
6
 *  Michael Meeks <michael@ximian.com>
7
 *  Andreas J. Guelzow <aguelzow@taliesin.ca>
8
 *  Morten Welinder <terra@gnome.org>
jpekka's avatar
jpekka committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
23
 */
Jody Goldberg's avatar
Jody Goldberg committed
24

25
#include <gnumeric-config.h>
26
#include <glib/gi18n-lib.h>
27 28
#include <gnumeric.h>
#include "dialogs.h"
29
#include "help.h"
30 31 32 33 34 35 36 37 38 39 40 41

#include <workbook-view.h>
#include <gui-util.h>
#include <cell.h>
#include <expr.h>
#include <selection.h>
#include <parse-util.h>
#include <ranges.h>
#include <commands.h>
#include <workbook.h>
#include <sort.h>
#include <sheet.h>
42
#include <sheet-view.h>
43
#include <wbc-gtk.h>
44
#include <gnumeric-gconf.h>
45
#include <widgets/gnumeric-cell-renderer-toggle.h>
46
#include <widgets/gnumeric-expr-entry.h>
47
#include <value.h>
48

49
#include <gtk/gtk.h>
Jody Goldberg's avatar
Jody Goldberg committed
50
#include <gsf/gsf-impl-utils.h>
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
51
#include <gdk/gdkkeysyms.h>
52
#include <goffice/goffice.h>
53

54
#define CELL_SORT_KEY "cell-sort-dialog"
55

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
56 57


58
typedef struct {
59
	WBCGtk  *wbcg;
60
	Workbook  *wb;
Jody Goldberg's avatar
Jody Goldberg committed
61 62
	SheetView *sv;
	Sheet     *sheet;
63

64
	GtkBuilder *gui;
65 66 67 68
	GtkWidget *dialog;
	GtkWidget *warning_dialog;
	GtkWidget *cancel_button;
	GtkWidget *ok_button;
69 70
	GtkWidget *up_button;
	GtkWidget *down_button;
71 72
	GtkWidget *add_button;
	GtkWidget *delete_button;
73
	GtkWidget *clear_button;
74 75
	GnmExprEntry *range_entry;
	GnmExprEntry *add_entry;
76 77
	GtkListStore  *model;
	GtkTreeView   *treeview;
78
	GtkTreeViewColumn *header_column;
79
	GtkTreeSelection   *selection;
80
	GtkWidget *cell_sort_row_rb;
81
	GtkWidget *cell_sort_col_rb;
82
	GtkWidget *cell_sort_header_check;
83
	GtkWidget *retain_format_check;
84 85
	GdkPixbuf *image_ascending;
	GdkPixbuf *image_descending;
86
	GOLocaleSel *locale_selector;
87

Jody Goldberg's avatar
Jody Goldberg committed
88
	GnmValue  *sel;
89 90
	gboolean   header;
	gboolean   is_cols;
91
	int        sort_items;
92

93 94 95
} SortFlowState;

enum {
96
	ITEM_HEADER,
97 98
	ITEM_NAME,
	ITEM_DESCENDING,
99
	ITEM_DESCENDING_IMAGE,
100 101 102 103 104 105
	ITEM_CASE_SENSITIVE,
	ITEM_SORT_BY_VALUE,
	ITEM_MOVE_FORMAT,
	ITEM_NUMBER,
	NUM_COLMNS
};
106

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
107 108 109 110 111 112 113 114 115
static const gint MAX_MENU_SIZE = 20;
typedef struct {
	gint index;
	gint start;
	gint end;
	gboolean done_submenu;
	SortFlowState *state;
} AddSortFieldMenuState;

116 117 118 119 120 121 122 123 124 125 126 127 128 129
static gchar *
header_name (Sheet *sheet, int col, int row)
{
	GnmCell *cell;
	gchar *str = NULL;

	cell = sheet_cell_get (sheet, col, row);
	if (cell)
		str = value_get_as_string (cell->value);

	return str;
}


130
static gchar *
131
col_row_name (Sheet *sheet, int col, int row, gboolean header, gboolean is_cols)
132
{
133
	GnmCell *cell;
134 135
	gchar *str = NULL;

136 137 138 139 140
	if (is_cols)
		str = g_strdup_printf (_("Column %s"), col_name (col));
	else
		str = g_strdup_printf (_("Row %s"), row_name (row));

141 142
	if (header) {
		cell = sheet_cell_get (sheet, col, row);
143
		if (cell && !gnm_cell_is_blank (cell)) {
144 145
			gchar *header_str, *generic_str = str;
			header_str = value_get_as_string (cell->value);
146
			str = g_strdup_printf (_("%s (%s)"), header_str, generic_str);
147 148
			g_free (header_str);
			g_free (generic_str);
149
		}
150 151
	}

152 153 154
	return str;
}

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
155

156
static gboolean
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
157
already_in_sort_fields(int index, SortFlowState *state)
158
{
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
159 160 161
	GtkTreeIter iter;
	int item = 0;
	gint number;
162

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
163 164 165 166 167 168 169
	/* See if index is already in the sort fields */
	while (gtk_tree_model_iter_nth_child  (GTK_TREE_MODEL (state->model),
					       &iter, NULL, item)) {
		gtk_tree_model_get (GTK_TREE_MODEL (state->model), &iter,
				    ITEM_NUMBER, &number,
				    -1);
		item++;
170

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
171 172 173
		if (number == index) {
			return TRUE;
		}
174 175
	}

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
176 177 178 179 180 181 182 183 184
	/* Here means not already in sort fields */
	return FALSE;
}

static gboolean
range_already_in_sort_criteria(gint start, gint end, SortFlowState *state)
{
	gint i;
	for (i=start; i<=end; i++) {
185
		if (!already_in_sort_fields(i, state))
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
186
			return FALSE;
187
	}
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
188 189 190 191 192
	return TRUE;
}


static void
193
build_sort_field_menu (gint start, gint end, gint index, GtkWidget *menu, SortFlowState *state, int used);
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
194 195 196 197

static void
cb_sort_field_menu_activate(GtkWidget *item, AddSortFieldMenuState *menu_state)
{
198 199 200 201 202 203 204 205 206 207
	GtkWidget *menu = GTK_WIDGET (gtk_menu_item_get_submenu(GTK_MENU_ITEM (item)));

	if (menu_state->done_submenu == FALSE) {
		build_sort_field_menu(menu_state->start,
				      menu_state->end,
				      menu_state->index,
				      menu,
				      menu_state->state, 0);
		menu_state->done_submenu = TRUE;
	}
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
208 209 210
}

static void
211
set_button_sensitivity(SortFlowState *state)
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
212 213
{
	int items;
214 215 216 217 218 219

	if (state->sel == NULL) {
		gtk_widget_set_sensitive (state->ok_button, FALSE);
		return;
	}

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
220 221
	items = state->is_cols ? (state->sel->v_range.cell.b.row -
				  state->sel->v_range.cell.a.row + 1) :
222 223
		(state->sel->v_range.cell.b.col -
		 state->sel->v_range.cell.a.col + 1);
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
224 225 226 227 228
	if (state->header)
		items -= 1;
	gtk_widget_set_sensitive (state->ok_button,
				  (state->sort_items != 0) &&
				  (items > 1));
229
	gtk_widget_set_sensitive (state->clear_button, state->sort_items != 0);
230 231
}

232 233 234
static void
append_data (SortFlowState *state, int i, int index)
{
235
	gchar *str, *header;
236 237
	GtkTreeIter iter;
	Sheet *sheet = state->sel->v_range.cell.a.sheet;
238
	gboolean sort_asc = gnm_conf_get_core_sort_default_ascending ();
239

240 241 242
	header = state->is_cols
		? header_name (sheet, i, index)
		: header_name (sheet, index, i);
243
	str = state->is_cols
244 245
		? col_row_name (sheet, i, index, FALSE, TRUE)
		: col_row_name (sheet, index, i, FALSE, FALSE);
246 247
	gtk_list_store_append (state->model, &iter);
	gtk_list_store_set (state->model, &iter,
248
			    ITEM_HEADER,  header,
249
			    ITEM_NAME,  str,
250
			    ITEM_DESCENDING, !sort_asc,
Morten Welinder's avatar
Morten Welinder committed
251
			    ITEM_DESCENDING_IMAGE, sort_asc ? state->image_ascending
252
			    : state->image_descending,
253
			    ITEM_CASE_SENSITIVE, gnm_conf_get_core_sort_default_by_case (),
254 255 256 257 258 259
			    ITEM_SORT_BY_VALUE, TRUE,
			    ITEM_MOVE_FORMAT, TRUE,
			    ITEM_NUMBER, i,
			    -1);
	state->sort_items++;
	g_free (str);
260
	g_free (header);
261 262
}

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
263 264 265 266 267 268 269 270
static void
cb_sort_field_selection(GtkWidget *item, AddSortFieldMenuState *menu_state)
{
	append_data(menu_state->state,
		    menu_state->start,
		    menu_state->index);
	/* Update sensitivity if this is the first sort item. */
	if (menu_state->state->sort_items == 1)
271
		set_button_sensitivity(menu_state->state);
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
272 273 274
}

static void
275
build_sort_field_menu (gint start, gint end, gint index, GtkWidget *menu, SortFlowState *state, int used)
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
276 277 278 279 280 281 282 283 284 285 286
{
	Sheet *sheet = state->sel->v_range.cell.a.sheet;
	GtkWidget *item;
	GtkWidget *submenu;
	int i;
	int this_end;
	char *str;
	char *str_start;
	char *str_end;
	AddSortFieldMenuState *menu_state;
	gint menu_size;
287

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
288
	menu_size = 1 + end - start;
289 290 291
	if (MAX_MENU_SIZE < menu_size - used) {
		gint submenu_size;
		gint balanced_submenu_size;
292

293
		submenu_size = (menu_size + MAX_MENU_SIZE - 1) / MAX_MENU_SIZE;
294
		balanced_submenu_size = sqrt((double)
295 296 297 298
					     (menu_size + MAX_MENU_SIZE - 1));
		if (balanced_submenu_size > submenu_size)
			submenu_size = balanced_submenu_size;

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
299 300 301 302
		for (i = start; i <= end; i+=submenu_size) {
			this_end = i + submenu_size - 1;
			if (this_end > end)
				this_end = end;
303

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
304 305
			/* See if there are any fields in this range that aren't already
			   in the sort.
306
			*/
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
307
			if (range_already_in_sort_criteria(i, this_end, state))
308 309 310 311 312 313 314 315 316 317
				continue;

			str_start = state->is_cols
				? col_row_name (sheet, i, index, state->header, TRUE)
				: col_row_name (sheet, index, i, state->header, FALSE);

			str_end = state->is_cols
				? col_row_name (sheet, this_end, index, state->header, TRUE)
				: col_row_name (sheet, index, this_end, state->header, FALSE);

318
			str = g_strdup_printf(_("%s to %s"), str_start, str_end);
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
319 320 321 322 323 324
			g_free(str_start);
			g_free(str_end);

			item = (GtkWidget *) gtk_menu_item_new_with_label(str);
			gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
			gtk_widget_show (item);
325

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
326 327 328 329 330 331 332 333 334 335 336 337 338 339
			menu_state = g_new(AddSortFieldMenuState, 1);
			menu_state->start = i;
			menu_state->end = this_end;
			menu_state->index = index;
			menu_state->state = state;
			menu_state->done_submenu = FALSE;
			submenu = gtk_menu_new();
			gtk_menu_item_set_submenu(GTK_MENU_ITEM (item), submenu);
			g_signal_connect (item, "activate",
					  G_CALLBACK (cb_sort_field_menu_activate), menu_state);
		}
	}  else {
		for (i = start; i <= end; i++) {
			if (FALSE == already_in_sort_fields(i, state)) {
340 341

				str = state->is_cols
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
342 343 344 345 346 347 348 349 350 351 352 353
					? col_row_name (sheet, i, index, state->header, TRUE)
					: col_row_name (sheet, index, i, state->header, FALSE);
				item = (GtkWidget *) gtk_menu_item_new_with_label(str);
				gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
				gtk_widget_show (item);
				menu_state = g_new(AddSortFieldMenuState, 1);
				menu_state->start = i;
				menu_state->end = i;
				menu_state->index = index;
				menu_state->state = state;
				menu_state->done_submenu = FALSE;
				g_signal_connect (item, "activate",
354
						  G_CALLBACK (cb_sort_field_selection),
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
355 356 357 358 359 360
						  menu_state);
			}
		}
	}
}

361
static void
362
load_model_data (SortFlowState *state)
363 364 365 366 367
{
	int start;
	int end;
	int index;
	int i;
368
	int limit = gnm_conf_get_core_sort_dialog_max_initial_clauses ();
369 370 371

	if (state->is_cols) {
		start = state->sel->v_range.cell.a.col;
372
		end = state->sel->v_range.cell.b.col;
373 374 375
		index = state->sel->v_range.cell.a.row;
	} else {
		start = state->sel->v_range.cell.a.row;
376
		end = state->sel->v_range.cell.b.row;
377 378 379 380
		index = state->sel->v_range.cell.a.col;
	}

	gtk_list_store_clear (state->model);
381
	state->sort_items = 0;
382

383 384
	if (end >= start + limit)
		end = start + limit - 1;
385

386 387 388 389 390
	for (i = start; i <= end; i++)
		append_data (state, i, index);
}

static void
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
391
translate_range (GnmValue *range, SortFlowState *state)
392
{
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
393 394 395 396
	state->is_cols = !gtk_toggle_button_get_active (
		GTK_TOGGLE_BUTTON (state->cell_sort_row_rb));
	state->header = gtk_toggle_button_get_active (
		GTK_TOGGLE_BUTTON (state->cell_sort_header_check));
397

398
	value_release (state->sel);
399
	state->sel = range;
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
400 401 402 403 404 405 406 407 408
	load_model_data(state);
}

static void
cb_sort_header_check(SortFlowState *state)
{
	state->header = gtk_toggle_button_get_active (
		GTK_TOGGLE_BUTTON (state->cell_sort_header_check));

409
	gtk_tree_view_column_set_visible (state->header_column, state->header);
410
	set_button_sensitivity (state);
411 412 413
}

static void
414
cb_update_to_new_range (SortFlowState *state)
415
{
Jody Goldberg's avatar
Jody Goldberg committed
416
        GnmValue *range;
417

418
        range = gnm_expr_entry_parse_as_value
419
		(GNM_EXPR_ENTRY (state->range_entry), state->sheet);
420 421 422 423 424
	if (range == NULL) {
		if (state->sel != NULL) {
			value_release (state->sel);
			state->sel = NULL;
			gtk_list_store_clear (state->model);
425
			state->sort_items = 0;
426
		}
427
	} else
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
428
		translate_range (range, state);
429
	set_button_sensitivity (state);
430 431
}

432 433
static void
cb_dialog_destroy (SortFlowState  *state)
434
{
435 436
	value_release (state->sel);
	state->sel = NULL;
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
437

438 439 440
	if (state->model != NULL)
		g_object_unref (G_OBJECT (state->model));
	if (state->gui != NULL)
441 442
		g_object_unref (G_OBJECT (state->gui));

443
	wbcg_edit_finish (state->wbcg, WBC_EDIT_REJECT, NULL);
444 445 446

	state->dialog = NULL;

447 448 449 450 451
	g_object_unref (state->image_ascending);
	state->image_ascending = NULL;
	g_object_unref (state->image_descending);
	state->image_descending = NULL;

452 453 454
	g_free (state);
}

455
static void
456
cb_dialog_ok_clicked (SortFlowState *state)
457
{
458
	GnmSortData *data, *data_copy;
Jody Goldberg's avatar
Jody Goldberg committed
459
	GnmSortClause *array, *this_array_item;
460 461
	int item = 0;
	GtkTreeIter iter;
462
	gboolean descending, case_sensitive, sort_by_value, move_format;
463
	gint number;
464
	gint base;
465
	char const *text;
466

Jody Goldberg's avatar
Jody Goldberg committed
467
	array = g_new (GnmSortClause, state->sort_items);
468
	this_array_item = array;
469
	base = (state->is_cols ? state->sel->v_range.cell.a.col : state->sel->v_range.cell.a.row);
470 471 472 473 474 475 476 477 478 479 480

	while (gtk_tree_model_iter_nth_child  (GTK_TREE_MODEL (state->model),
					       &iter, NULL, item)) {
		gtk_tree_model_get (GTK_TREE_MODEL (state->model), &iter,
				    ITEM_DESCENDING,&descending,
				    ITEM_CASE_SENSITIVE, &case_sensitive,
				    ITEM_SORT_BY_VALUE, &sort_by_value,
				    ITEM_MOVE_FORMAT, &move_format,
				    ITEM_NUMBER, &number,
				    -1);
		item++;
481
		this_array_item->offset = number - base;
482
		this_array_item->asc = !!descending;
483 484 485
		this_array_item->cs = case_sensitive;
		this_array_item->val = sort_by_value;
		this_array_item++;
486 487 488
	}


Jody Goldberg's avatar
Jody Goldberg committed
489
	data = g_new (GnmSortData, 1);
490
	data->sheet = state->sel->v_range.cell.a.sheet;
Jody Goldberg's avatar
Jody Goldberg committed
491
	data->range = g_new (GnmRange, 1);
492 493
	data->range = range_init (data->range, state->sel->v_range.cell.a.col
				  + ((state->header && !state->is_cols) ? 1 : 0),
494
				  state->sel->v_range.cell.a.row
495
				  + ((state->header && state->is_cols) ? 1 : 0),
496
				  state->sel->v_range.cell.b.col,
497 498 499 500
				  state->sel->v_range.cell.b.row);
	data->num_clause = state->sort_items;
	data->clauses = array;
	data->top = state->is_cols;
501 502
	data->retain_formats = gtk_toggle_button_get_active (
		GTK_TOGGLE_BUTTON (state->retain_format_check));
503
	data->locale = go_locale_sel_get_locale (state->locale_selector);
Morten Welinder's avatar
Morten Welinder committed
504

505 506 507
	data_copy = gnm_sort_data_copy (data);
	text = gnm_expr_entry_get_text (state->range_entry);
	gnm_sheet_add_sort_setup
Morten Welinder's avatar
Morten Welinder committed
508 509
		(data->sheet,
		 g_strdup((text != NULL && text[0] != '\0') ? text : "Other"),
510
		 data_copy);
Morten Welinder's avatar
Morten Welinder committed
511

512 513 514 515 516 517
	cmd_sort (WORKBOOK_CONTROL (state->wbcg), data);

	gtk_widget_destroy (state->dialog);
	return;
}

518
static void
Morten Welinder's avatar
Morten Welinder committed
519
cb_dialog_cancel_clicked (G_GNUC_UNUSED GtkWidget *button,
520
			  SortFlowState *state)
521 522 523 524
{
	gtk_widget_destroy (state->dialog);
}

525 526 527
static void
dialog_cell_sort_load_sort_setup (SortFlowState *state, GnmSortData const *data)
{
528 529 530 531
	int i;
	GnmSortClause *this = data->clauses;
	gint base, max, index;
	Sheet *sheet = state->sel->v_range.cell.a.sheet;
532

533 534
	if (sheet == NULL)
		sheet = state->sheet;
Morten Welinder's avatar
Morten Welinder committed
535

536
	go_locale_sel_set_locale (state->locale_selector, data->locale);
Morten Welinder's avatar
Morten Welinder committed
537

538 539
	gtk_toggle_button_set_active (
		GTK_TOGGLE_BUTTON (state->retain_format_check), data->retain_formats);
Morten Welinder's avatar
Morten Welinder committed
540

541 542 543
	gtk_toggle_button_set_active (
		GTK_TOGGLE_BUTTON (state->cell_sort_row_rb), !data->top);
	state->is_cols = data->top;
544

545 546 547 548 549
	index = (data->top ? state->sel->v_range.cell.a.row : state->sel->v_range.cell.a.col);
	base = (data->top ? state->sel->v_range.cell.a.col : state->sel->v_range.cell.a.row);
	max = (data->top ? state->sel->v_range.cell.b.col : state->sel->v_range.cell.b.row);
	gtk_list_store_clear (state->model);
	state->sort_items = 0;
Morten Welinder's avatar
Morten Welinder committed
550
	for (i = 0; i < data->num_clause; i++) {
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
		if (data->clauses[i].offset <= max ) {
			GtkTreeIter iter;
			gchar *str, *header;
			int id = data->clauses[i].offset + base;

			header = state->is_cols
				? header_name (sheet, id, index)
				: header_name (sheet, index, id);
			str = col_row_name (sheet, id, id, FALSE, state->is_cols);

			gtk_list_store_append (state->model, &iter);
			gtk_list_store_set (state->model, &iter,
					    ITEM_HEADER,  header,
					    ITEM_NAME,  str,
					    ITEM_DESCENDING, data->clauses[i].asc,
Morten Welinder's avatar
Morten Welinder committed
566
					    ITEM_DESCENDING_IMAGE,
567 568 569 570 571 572 573 574 575 576 577 578
					    !data->clauses[i].asc
					    ? state->image_ascending
					    : state->image_descending,
					    ITEM_CASE_SENSITIVE, data->clauses[i].cs,
					    ITEM_SORT_BY_VALUE, data->clauses[i].val,
					    ITEM_MOVE_FORMAT, TRUE,
					    ITEM_NUMBER, id,
					    -1);
			state->sort_items++;
		}
		this++;
	}
579
	set_button_sensitivity (state);
580 581
}

582 583
static GnmRange const *
dialog_load_selection (SortFlowState *state, gboolean *col_rb)
584
{
Jody Goldberg's avatar
Jody Goldberg committed
585
	GnmRange const *first;
586
	GnmSortData const *data;
587

Jody Goldberg's avatar
Jody Goldberg committed
588
	first = selection_first_range (state->sv, NULL, NULL);
589

590
	if (first != NULL) {
591 592
		gtk_toggle_button_set_active (
			GTK_TOGGLE_BUTTON (state->cell_sort_col_rb),
593
			(*col_rb = (first->end.row - first->start.row > first->end.col - first->start.col)));
594
		gnm_expr_entry_load_from_range (state->range_entry,
595
						state->sheet, first);
596
	} else
597 598
		gtk_toggle_button_set_active (
			GTK_TOGGLE_BUTTON (state->cell_sort_col_rb),
599
			(*col_rb = TRUE));
600 601

	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->cell_sort_header_check),
Morten Welinder's avatar
Morten Welinder committed
602
				      sheet_range_has_heading
603 604
				      (state->sheet, first, *col_rb, FALSE));
	cb_sort_header_check (state);
Morten Welinder's avatar
Morten Welinder committed
605

Morten Welinder's avatar
Morten Welinder committed
606
	data = gnm_sheet_find_sort_setup (state->sheet,
607 608 609
					  gnm_expr_entry_get_text (state->range_entry));
	if (data != NULL)
		dialog_cell_sort_load_sort_setup (state, data);
610 611
	else
		cb_update_to_new_range (state);
Morten Welinder's avatar
Morten Welinder committed
612

613
	return first;
614 615
}

616 617
/**
 * Refreshes the buttons on a row (un)selection
618
 *
619 620
 */
static void
621
cb_sort_selection_changed (SortFlowState *state)
622
{
623
	GtkTreeIter iter, test;
624

625 626 627
	if (!gtk_tree_selection_get_selected (state->selection, NULL, &iter)) {
		gtk_widget_set_sensitive (state->up_button, FALSE);
		gtk_widget_set_sensitive (state->down_button, FALSE);
628
		gtk_widget_set_sensitive (state->delete_button, FALSE);
629 630 631
		return;
	}

632 633 634 635 636 637 638 639 640 641 642
	test = iter;
	gtk_widget_set_sensitive
		(state->up_button,
		 gnm_tree_model_iter_prev (GTK_TREE_MODEL (state->model),
					   &test));

	test = iter;
	gtk_widget_set_sensitive
		(state->down_button,
		 gtk_tree_model_iter_next (GTK_TREE_MODEL (state->model),
					   &test));
643

644
	gtk_widget_set_sensitive (state->delete_button, TRUE);
645
	set_button_sensitivity (state);
646 647 648
}

static void
649
toggled (SortFlowState *state, const gchar *path_string, int column)
650
{
651 652 653 654
	GtkTreeModel *model = GTK_TREE_MODEL (state->model);
	GtkTreeIter iter;
	GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
	gboolean value;
655

656 657 658
	if (gtk_tree_model_get_iter (model, &iter, path)) {
		gtk_tree_model_get (model, &iter, column, &value, -1);
		value = !value;
659
		gtk_list_store_set (GTK_LIST_STORE (model),
660 661 662 663
				    &iter, column, value, -1);
	} else {
		g_warning ("Did not get a valid iterator");
	}
664

665
	gtk_tree_path_free (path);
666 667 668
}

static void
669 670
move_cb (SortFlowState *state,
	 gboolean (*mover) (GtkTreeModel *, GtkTreeIter *))
671
{
672
	GtkTreeIter iter, this_iter;
673

674 675
	if (!gtk_tree_selection_get_selected (state->selection, NULL,
					      &this_iter))
676
		return;
677

678 679 680
	iter = this_iter;
	if (!mover (GTK_TREE_MODEL(state->model), &iter))
		return;
681 682 683

	gtk_list_store_swap (state->model, &this_iter, &iter);
	cb_sort_selection_changed (state);
684 685
}

686
static void
687
cb_up (SortFlowState *state)
688
{
689
	move_cb (state, gnm_tree_model_iter_prev);
690 691 692
}

static void
693
cb_down (SortFlowState *state)
694
{
695
	move_cb (state, gtk_tree_model_iter_next);
696
}
697

698
static void
Morten Welinder's avatar
Morten Welinder committed
699
cb_delete_clicked (G_GNUC_UNUSED GtkWidget *w, SortFlowState *state)
700
{
701 702 703
	GtkTreeIter iter, iter2;
	gboolean ok;

704 705
	if (!gtk_tree_selection_get_selected (state->selection, NULL, &iter))
		return;
706 707 708 709 710 711

	iter2 = iter;
	ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (state->model), &iter2);
	if (!ok) {
		iter2 = iter;
		ok = gnm_tree_model_iter_prev (GTK_TREE_MODEL (state->model), &iter2);
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
712
	}
713 714 715 716 717 718

	if (ok)
		gtk_tree_selection_select_iter (state->selection, &iter2);

	gtk_list_store_remove (state->model, &iter);
	state->sort_items--;
719
	set_button_sensitivity (state);
720
}
721

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
722

723
static void
724
cb_clear_clicked (SortFlowState *state)
725 726 727
{
	state->sort_items = 0;
	gtk_list_store_clear (state->model);
728
	set_button_sensitivity (state);
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
729 730 731 732 733 734 735 736 737 738
}

static GtkMenu *
build_sort_field_base_menu (SortFlowState *state)
{
	gint start;
	gint end;
	gint index;

	GtkWidget *menu = gtk_menu_new ();
739 740 741
	GList* items = NULL;

	if (state->sel != NULL) {
742 743 744 745 746 747 748 749 750 751 752 753 754 755
		if (state->is_cols) {
			start = state->sel->v_range.cell.a.col;
			end = state->sel->v_range.cell.b.col;
			index = state->sel->v_range.cell.a.row;
		} else {
			start = state->sel->v_range.cell.a.row;
			end = state->sel->v_range.cell.b.row;
			index = state->sel->v_range.cell.a.col;
		}

		build_sort_field_menu (start, end, index, menu, state,
				       state->sort_items);

		items = gtk_container_get_children (GTK_CONTAINER (menu));
756
	}
757

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
758 759
	if (items == NULL) {
		GtkWidget *item;
760 761
		item = (GtkWidget *) gtk_menu_item_new_with_label(state->is_cols ?
								  _("no available row"): _("no available column"));
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
762 763 764 765 766 767
		gtk_widget_set_sensitive( GTK_WIDGET (item), FALSE);
		gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
		gtk_widget_show (item);
	}

	g_list_free (items);
768

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
769 770 771 772 773 774
	return GTK_MENU (menu);
}

static void
show_add_menu (SortFlowState *state)
{
775 776
	gnumeric_popup_menu (build_sort_field_base_menu(state),
			     NULL);
777 778
}

779
static void
780
cb_add_clicked (SortFlowState *state)
781
{
Jody Goldberg's avatar
Jody Goldberg committed
782
        GnmValue *range_add;
783
	GnmSheetRange grange_sort, grange_add;
Jody Goldberg's avatar
Jody Goldberg committed
784
	GnmRange intersection;
785 786 787 788
	int start;
	int end;
	int index;
	int i;
789
	gboolean had_items = (state->sort_items > 0);
790 791

        range_add = gnm_expr_entry_parse_as_value
792
		(GNM_EXPR_ENTRY (state->add_entry), state->sheet);
793

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
794 795 796 797 798
	if (range_add == NULL) {
		show_add_menu (state);
		return;
	}

799
	g_return_if_fail (range_add != NULL && state->sel != NULL);
Morten Welinder's avatar
Morten Welinder committed
800

801 802
	gnm_sheet_range_from_value (&grange_sort, state->sel);
	gnm_sheet_range_from_value (&grange_add, range_add);
803

804 805
	value_release (range_add);

806
	if (range_intersection (&intersection, &grange_sort.range, &grange_add.range)) {
807 808 809

		if (state->is_cols) {
			start = intersection.start.col;
810
			end = intersection.end.col;
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
811
			index = state->sel->v_range.cell.a.row;
812 813
		} else {
			start = intersection.start.row;
814
			end = intersection.end.row;
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
815
			index = state->sel->v_range.cell.a.col;
816
		}
Morten Welinder's avatar
Morten Welinder committed
817

818
		for (i = start; i <= end; i++) {
Morten Welinder's avatar
Morten Welinder committed
819

820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835
			int item = 0;
			GtkTreeIter iter;
			gboolean found = FALSE;
			gint number;

			while (gtk_tree_model_iter_nth_child  (GTK_TREE_MODEL (state->model),
							       &iter, NULL, item)) {
				gtk_tree_model_get (GTK_TREE_MODEL (state->model), &iter,
						    ITEM_NUMBER, &number,
						    -1);
				item++;
				if (number == i) {
					found = TRUE;
					break;
				}
			}
Morten Welinder's avatar
Morten Welinder committed
836

837 838 839
			if (!found) {
				append_data (state, i, index);
			}
Morten Welinder's avatar
Morten Welinder committed
840
		}
841
		if (!had_items && (state->sort_items > 0))
842
			set_button_sensitivity(state);
843
	} else
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
844 845 846 847 848 849 850 851 852
		show_add_menu (state);
	gnm_expr_entry_load_from_text (GNM_EXPR_ENTRY (state->add_entry), "");
}

static gint
cb_treeview_button_press(GtkWidget *w, GdkEvent *event, SortFlowState *state)
{
	if ((event->type == GDK_BUTTON_PRESS) &&
	    (event->button.button == 3)) {
853
		gnumeric_popup_menu (build_sort_field_base_menu(state),
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
854 855 856
				     &(event->button));
		return TRUE;
	}
857

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
858 859 860 861 862 863 864 865 866
	return FALSE;
}

static gint
cb_treeview_keypress (G_GNUC_UNUSED GtkWidget *w, GdkEventKey *event,
		      SortFlowState *state)
{
	gboolean ctrl = (event->state & GDK_CONTROL_MASK);
	GtkTreeIter iter;
867

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
868 869 870
	switch (event->keyval) {
	case GDK_Delete:
	case GDK_KP_Delete:
871
		cb_delete_clicked (w, state);
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
872
		return TRUE;
873 874 875 876 877
	case GDK_KP_Up:
	case GDK_Up:
		if (ctrl) {
			cb_up (state);
			return TRUE;
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
878
		}
879 880 881 882 883

		if (gtk_tree_selection_get_selected (state->selection, NULL, &iter) &&
		    gnm_tree_model_iter_prev (GTK_TREE_MODEL (state->model), &iter))
			gtk_tree_selection_select_iter (state->selection,
							&iter);
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
884 885
		return TRUE;

886 887 888 889 890
	case GDK_KP_Down:
	case GDK_Down:
		if (ctrl) {
			cb_down (state);
			return TRUE;
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
891
		}
892 893 894 895 896

		if (gtk_tree_selection_get_selected (state->selection, NULL, &iter) &&
		    gtk_tree_model_iter_next (GTK_TREE_MODEL (state->model), &iter))
			gtk_tree_selection_select_iter (state->selection,
							&iter);
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
897
		return TRUE;
898
	}
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
899
	return FALSE;
900 901
}

902
static void
Morten Welinder's avatar
Morten Welinder committed
903
cb_toggled_descending (G_GNUC_UNUSED GtkCellRendererToggle *cell,
904 905
		       const gchar *path_string,
		       SortFlowState *state)
906
{
907 908 909 910
	GtkTreeModel *model = GTK_TREE_MODEL (state->model);
	GtkTreeIter iter;
	GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
	gboolean value;
911

912 913 914
	if (gtk_tree_model_get_iter (model, &iter, path)) {
		gtk_tree_model_get (model, &iter, ITEM_DESCENDING, &value, -1);
		if (value) {
915
			gtk_list_store_set (GTK_LIST_STORE (model), &iter,
916
					    ITEM_DESCENDING, FALSE,
917
					    ITEM_DESCENDING_IMAGE, state->image_ascending,
918 919
					    -1);
		} else {
920
			gtk_list_store_set (GTK_LIST_STORE (model), &iter,
921
					    ITEM_DESCENDING, TRUE,
922
					    ITEM_DESCENDING_IMAGE, state->image_descending,
923 924
					    -1);
		}
925
	} else {
926
		g_warning ("Did not get a valid iterator");
927
	}
928
	gtk_tree_path_free (path);
929 930
}

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
931 932
#if 0
/* We are currently not supporting `by-value' vs not. */
933 934
static void
cb_toggled_sort_by_value (GtkCellRendererToggle *cell,
935 936
			  const gchar *path_string,
			  SortFlowState *state)
937
{
938
	toggled (state, path_string, ITEM_SORT_BY_VALUE);
939
}
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
940
#endif
941 942 943

static void
cb_toggled_case_sensitive (GtkCellRendererToggle *cell,
944 945
			   const gchar           *path_string,
			   SortFlowState *state)
946
{
947
	toggled (state, path_string, ITEM_CASE_SENSITIVE);
948 949
}

Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
950

951
static void
952 953 954 955 956
dialog_init (SortFlowState *state)
{
	GtkTable *table;
	GtkWidget *scrolled;
	GtkTreeViewColumn *column;
957
	GtkCellRenderer *renderer;
958 959
	gboolean col_rb;
	GnmRange const *range;
960

Morten Welinder's avatar
Morten Welinder committed
961
	table = GTK_TABLE (go_gtk_builder_get_widget (state->gui, "cell_sort_options_table"));
962
	/* setup range entry */
963
	state->range_entry = gnm_expr_entry_new (state->wbcg, TRUE);
964
	gnm_expr_entry_set_flags (state->range_entry,
965 966
				  GNM_EE_SINGLE_RANGE,
				  GNM_EE_MASK);
967
	gtk_table_attach (table, GTK_WIDGET (state->range_entry),
Jody Goldberg's avatar
Jody Goldberg committed
968
			  2, 3, 1, 2,
969 970
			  GTK_EXPAND | GTK_FILL, 0,
			  0, 0);
971
	gnumeric_editable_enters (GTK_WINDOW (state->dialog),
972
				  GTK_WIDGET (state->range_entry));
973
	gnm_expr_entry_set_update_policy (state->range_entry, GTK_UPDATE_DISCONTINUOUS);
974
	gtk_widget_show (GTK_WIDGET (state->range_entry));
975
	g_signal_connect_swapped (G_OBJECT (state->range_entry),
976
				  "changed",
977
				  G_CALLBACK (cb_update_to_new_range), state);
978

979 980 981 982 983 984
	state->locale_selector = GO_LOCALE_SEL (go_locale_sel_new ());
	gtk_widget_show_all (GTK_WIDGET (state->locale_selector));
	gtk_table_attach (table, GTK_WIDGET (state->locale_selector),
			  2, 3, 5, 6,
			  GTK_EXPAND | GTK_FILL, 0,
			  0, 0);
985

Morten Welinder's avatar
Morten Welinder committed
986
	table = GTK_TABLE (go_gtk_builder_get_widget (state->gui, "cell_sort_spec_table"));
987
	/* setup add entry */
988
	state->add_entry = gnm_expr_entry_new (state->wbcg, TRUE);
989
	gnm_expr_entry_set_flags (state->add_entry,
990 991
				  GNM_EE_SINGLE_RANGE,
				  GNM_EE_MASK);
992
	gtk_table_attach (table, GTK_WIDGET (state->add_entry),
993
			  1, 2, 2, 3,
994 995
			  GTK_EXPAND | GTK_FILL, 0,
			  0, 0);
996
	gnumeric_editable_enters (GTK_WINDOW (state->dialog),
997 998 999
				  GTK_WIDGET (state->add_entry));
	gtk_widget_show (GTK_WIDGET (state->add_entry));

1000
	/* Set-up tree view */
Morten Welinder's avatar
Morten Welinder committed
1001
	scrolled = go_gtk_builder_get_widget (state->gui, "scrolled_cell_sort_list");
1002 1003
	state->model = gtk_list_store_new (NUM_COLMNS, G_TYPE_STRING,
					   G_TYPE_STRING, G_TYPE_BOOLEAN,
1004
					   GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN,
1005
					   G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
1006
					   G_TYPE_INT);
1007 1008 1009 1010
	state->treeview = GTK_TREE_VIEW (
		gtk_tree_view_new_with_model (GTK_TREE_MODEL (state->model)));
	state->selection = gtk_tree_view_get_selection (state->treeview);
	gtk_tree_selection_set_mode (state->selection, GTK_SELECTION_BROWSE);
1011
	g_signal_connect_swapped (state->selection,
1012 1013
				  "changed",
				  G_CALLBACK (cb_sort_selection_changed), state);
1014

1015
	state->header_column = gtk_tree_view_column_new_with_attributes (_("Header"),
1016 1017
									 gtk_cell_renderer_text_new (),
									 "text", ITEM_HEADER, NULL);
1018 1019
	gtk_tree_view_append_column (state->treeview, state->header_column);

1020
	column = gtk_tree_view_column_new_with_attributes (_("Row/Column"),
1021 1022 1023 1024
							   gtk_cell_renderer_text_new (),
							   "text", ITEM_NAME, NULL);
	gtk_tree_view_append_column (state->treeview, column);

1025
	renderer = gnumeric_cell_renderer_toggle_new ();
1026
	g_signal_connect (G_OBJECT (renderer),
1027 1028
			  "toggled",
			  G_CALLBACK (cb_toggled_descending), state);
1029
	column = gtk_tree_view_column_new_with_attributes ("",
1030
							   renderer,
Morten Welinder's avatar
Morten Welinder committed
1031
							   "active", ITEM_DESCENDING,
1032 1033
							   "pixbuf", ITEM_DESCENDING_IMAGE,
							   NULL);
1034 1035
	gtk_tree_view_append_column (state->treeview, column);

1036
	renderer = gtk_cell_renderer_toggle_new ();
1037
	g_signal_connect (G_OBJECT (renderer),
1038 1039
			  "toggled",
			  G_CALLBACK (cb_toggled_case_sensitive), state);
1040
	column = gtk_tree_view_column_new_with_attributes (_("Case Sensitive"),
1041 1042 1043 1044
							   renderer,
							   "active", ITEM_CASE_SENSITIVE, NULL);
	gtk_tree_view_append_column (state->treeview, column);

Jody Goldberg's avatar
Jody Goldberg committed
1045
	gtk_tree_view_columns_autosize (state->treeview);
1046 1047


Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
1048
	g_signal_connect (G_OBJECT (state->treeview),
1049 1050
			  "key_press_event",
			  G_CALLBACK (cb_treeview_keypress), state);
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
1051
	g_signal_connect (G_OBJECT (state->treeview),
1052 1053
			  "button_press_event",
			  G_CALLBACK (cb_treeview_button_press), state);
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
1054 1055
#if 0
	/* We are currently not supporting `by-value' vs not. */
1056
	renderer = gtk_cell_renderer_toggle_new ();
1057
	g_signal_connect (G_OBJECT (renderer),
1058 1059
			  "toggled",
			  G_CALLBACK (cb_toggled_sort_by_value), state);
1060
	column = gtk_tree_view_column_new_with_attributes (_("By Value"),
1061 1062 1063
							   renderer,
							   "active", ITEM_SORT_BY_VALUE, NULL);
	gtk_tree_view_append_column (state->treeview, column);
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
1064
#endif
1065

1066 1067
	gtk_tree_view_set_reorderable (state->treeview,TRUE);

1068 1069 1070
	gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (state->treeview));
	gtk_widget_show (GTK_WIDGET (state->treeview));

1071
	/* Set-up other widgets */
Morten Welinder's avatar
Morten Welinder committed
1072 1073
	state->cell_sort_row_rb = go_gtk_builder_get_widget (state->gui, "cell_sort_row_rb");
	state->cell_sort_col_rb = go_gtk_builder_get_widget (state->gui, "cell_sort_col_rb");
1074
	g_signal_connect_swapped (G_OBJECT (state->cell_sort_row_rb),
1075
				  "toggled",
1076
				  G_CALLBACK (cb_update_to_new_range), state);
1077

Morten Welinder's avatar
Morten Welinder committed
1078
	state->cell_sort_header_check = go_gtk_builder_get_widget (state->gui,
1079
							      "cell_sort_header_check");
1080
	g_signal_connect_swapped (G_OBJECT (state->cell_sort_header_check),
1081 1082
				  "toggled",
				  G_CALLBACK (cb_sort_header_check), state);
1083

Morten Welinder's avatar
Morten Welinder committed
1084
	state->retain_format_check = go_gtk_builder_get_widget (state->gui,
1085
							   "retain_format_button");
1086
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->retain_format_check),
1087
				      gnm_conf_get_core_sort_default_retain_formats ());
1088 1089


1090
	/* Set-up buttons */
Morten Welinder's avatar
Morten Welinder committed
1091
	state->up_button = go_gtk_builder_get_widget (state->gui, "up_button");
1092 1093 1094
	g_signal_connect_swapped (G_OBJECT (state->up_button),
				  "clicked",
				  G_CALLBACK (cb_up), state);
Morten Welinder's avatar
Morten Welinder committed
1095
	state->down_button = go_gtk_builder_get_widget (state->gui, "down_button");
1096 1097 1098
	g_signal_connect_swapped (G_OBJECT (state->down_button),
				  "clicked",
				  G_CALLBACK (cb_down), state);
Morten Welinder's avatar
Morten Welinder committed
1099
	state->add_button = go_gtk_builder_get_widget (state->gui, "add_button");
1100 1101 1102
	g_signal_connect_swapped (G_OBJECT (state->add_button),
				  "clicked",
				  G_CALLBACK (cb_add_clicked), state);
Andreas J. Guelzow's avatar
Andreas J. Guelzow committed
1103
	gtk_widget_set_sensitive (state->add_button, TRUE);
Morten Welinder's avatar
Morten Welinder committed
1104
	state->delete_button = go_gtk_builder_get_widget (state->gui, "delete_button");
Jody Goldberg's avatar
Jody Goldberg committed
1105
	g_signal_connect (G_OBJECT (state->delete_button),
1106 1107
			  "clicked",
			  G_CALLBACK (cb_delete_clicked), state);
1108 1109
	gtk_widget_set_sensitive (state->delete_button, FALSE);

Morten Welinder's avatar
Morten Welinder committed
1110
	state->clear_button = go_gtk_builder_get_widget (state->gui, "clear_button");
1111 1112 1113
	g_signal_connect_swapped (G_OBJECT (state->clear_button),
				  "clicked",
				  G_CALLBACK (cb_clear_clicked), state);
1114 1115
	gtk_widget_set_sensitive (state->clear_button, FALSE);

1116 1117 1118 1119 1120
	gtk_button_set_alignment (GTK_BUTTON (state->up_button), 0., .5);
	gtk_button_set_alignment (GTK_BUTTON (state->down_button), 0., .5);
	gtk_button_set_alignment (GTK_BUTTON (state->add_button), 0., .5);
	gtk_button_set_alignment (GTK_BUTTON (state->delete_button), 0., .5);
	gtk_button_set_alignment (GTK_BUTTON (state->clear_button), 0., .5);
1121
	gnumeric_init_help_button (
Morten Welinder's avatar
Morten Welinder committed
1122
		go_gtk_builder_get_widget (state->gui, "help_button"),
1123
		GNUMERIC_HELP_LINK_CELL_SORT);
1124

Morten Welinder's avatar
Morten Welinder committed
1125
	state->ok_button = go_gtk_builder_get_widget (state->gui, "ok_button");
1126 1127 1128
	g_signal_connect_swapped (G_OBJECT (state->ok_button),
				  "clicked",
				  G_CALLBACK (cb_dialog_ok_clicked), state);
Morten Welinder's avatar
Morten Welinder committed
1129
	state->cancel_button = go_gtk_builder_get_widget (state->gui, "cancel_button");
1130
	g_signal_connect (G_OBJECT (state->cancel_button),
1131 1132
			  "clicked",
			  G_CALLBACK (cb_dialog_cancel_clicked), state);
1133

Morten Welinder's avatar
Morten Welinder committed
1134
	gnm_dialog_setup_destroy_handlers (GTK_DIALOG (state->dialog),