2 * dialog-cell-format-cond.c: Implements a dialog to format cells.
4 * (c) Copyright 2010-2011 Andreas J. Guelzow <aguelzow@pyrshep.ca>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <https://www.gnu.org/licenses/>.
20 #include <gnumeric-config.h>
21 #include <glib/gi18n-lib.h>
23 #include <dialogs/dialogs.h>
24 #include <dialogs/help.h>
27 #include <sheet-view.h>
28 #include <sheet-merge.h>
29 #include <sheet-style.h>
31 #include <selection.h>
38 #include <application.h>
39 #include <validation.h>
44 #include <style-conditions.h>
49 #define CELL_FORMAT_KEY "cell-format-cond-dialog"
50 #define CELL_FORMAT_DEF_KEY "cell-format-cond-def-dialog"
52 typedef struct _CFormatState
{
56 GtkWidget
*close_button
;
60 unsigned int conflicts
;
68 GtkTreeView
*treeview
;
70 GtkTreeSelection
*selection
;
78 gboolean existing_conds_only
;
81 GtkWidget
*edit_style_button
;
82 GtkWidget
*add_button
;
83 GtkWidget
*replace_button
;
84 GtkWidget
*copy_button
;
88 GtkListStore
*typestore
;
90 GtkWidget
*style_label
;
99 CONDITIONS_NUM_COLUMNS
104 /*****************************************************************************/
105 static void c_fmt_dialog_load (CFormatState
*state
);
106 static void c_fmt_dialog_apply_add_choice (CFormatState
*state
, GnmStyleCond
*cond
, gboolean add
);
108 /*****************************************************************************/
110 /* button handlers */
112 cb_c_fmt_dialog_dialog_buttons (G_GNUC_UNUSED GtkWidget
*btn
, CFormatState
*state
)
114 /* users may accidentally click on 'close' before adding the formatting style see #733352 */
115 if (!gtk_widget_get_sensitive (GTK_WIDGET (state
->editor
.add_button
)) ||
116 gtk_widget_get_sensitive (GTK_WIDGET (state
->clear
)) ||
117 go_gtk_query_yes_no (GTK_WINDOW (state
->dialog
), FALSE
,
118 _("You did not add the defined conditional format."
119 " Do you really want to close the conditional formatting dialog?")))
120 gtk_widget_destroy (GTK_WIDGET (state
->dialog
));
123 /* Handler for destroy */
125 cb_c_fmt_dialog_dialog_destroy (CFormatState
*state
)
127 if (state
->editor
.dialog
) {
128 gtk_widget_destroy (GTK_WIDGET (state
->editor
.dialog
));
129 state
->editor
.dialog
= NULL
;
131 if (state
->editor
.style
)
132 gnm_style_unref (state
->editor
.style
);
134 gnm_style_unref (state
->style
);
135 g_object_unref (state
->gui
);
140 cb_dialog_destroy (GtkDialog
*dialog
)
142 g_object_set_data (G_OBJECT (dialog
), "state", NULL
);
145 /*****************************************************************************/
148 c_fmt_dialog_set_sensitive (CFormatState
*state
)
150 gboolean ok
= (state
->editor
.style
!= NULL
&& state
->homogeneous
);
153 gboolean not_empty
, selected
;
155 not_empty
= gtk_tree_model_get_iter_first
156 (GTK_TREE_MODEL (state
->model
), &iter
);
157 selected
= gtk_tree_selection_get_selected
158 (state
->selection
, NULL
, NULL
);
160 gtk_widget_set_sensitive (GTK_WIDGET (state
->clear
), not_empty
);
162 gtk_widget_set_sensitive (GTK_WIDGET (state
->remove
),
163 state
->homogeneous
&& selected
);
164 gtk_widget_set_sensitive (GTK_WIDGET (state
->expand
),
165 (!state
->homogeneous
) && selected
);
167 parse_pos_init_editpos (&pp
, state
->sv
);
169 if (ok
&& gtk_widget_get_sensitive (state
->editor
.expr_x
)) {
170 GnmExprTop
const *texpr
= gnm_expr_entry_parse (GNM_EXPR_ENTRY (state
->editor
.expr_x
), &pp
,
172 GNM_EXPR_PARSE_UNKNOWN_NAMES_ARE_STRINGS
);
173 ok
= (texpr
!= NULL
);
175 gnm_expr_top_unref (texpr
);
177 if (ok
&& gtk_widget_get_sensitive (state
->editor
.expr_y
)) {
178 GnmExprTop
const *texpr
= gnm_expr_entry_parse (GNM_EXPR_ENTRY (state
->editor
.expr_y
), &pp
,
180 GNM_EXPR_PARSE_UNKNOWN_NAMES_ARE_STRINGS
);
181 ok
= (texpr
!= NULL
);
183 gnm_expr_top_unref (texpr
);
186 gtk_widget_set_sensitive (state
->editor
.add_button
, ok
);
187 gtk_widget_set_sensitive (state
->editor
.replace_button
, ok
&& selected
);
188 gtk_widget_set_sensitive (state
->editor
.copy_button
, selected
&& state
->homogeneous
);
192 c_fmt_dialog_set_expr_sensitive (CFormatState
*state
)
197 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (state
->editor
.combo
), &iter
))
198 gtk_tree_model_get (GTK_TREE_MODEL (state
->editor
.typestore
),
203 gtk_widget_set_sensitive (state
->editor
.expr_x
, FALSE
);
204 gtk_entry_set_text (gnm_expr_entry_get_entry (GNM_EXPR_ENTRY (state
->editor
.expr_x
)), "");
206 gtk_widget_set_sensitive (state
->editor
.expr_x
, TRUE
);
208 gtk_widget_set_sensitive (state
->editor
.expr_y
, FALSE
);
209 gtk_entry_set_text (gnm_expr_entry_get_entry (GNM_EXPR_ENTRY (state
->editor
.expr_y
)), "");
211 gtk_widget_set_sensitive (state
->editor
.expr_y
, TRUE
);
215 cb_c_fmt_dialog_chooser_type_changed (G_GNUC_UNUSED GtkComboBox
*widget
, CFormatState
*state
)
217 c_fmt_dialog_set_expr_sensitive (state
);
218 c_fmt_dialog_set_sensitive (state
);
222 cb_c_fmt_dialog_chooser_entry_changed (G_GNUC_UNUSED GnmExprEntry
*widget
, G_GNUC_UNUSED GdkEvent
*event
,
225 c_fmt_dialog_set_sensitive (state
);
230 dialog_cell_format_style_added (gpointer closure
, GnmStyle
*style
)
232 CFormatState
*state
= closure
;
234 if (state
->editor
.style
)
235 gnm_style_unref (state
->editor
.style
);
236 state
->editor
.style
= style
;
237 gtk_label_set_text (GTK_LABEL (state
->editor
.style_label
),
238 style
? _("(defined)") : _("(undefined)"));
239 c_fmt_dialog_set_sensitive (state
);
243 c_fmt_dialog_set_component (CFormatState
*state
, GnmStyle
*overlay
, gchar
const *name
,
244 GnmStyleElement elem
, gboolean uncheck
)
246 GtkWidget
*w
= go_gtk_builder_get_widget (state
->gui
, name
);
248 if (gnm_style_is_element_set (overlay
, elem
))
249 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w
), TRUE
);
251 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w
), FALSE
);
256 cb_c_fmt_dialog_chooser_check_page (CFormatState
*state
, gchar
const *name
,
259 GtkWidget
*w
= go_gtk_builder_get_widget (state
->gui
, name
);
261 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w
)))
268 editor_destroy_cb (G_GNUC_UNUSED GObject
*obj
, CFormatState
*state
)
270 state
->editor
.dialog
= NULL
;
274 c_fmt_dialog_select_style (CFormatState
*state
, int pages
)
276 if (state
->editor
.dialog
)
277 gtk_widget_destroy (GTK_WIDGET (state
->editor
.dialog
));
278 state
->editor
.dialog
= dialog_cell_format_select_style
280 GTK_WINDOW (state
->dialog
),
281 state
->editor
.style
, state
);
282 if (state
->editor
.dialog
)
284 (G_OBJECT (state
->editor
.dialog
),
285 "destroy", G_CALLBACK (editor_destroy_cb
), state
);
289 cb_c_fmt_dialog_edit_style_button (G_GNUC_UNUSED GtkWidget
*btn
, CFormatState
*state
)
292 pages
|= cb_c_fmt_dialog_chooser_check_page
293 (state
, "check-background", FD_BACKGROUND
);
294 pages
|= cb_c_fmt_dialog_chooser_check_page
295 (state
, "check-number", FD_NUMBER
);
296 pages
|= cb_c_fmt_dialog_chooser_check_page
297 (state
, "check-align", FD_ALIGNMENT
);
298 pages
|= cb_c_fmt_dialog_chooser_check_page
299 (state
, "check-font", FD_FONT
);
300 pages
|= cb_c_fmt_dialog_chooser_check_page
301 (state
, "check-border", FD_BORDER
);
302 pages
|= cb_c_fmt_dialog_chooser_check_page
303 (state
, "check-protection", FD_PROTECTION
);
304 pages
|= cb_c_fmt_dialog_chooser_check_page
305 (state
, "check-validation", FD_VALIDATION
);
307 if (state
->editor
.style
!= NULL
)
308 gnm_style_ref (state
->editor
.style
);
309 c_fmt_dialog_select_style (state
, pages
);
312 static GnmStyleCond
*
313 c_fmt_dialog_get_condition (CFormatState
*state
)
322 parse_pos_init_editpos (&pp
, state
->sv
);
324 overlay
= gnm_style_new ();
325 if (state
->editor
.style
) {
326 if (cb_c_fmt_dialog_chooser_check_page
327 (state
, "check-background", FD_BACKGROUND
)) {
328 gnm_style_merge_element (overlay
, state
->editor
.style
,
330 gnm_style_merge_element (overlay
, state
->editor
.style
,
331 MSTYLE_COLOR_PATTERN
);
332 gnm_style_merge_element (overlay
, state
->editor
.style
,
335 if (cb_c_fmt_dialog_chooser_check_page
336 (state
, "check-number", FD_NUMBER
)) {
337 gnm_style_merge_element (overlay
, state
->editor
.style
,
340 if (cb_c_fmt_dialog_chooser_check_page
341 (state
, "check-align", FD_ALIGNMENT
)) {
342 gnm_style_merge_element (overlay
, state
->editor
.style
,
344 gnm_style_merge_element (overlay
, state
->editor
.style
,
346 gnm_style_merge_element (overlay
, state
->editor
.style
,
348 gnm_style_merge_element (overlay
, state
->editor
.style
,
350 gnm_style_merge_element (overlay
, state
->editor
.style
,
352 gnm_style_merge_element (overlay
, state
->editor
.style
,
354 gnm_style_merge_element (overlay
, state
->editor
.style
,
355 MSTYLE_SHRINK_TO_FIT
);
357 if (cb_c_fmt_dialog_chooser_check_page
358 (state
, "check-font", FD_FONT
)) {
359 gnm_style_merge_element (overlay
, state
->editor
.style
,
361 gnm_style_merge_element (overlay
, state
->editor
.style
,
363 gnm_style_merge_element (overlay
, state
->editor
.style
,
365 gnm_style_merge_element (overlay
, state
->editor
.style
,
367 gnm_style_merge_element (overlay
, state
->editor
.style
,
368 MSTYLE_FONT_UNDERLINE
);
369 gnm_style_merge_element (overlay
, state
->editor
.style
,
370 MSTYLE_FONT_STRIKETHROUGH
);
371 gnm_style_merge_element (overlay
, state
->editor
.style
,
373 gnm_style_merge_element (overlay
, state
->editor
.style
,
376 if (cb_c_fmt_dialog_chooser_check_page
377 (state
, "check-border", FD_BORDER
)) {
378 gnm_style_merge_element (overlay
, state
->editor
.style
,
380 gnm_style_merge_element (overlay
, state
->editor
.style
,
381 MSTYLE_BORDER_BOTTOM
);
382 gnm_style_merge_element (overlay
, state
->editor
.style
,
384 gnm_style_merge_element (overlay
, state
->editor
.style
,
385 MSTYLE_BORDER_RIGHT
);
386 gnm_style_merge_element (overlay
, state
->editor
.style
,
387 MSTYLE_BORDER_REV_DIAGONAL
);
388 gnm_style_merge_element (overlay
, state
->editor
.style
,
389 MSTYLE_BORDER_DIAGONAL
);
391 if (cb_c_fmt_dialog_chooser_check_page
392 (state
, "check-protection", FD_PROTECTION
)) {
395 if (cb_c_fmt_dialog_chooser_check_page
396 (state
, "check-validation", FD_VALIDATION
)) {
400 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (state
->editor
.combo
), &iter
))
401 gtk_tree_model_get (GTK_TREE_MODEL (state
->editor
.typestore
),
407 op
= GNM_STYLE_COND_CONTAINS_ERR
;
409 cond
= gnm_style_cond_new (op
, state
->sheet
);
410 gnm_style_cond_set_overlay (cond
, overlay
);
411 gnm_style_unref (overlay
);
414 GnmExprTop
const *texpr
= gnm_expr_entry_parse (GNM_EXPR_ENTRY (state
->editor
.expr_x
), &pp
,
416 GNM_EXPR_PARSE_UNKNOWN_NAMES_ARE_STRINGS
);
417 gnm_style_cond_set_expr (cond
, texpr
, 0);
418 gnm_expr_top_unref (texpr
);
421 GnmExprTop
const *texpr
= gnm_expr_entry_parse (GNM_EXPR_ENTRY (state
->editor
.expr_y
), &pp
,
423 GNM_EXPR_PARSE_UNKNOWN_NAMES_ARE_STRINGS
);
424 gnm_style_cond_set_expr (cond
, texpr
, 1);
425 gnm_expr_top_unref (texpr
);
431 cb_c_fmt_dialog_add_button (G_GNUC_UNUSED GtkWidget
*btn
, CFormatState
*state
)
433 GnmStyleCond
*cond
= c_fmt_dialog_get_condition (state
);
434 c_fmt_dialog_apply_add_choice (state
, cond
, TRUE
);
435 gnm_style_cond_free (cond
);
439 cb_c_fmt_dialog_replace_button (G_GNUC_UNUSED GtkWidget
*btn
, CFormatState
*state
)
441 GnmStyleCond
*cond
= c_fmt_dialog_get_condition (state
);
442 c_fmt_dialog_apply_add_choice (state
, cond
, FALSE
);
443 gnm_style_cond_free (cond
);
447 cb_c_fmt_dialog_copy_button (G_GNUC_UNUSED GtkWidget
*btn
, CFormatState
*state
)
449 GnmStyleConditions
*sc
;
451 sc
= gnm_style_get_conditions (state
->style
);
452 if (sc
!= NULL
&& gtk_tree_selection_get_selected (state
->selection
, NULL
, &iter
)) {
453 GtkTreePath
*path
= gtk_tree_model_get_path
454 (GTK_TREE_MODEL (state
->model
), &iter
);
455 gint
*pind
= gtk_tree_path_get_indices (path
);
456 GPtrArray
const *conds
= gnm_style_conditions_details (sc
);
459 GnmStyleCond
*gsc
= g_ptr_array_index (conds
, ind
);
463 GnmStyleConditions
*conds
;
465 /* Set the condition op */
466 if (gtk_tree_model_get_iter_first
467 (GTK_TREE_MODEL (state
->editor
.typestore
), &iter
)) {
470 gtk_tree_model_get (GTK_TREE_MODEL (state
->editor
.typestore
),
475 gtk_combo_box_set_active_iter
476 (GTK_COMBO_BOX (state
->editor
.combo
), &iter
);
479 } while (gtk_tree_model_iter_next
480 (GTK_TREE_MODEL (state
->editor
.typestore
), &iter
));
482 /* Set the expressions */
483 parse_pos_init_editpos (&pp
, state
->sv
);
484 if (gnm_style_cond_get_expr (gsc
, 0))
485 gnm_expr_entry_load_from_expr (GNM_EXPR_ENTRY (state
->editor
.expr_x
),
486 gnm_style_cond_get_expr (gsc
, 0),
489 gnm_expr_entry_load_from_text (GNM_EXPR_ENTRY (state
->editor
.expr_x
),
491 if (gnm_style_cond_get_expr (gsc
, 1))
492 gnm_expr_entry_load_from_expr (GNM_EXPR_ENTRY (state
->editor
.expr_y
),
493 gnm_style_cond_get_expr (gsc
, 1),
496 gnm_expr_entry_load_from_text (GNM_EXPR_ENTRY (state
->editor
.expr_y
),
500 ? gnm_style_get_conditions (state
->style
)
503 style
= gnm_style_dup
504 (gnm_style_get_cond_style (state
->style
, ind
));
506 style
= gnm_style_new_default ();
507 gnm_style_merge (style
, gsc
->overlay
);
509 dialog_cell_format_style_added (state
, style
);
510 /* Set the appl. style components */
511 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-background",
512 MSTYLE_COLOR_BACK
, TRUE
);
513 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-background",
514 MSTYLE_COLOR_PATTERN
, FALSE
);
515 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-background",
516 MSTYLE_PATTERN
, FALSE
);
517 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-number",
518 MSTYLE_FORMAT
, TRUE
);
519 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-align",
520 MSTYLE_ALIGN_V
, TRUE
);
521 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-align",
522 MSTYLE_ALIGN_H
, FALSE
);
523 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-align",
524 MSTYLE_ROTATION
, FALSE
);
525 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-align",
526 MSTYLE_INDENT
, FALSE
);
527 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-align",
528 MSTYLE_TEXT_DIR
, FALSE
);
529 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-align",
530 MSTYLE_WRAP_TEXT
, FALSE
);
531 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-align",
532 MSTYLE_SHRINK_TO_FIT
, FALSE
);
533 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-font",
534 MSTYLE_FONT_COLOR
, TRUE
);
535 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-font",
536 MSTYLE_FONT_NAME
, FALSE
);
537 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-font",
538 MSTYLE_FONT_BOLD
, FALSE
);
539 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-font",
540 MSTYLE_FONT_ITALIC
, FALSE
);
541 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-font",
542 MSTYLE_FONT_UNDERLINE
, FALSE
);
543 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-font",
544 MSTYLE_FONT_STRIKETHROUGH
, FALSE
);
545 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-font",
546 MSTYLE_FONT_SCRIPT
, FALSE
);
547 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-font",
548 MSTYLE_FONT_SIZE
, FALSE
);
549 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-border",
550 MSTYLE_BORDER_TOP
, TRUE
);
551 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-border",
552 MSTYLE_BORDER_BOTTOM
, FALSE
);
553 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-border",
554 MSTYLE_BORDER_LEFT
, FALSE
);
555 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-border",
556 MSTYLE_BORDER_RIGHT
, FALSE
);
557 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-border",
558 MSTYLE_BORDER_REV_DIAGONAL
, FALSE
);
559 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-border",
560 MSTYLE_BORDER_DIAGONAL
, FALSE
);
562 gtk_tree_path_free (path
);
567 c_fmt_dialog_chooser_load_combo (CFormatState
*state
)
574 /* without any expression */
575 { N_("Cell contains an error value."), GNM_STYLE_COND_CONTAINS_ERR
, 0},
576 { N_("Cell does not contain an error value."), GNM_STYLE_COND_NOT_CONTAINS_ERR
, 0},
577 { N_("Cell contains whitespace."), GNM_STYLE_COND_CONTAINS_BLANKS
, 0},
578 { N_("Cell does not contain whitespace."), GNM_STYLE_COND_NOT_CONTAINS_BLANKS
, 0},
579 /* with one expression */
580 { N_("Cell value is = x."), GNM_STYLE_COND_EQUAL
, 1},
581 { N_("Cell value is \xe2\x89\xa0 x."), GNM_STYLE_COND_NOT_EQUAL
, 1},
582 { N_("Cell value is > x."), GNM_STYLE_COND_GT
, 1},
583 { N_("Cell value is < x."), GNM_STYLE_COND_LT
, 1},
584 { N_("Cell value is \xe2\x89\xa7 x."), GNM_STYLE_COND_GTE
, 1},
585 { N_("Cell value is \xe2\x89\xa6 x."), GNM_STYLE_COND_LTE
, 1},
586 { N_("Expression x evaluates to TRUE."), GNM_STYLE_COND_CUSTOM
, 1},
587 { N_("Cell contains the string x."), GNM_STYLE_COND_CONTAINS_STR
, 1},
588 { N_("Cell does not contain the string x."), GNM_STYLE_COND_NOT_CONTAINS_STR
, 1},
589 { N_("Cell value begins with the string x."), GNM_STYLE_COND_BEGINS_WITH_STR
, 1},
590 { N_("Cell value does not begin with the string x."), GNM_STYLE_COND_NOT_BEGINS_WITH_STR
, 1},
591 { N_("Cell value ends with the string x."), GNM_STYLE_COND_ENDS_WITH_STR
, 1},
592 { N_("Cell value does not end with the string x."), GNM_STYLE_COND_NOT_ENDS_WITH_STR
, 1},
593 /* with two expressions */
594 { N_("Cell value is between x and y (incl.)."), GNM_STYLE_COND_BETWEEN
, 2},
595 { N_("Cell value is not between x and y (incl.)."), GNM_STYLE_COND_NOT_BETWEEN
, 2}
598 GtkCellRenderer
*cell
;
601 for (i
= 0; i
< G_N_ELEMENTS (cond_types
); i
++)
602 gtk_list_store_insert_with_values (state
->editor
.typestore
,
604 0, _(cond_types
[i
].label
),
605 1, cond_types
[i
].type
,
606 2, cond_types
[i
].n_expressions
,
608 cell
= gtk_cell_renderer_text_new();
609 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(state
->editor
.combo
), cell
, TRUE
);
610 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(state
->editor
.combo
), cell
, "text", 0, NULL
);
611 if (gtk_tree_model_get_iter_first
612 (GTK_TREE_MODEL (state
->editor
.typestore
), &iter
))
613 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (state
->editor
.combo
), &iter
);
617 /*****************************************************************************/
618 /*****************************************************************************/
620 c_fmt_dialog_condition_setter (SheetView
*sv
, GnmRange
const *range
, CFormatState
*state
)
622 GnmSheetRange
*sr
= g_new (GnmSheetRange
, 1);
624 sr
->sheet
= sv
->sheet
;
625 state
->action
.redo
= go_undo_combine
627 sheet_apply_style_undo (sr
, state
->action
.new_style
));
628 sr
= g_new (GnmSheetRange
, 1);
630 sr
->sheet
= sv
->sheet
;
631 state
->action
.undo
= go_undo_combine
632 (sheet_apply_style_undo (sr
, state
->action
.old_style
),
634 state
->action
.size
++;
639 c_fmt_dialog_condition_setter_tiled (G_GNUC_UNUSED SheetView
*sv
, GnmRange
const *range
,
642 GnmStyleList
*l
, *list
;
643 if (state
->action
.existing_conds_only
)
644 list
= sheet_style_collect_conditions (state
->sheet
, range
);
646 list
= sheet_style_get_range (state
->sheet
, range
);
647 for (l
= list
; l
!= NULL
; l
= l
->next
) {
648 GnmStyleConditions
*old_cond
;
649 GnmStyleRegion
const *sr
= l
->data
;
650 GnmRange r
= *((GnmRange
*) l
->data
);
652 r
.start
.row
+= range
->start
.row
;
653 r
.end
.row
+= range
->start
.row
;
654 r
.start
.col
+= range
->start
.col
;
655 r
.end
.col
+= range
->start
.col
;
656 state
->action
.old_style
= gnm_style_new ();
657 if (gnm_style_is_element_set (sr
->style
, MSTYLE_CONDITIONS
) &&
658 NULL
!= (old_cond
= gnm_style_get_conditions (sr
->style
)))
659 gnm_style_set_conditions (state
->action
.old_style
,
660 g_object_ref (old_cond
));
662 gnm_style_set_conditions (state
->action
.old_style
, NULL
);
663 c_fmt_dialog_condition_setter (state
->sv
, &r
, state
);
664 gnm_style_unref (state
->action
.old_style
);
665 state
->action
.old_style
= NULL
;
667 style_list_free (list
);
672 c_fmt_dialog_set_conditions (CFormatState
*state
, char const *cmd_label
)
674 GnmStyleConditions
*old_cond
;
676 state
->action
.undo
= NULL
;
677 state
->action
.redo
= NULL
;
678 state
->action
.size
= 0;
680 if (state
->homogeneous
) {
681 state
->action
.old_style
= gnm_style_new ();
682 old_cond
= gnm_style_get_conditions (state
->style
);
683 gnm_style_set_conditions (state
->action
.old_style
,
684 old_cond
? g_object_ref (old_cond
) : NULL
);
686 sv_selection_foreach (state
->sv
,
687 (GnmSelectionFunc
)c_fmt_dialog_condition_setter
,
690 sv_selection_foreach (state
->sv
,
691 (GnmSelectionFunc
)c_fmt_dialog_condition_setter_tiled
,
694 cmd_generic_with_size (GNM_WBC (state
->wbcg
), cmd_label
,
695 state
->action
.size
, state
->action
.undo
, state
->action
.redo
);
697 state
->action
.undo
= NULL
;
698 state
->action
.redo
= NULL
;
699 if (state
->action
.old_style
) {
700 gnm_style_unref (state
->action
.old_style
);
701 state
->action
.old_style
= NULL
;
706 c_fmt_dialog_apply_add_choice (CFormatState
*state
, GnmStyleCond
*cond
, gboolean add
)
709 GnmStyleConditions
*sc
;
711 sc
= gnm_style_conditions_dup (gnm_style_get_conditions (state
->style
));
713 sc
= gnm_style_conditions_new (state
->sheet
);
716 if (gtk_tree_selection_get_selected (state
->selection
, NULL
, &iter
)) {
717 GtkTreePath
*path
= gtk_tree_model_get_path
718 (GTK_TREE_MODEL (state
->model
), &iter
);
719 gint
*ind
= gtk_tree_path_get_indices (path
);
721 gnm_style_conditions_delete (sc
, *ind
);
724 gtk_tree_path_free (path
);
727 gnm_style_conditions_insert (sc
, cond
, index
);
728 state
->action
.new_style
= gnm_style_new ();
729 gnm_style_set_conditions (state
->action
.new_style
, sc
);
730 state
->action
.existing_conds_only
= FALSE
;
732 c_fmt_dialog_set_conditions (state
, _("Set conditional formatting"));
734 gnm_style_unref (state
->action
.new_style
);
735 state
->action
.new_style
= NULL
;
737 c_fmt_dialog_load (state
);
742 cb_c_fmt_dialog_clear_clicked (G_GNUC_UNUSED GtkButton
*button
, CFormatState
*state
)
744 state
->action
.new_style
= gnm_style_new ();
745 gnm_style_set_conditions (state
->action
.new_style
, NULL
);
746 state
->action
.existing_conds_only
= TRUE
;
748 c_fmt_dialog_set_conditions (state
, _("Clear conditional formatting"));
750 gnm_style_unref (state
->action
.new_style
);
751 state
->action
.new_style
= NULL
;
753 c_fmt_dialog_load (state
);
757 cb_c_fmt_dialog_remove_clicked (GtkButton
*button
, CFormatState
*state
)
759 if (1 == gtk_tree_model_iter_n_children (GTK_TREE_MODEL (state
->model
), NULL
))
760 cb_c_fmt_dialog_clear_clicked (button
, state
);
763 if (gtk_tree_selection_get_selected (state
->selection
, NULL
, &iter
)) {
764 GtkTreePath
*path
= gtk_tree_model_get_path
765 (GTK_TREE_MODEL (state
->model
), &iter
);
766 gint
*ind
= gtk_tree_path_get_indices (path
);
768 GnmStyleConditions
*sc
;
769 sc
= gnm_style_conditions_dup
770 (gnm_style_get_conditions (state
->style
));
772 gnm_style_conditions_delete (sc
, *ind
);
773 state
->action
.new_style
= gnm_style_new ();
774 gnm_style_set_conditions
775 (state
->action
.new_style
, sc
);
776 state
->action
.existing_conds_only
= TRUE
;
778 c_fmt_dialog_set_conditions
780 _("Remove condition from conditional "
783 gnm_style_unref (state
->action
.new_style
);
784 state
->action
.new_style
= NULL
;
786 c_fmt_dialog_load (state
);
789 gtk_tree_path_free (path
);
795 cb_c_fmt_dialog_expand_clicked (G_GNUC_UNUSED GtkButton
*button
, CFormatState
*state
)
798 if (!state
->homogeneous
&& gtk_tree_selection_get_selected (state
->selection
, NULL
, &iter
)) {
799 GnmStyleConditions
*sc
;
800 gtk_tree_model_get (GTK_TREE_MODEL (state
->model
),
802 CONDITIONS_REFERENCE
, &sc
,
805 state
->action
.new_style
= gnm_style_new ();
806 gnm_style_set_conditions
807 (state
->action
.new_style
, sc
);
808 state
->action
.existing_conds_only
= FALSE
;
810 c_fmt_dialog_set_conditions
812 _("Expand conditional formatting"));
814 gnm_style_unref (state
->action
.new_style
);
815 state
->action
.new_style
= NULL
;
817 c_fmt_dialog_load (state
);
823 c_fmt_dialog_conditions_page_load_cond_single_f (CFormatState
*state
,
824 GnmExprTop
const *texpr
, GtkTreeIter
*iter1
)
830 gtk_tree_store_append (state
->model
, &iter2
, iter1
);
832 parse_pos_init_editpos (&pp
, state
->sv
);
834 formula
= gnm_expr_top_as_string (texpr
, &pp
, gnm_conventions_default
);
835 gtk_tree_store_set (state
->model
, &iter2
, CONDITIONS_RANGE
, NULL
,
836 CONDITIONS_COND
, formula
, CONDITIONS_REFERENCE
, NULL
, -1);
842 c_fmt_dialog_conditions_page_load_cond_double_f (CFormatState
*state
,
843 GnmStyleCond
const *cond
, GtkTreeIter
*iter1
)
845 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), iter1
);
846 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 1), iter1
);
850 c_fmt_dialog_conditions_page_load_cond (CFormatState
*state
, GnmStyleCond
const *cond
,
855 gtk_tree_store_append (state
->model
, &iter1
, iter
);
858 case GNM_STYLE_COND_BETWEEN
:
859 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
861 _("If the cell content is between these "
862 "two values, a special style is used."),
863 CONDITIONS_REFERENCE
, NULL
, -1);
864 c_fmt_dialog_conditions_page_load_cond_double_f (state
, cond
, &iter1
);
866 case GNM_STYLE_COND_NOT_BETWEEN
:
867 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
869 _("If the cell content is not between these"
870 " two values, a special style is used."),
871 CONDITIONS_REFERENCE
, NULL
, -1);
872 c_fmt_dialog_conditions_page_load_cond_double_f (state
, cond
, &iter1
);
874 case GNM_STYLE_COND_EQUAL
:
875 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
877 _("If the cell content is equal to this value"
878 ", a special style is used."),
879 CONDITIONS_REFERENCE
, NULL
, -1);
880 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
882 case GNM_STYLE_COND_NOT_EQUAL
:
883 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
885 _("If the cell content is not equal to this value"
886 ", a special style is used."),
887 CONDITIONS_REFERENCE
, NULL
, -1);
888 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
890 case GNM_STYLE_COND_GT
:
891 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
893 _("If the cell content is > this value, a "
894 "special style is used."), -1);
895 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
897 case GNM_STYLE_COND_LT
:
898 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
900 _("If the cell content is < this value, a "
901 "special style is used."),
902 CONDITIONS_REFERENCE
, NULL
, -1);
903 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
905 case GNM_STYLE_COND_GTE
:
906 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
908 _("If the cell content is \xe2\x89\xa7 this "
909 "value, a special style is used."),
910 CONDITIONS_REFERENCE
, NULL
, -1);
912 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
914 case GNM_STYLE_COND_LTE
:
915 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
917 _("If the cell content is \xe2\x89\xa6 this "
918 "value, a special style is used."),
919 CONDITIONS_REFERENCE
, NULL
, -1);
920 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
923 case GNM_STYLE_COND_CUSTOM
:
924 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
926 _("If this formula evaluates to TRUE, a special style is used."),
927 CONDITIONS_REFERENCE
, NULL
, -1);
928 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
930 case GNM_STYLE_COND_CONTAINS_STR
:
931 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
933 _("If the cell content contains this string"
934 ", a special style is used."),
935 CONDITIONS_REFERENCE
, NULL
, -1);
936 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
938 case GNM_STYLE_COND_NOT_CONTAINS_STR
:
939 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
941 _("If the cell content does not contain this string"
942 ", a special style is used."),
943 CONDITIONS_REFERENCE
, NULL
, -1);
944 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
946 case GNM_STYLE_COND_BEGINS_WITH_STR
:
947 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
949 _("If the cell content begins with this string"
950 ", a special style is used."),
951 CONDITIONS_REFERENCE
, NULL
, -1);
952 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
954 case GNM_STYLE_COND_NOT_BEGINS_WITH_STR
:
955 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
957 _("If the cell content does not begin with this string,"
958 " a special style is used."), -1);
959 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
961 case GNM_STYLE_COND_ENDS_WITH_STR
:
962 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
964 _("If the cell content ends with this string"
965 ", a special style is used."),
966 CONDITIONS_REFERENCE
, NULL
, -1);
967 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
969 case GNM_STYLE_COND_NOT_ENDS_WITH_STR
:
970 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
972 _("If the cell content does not end "
973 "with this string, a special style is used."),
974 CONDITIONS_REFERENCE
, NULL
, -1);
975 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
977 case GNM_STYLE_COND_CONTAINS_ERR
:
978 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
980 _("If the cell contains an error "
981 "value, a special style is used."), -1);
983 case GNM_STYLE_COND_NOT_CONTAINS_ERR
:
984 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
986 _("If the cell does not contain an error value"
987 ", a special style is used."),
988 CONDITIONS_REFERENCE
, NULL
, -1);
990 case GNM_STYLE_COND_CONTAINS_BLANKS
:
991 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
993 _("If the cell content "
994 "contains blanks, a special style is used."),
995 CONDITIONS_REFERENCE
, NULL
, -1);
997 case GNM_STYLE_COND_NOT_CONTAINS_BLANKS
:
998 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
1000 _("If the cell content does not contain blanks"
1001 ", a special style is used."),
1002 CONDITIONS_REFERENCE
, NULL
, -1);
1005 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
1007 _("This is an unknown condition type."),
1008 CONDITIONS_REFERENCE
, NULL
, -1);
1014 c_fmt_dialog_conditions_page_load_conditions (GnmStyle
*style
, char const *range
, CFormatState
*state
)
1016 GnmStyleConditions
const *sc
;
1017 GPtrArray
const *conds
;
1019 GtkTreeIter iter1
, *iter
;
1021 if (gnm_style_is_element_set (style
, MSTYLE_CONDITIONS
) &&
1022 NULL
!= (sc
= gnm_style_get_conditions (style
)) &&
1023 NULL
!= (conds
= gnm_style_conditions_details (sc
))) {
1028 gtk_tree_store_append (state
->model
, iter
, NULL
);
1029 gtk_tree_store_set (state
->model
, iter
, CONDITIONS_RANGE
, range
,
1030 CONDITIONS_COND
, NULL
,
1031 CONDITIONS_REFERENCE
, sc
, -1);
1033 for (i
= 0 ; i
< conds
->len
; i
++)
1034 c_fmt_dialog_conditions_page_load_cond
1035 (state
, g_ptr_array_index (conds
, i
), iter
);
1041 c_fmt_dialog_condition_collector (G_GNUC_UNUSED SheetView
*sv
, GnmRange
const *range
,
1044 CFormatState
*state
= user_data
;
1045 GnmStyleList
*l
, *list
= sheet_style_collect_conditions (state
->sheet
, range
);
1047 for (l
= list
; l
!= NULL
; l
= l
->next
) {
1048 GnmStyleRegion
const *sr
= l
->data
;
1049 GnmRange r
= *((GnmRange
*) l
->data
);
1050 r
.start
.row
+= range
->start
.row
;
1051 r
.end
.row
+= range
->start
.row
;
1052 r
.start
.col
+= range
->start
.col
;
1053 r
.end
.col
+= range
->start
.col
;
1054 c_fmt_dialog_conditions_page_load_conditions
1055 (sr
->style
, range_as_string (&r
), state
);
1058 style_list_free (list
);
1064 c_fmt_dialog_selection_type (SheetView
*sv
,
1065 GnmRange
const *range
,
1068 GnmBorder
*borders
[GNM_STYLE_BORDER_EDGE_MAX
] = {NULL
};
1069 CFormatState
*state
= user_data
;
1071 GSList
*merged
= gnm_sheet_merge_get_overlap (sv
->sheet
, range
);
1072 GnmRange r
= *range
;
1073 gboolean allow_multi
=
1075 merged
->next
!= NULL
||
1076 !range_equal ((GnmRange
*)merged
->data
, range
);
1079 g_slist_free (merged
);
1081 /* allow_multi == FALSE && !is_singleton (range) means that we are in
1082 * an merge cell, use only the top left */
1084 if (r
.start
.col
!= r
.end
.col
)
1085 r
.end
.col
= r
.start
.col
;
1086 if (range
->start
.row
!= range
->end
.row
)
1087 r
.end
.row
= r
.start
.row
;
1090 state
->conflicts
= sheet_style_find_conflicts (state
->sheet
, &r
,
1091 &(state
->style
), borders
);
1093 for (i
= GNM_STYLE_BORDER_TOP
; i
< GNM_STYLE_BORDER_EDGE_MAX
; i
++) {
1094 gnm_style_border_unref (borders
[i
]);
1101 c_fmt_dialog_load (CFormatState
*state
)
1103 gtk_tree_store_clear (state
->model
);
1105 gnm_style_unref (state
->style
);
1106 state
->style
= NULL
;
1108 (void) sv_selection_foreach (state
->sv
,
1109 c_fmt_dialog_selection_type
, state
);
1111 state
->homogeneous
= !(state
->conflicts
& (1 << MSTYLE_CONDITIONS
));
1113 if (state
->homogeneous
) {
1114 gtk_label_set_markup (state
->label
,
1115 _("The selection is homogeneous with "
1116 "respect to conditions."));
1117 if (state
->style
!= NULL
)
1118 c_fmt_dialog_conditions_page_load_conditions
1119 (state
->style
, NULL
, state
);
1120 gtk_tree_view_expand_all (state
->treeview
);
1122 gtk_label_set_markup (state
->label
,
1123 _("The selection is <b>not</b> "
1125 "with respect to conditions!"));
1126 (void) sv_selection_foreach (state
->sv
,
1127 c_fmt_dialog_condition_collector
, state
);
1129 gtk_tree_view_column_queue_resize
1130 (gtk_tree_view_get_column (state
->treeview
, CONDITIONS_RANGE
));
1131 c_fmt_dialog_set_sensitive (state
);
1135 cb_selection_changed (G_GNUC_UNUSED GtkTreeSelection
*treeselection
, CFormatState
*state
)
1137 c_fmt_dialog_set_sensitive (state
);
1141 cb_can_select (G_GNUC_UNUSED GtkTreeSelection
*selection
,
1142 G_GNUC_UNUSED GtkTreeModel
*model
,
1144 gboolean path_currently_selected
,
1145 G_GNUC_UNUSED CFormatState
*state
)
1147 if (path_currently_selected
)
1150 return (gtk_tree_path_get_depth (path
) == 1);
1154 cb_c_format_dialog_range (G_GNUC_UNUSED SheetView
*sv
, GnmRange
const *range
, GString
*str
)
1156 g_string_append (str
, range_as_string (range
));
1157 g_string_append (str
, ", ");
1162 c_fmt_dialog_init_editor_page (CFormatState
*state
)
1166 state
->editor
.add_button
= go_gtk_builder_get_widget (state
->gui
, "add-button");
1167 state
->editor
.replace_button
= go_gtk_builder_get_widget (state
->gui
, "replace-button");
1168 state
->editor
.copy_button
= go_gtk_builder_get_widget (state
->gui
, "copy-button");
1169 state
->editor
.edit_style_button
= go_gtk_builder_get_widget (state
->gui
, "edit-style-button");
1170 state
->editor
.combo
= go_gtk_builder_get_widget (state
->gui
, "condition-combo");
1171 grid
= GTK_GRID (go_gtk_builder_get_widget (state
->gui
, "condition-grid"));
1172 state
->editor
.expr_x
= GTK_WIDGET (gnm_expr_entry_new (state
->wbcg
, TRUE
));
1173 gtk_grid_attach (grid
, state
->editor
.expr_x
, 1, 2, 2, 1);
1174 gtk_widget_set_hexpand (state
->editor
.expr_x
, TRUE
);
1175 gtk_widget_show(state
->editor
.expr_x
);
1176 gnm_expr_entry_set_flags (GNM_EXPR_ENTRY (state
->editor
.expr_x
),
1177 GNM_EE_SHEET_OPTIONAL
|
1178 GNM_EE_CONSTANT_ALLOWED
,
1181 state
->editor
.expr_y
= GTK_WIDGET (gnm_expr_entry_new (state
->wbcg
, TRUE
));
1182 gtk_grid_attach (grid
, state
->editor
.expr_y
, 1, 3, 2, 1);
1183 gtk_widget_set_hexpand (state
->editor
.expr_y
, TRUE
);
1184 gtk_widget_show(state
->editor
.expr_y
);
1185 gnm_expr_entry_set_flags (GNM_EXPR_ENTRY (state
->editor
.expr_y
),
1186 GNM_EE_SHEET_OPTIONAL
|
1187 GNM_EE_CONSTANT_ALLOWED
,
1190 state
->editor
.typestore
= GTK_LIST_STORE (gtk_combo_box_get_model
1191 (GTK_COMBO_BOX (state
->editor
.combo
)));
1192 c_fmt_dialog_chooser_load_combo (state
);
1194 state
->editor
.style_label
= go_gtk_builder_get_widget (state
->gui
, "style-label");
1195 gtk_label_set_text (GTK_LABEL (state
->editor
.style_label
), _("(undefined)"));
1197 c_fmt_dialog_set_expr_sensitive (state
);
1199 g_signal_connect (G_OBJECT (state
->editor
.add_button
),
1201 G_CALLBACK (cb_c_fmt_dialog_add_button
), state
);
1202 g_signal_connect (G_OBJECT (state
->editor
.replace_button
),
1204 G_CALLBACK (cb_c_fmt_dialog_replace_button
), state
);
1205 g_signal_connect (G_OBJECT (state
->editor
.copy_button
),
1207 G_CALLBACK (cb_c_fmt_dialog_copy_button
), state
);
1208 g_signal_connect (G_OBJECT (state
->editor
.edit_style_button
),
1210 G_CALLBACK (cb_c_fmt_dialog_edit_style_button
), state
);
1211 g_signal_connect (G_OBJECT (state
->editor
.combo
),
1213 G_CALLBACK (cb_c_fmt_dialog_chooser_type_changed
), state
);
1214 g_signal_connect (G_OBJECT (gnm_expr_entry_get_entry (GNM_EXPR_ENTRY (state
->editor
.expr_x
))),
1216 G_CALLBACK (cb_c_fmt_dialog_chooser_entry_changed
), state
);
1217 g_signal_connect (G_OBJECT (gnm_expr_entry_get_entry (GNM_EXPR_ENTRY (state
->editor
.expr_y
))),
1219 G_CALLBACK (cb_c_fmt_dialog_chooser_entry_changed
), state
);
1224 c_fmt_dialog_init_conditions_page (CFormatState
*state
)
1226 GtkTreeViewColumn
* column
;
1227 GtkCellRenderer
*renderer
;
1231 g_return_if_fail (state
!= NULL
);
1233 state
->remove
= GTK_BUTTON (go_gtk_builder_get_widget (state
->gui
,
1234 "conditions_remove"));
1235 gtk_widget_set_sensitive (GTK_WIDGET (state
->remove
), FALSE
);
1236 state
->clear
= GTK_BUTTON (go_gtk_builder_get_widget (state
->gui
,
1237 "conditions_clear"));
1238 gtk_widget_set_sensitive (GTK_WIDGET (state
->clear
), FALSE
);
1239 state
->expand
= GTK_BUTTON (go_gtk_builder_get_widget (state
->gui
,
1240 "conditions_expand"));
1241 gtk_widget_set_sensitive (GTK_WIDGET (state
->expand
), FALSE
);
1243 state
->model
= gtk_tree_store_new (CONDITIONS_NUM_COLUMNS
,
1247 state
->treeview
= GTK_TREE_VIEW (go_gtk_builder_get_widget
1248 (state
->gui
, "conditions_treeview"));
1249 gtk_tree_view_set_fixed_height_mode (state
->treeview
, FALSE
);
1250 gtk_tree_view_set_model (state
->treeview
, GTK_TREE_MODEL (state
->model
));
1251 g_object_unref (state
->model
);
1252 state
->selection
= gtk_tree_view_get_selection (state
->treeview
);
1253 gtk_tree_selection_set_mode (state
->selection
, GTK_SELECTION_SINGLE
);
1254 gtk_tree_selection_set_select_function (state
->selection
,
1255 (GtkTreeSelectionFunc
) cb_can_select
,
1257 renderer
= gtk_cell_renderer_text_new ();
1258 column
= gtk_tree_view_column_new_with_attributes
1259 ("Range", renderer
, "text", CONDITIONS_RANGE
, NULL
);
1260 gtk_tree_view_insert_column (state
->treeview
, column
, -1);
1261 renderer
= gtk_cell_renderer_text_new ();
1262 column
= gtk_tree_view_column_new_with_attributes
1263 ("Conditions", renderer
, "text", CONDITIONS_COND
, NULL
);
1264 gtk_tree_view_insert_column (state
->treeview
, column
, -1);
1265 gtk_tree_view_set_expander_column (state
->treeview
, column
);
1267 state
->label
= GTK_LABEL (go_gtk_builder_get_widget (state
->gui
,
1268 "conditions_label"));
1269 hl
= GTK_LABEL (go_gtk_builder_get_widget (state
->gui
, "header-label"));
1270 gtk_label_set_ellipsize (hl
, PANGO_ELLIPSIZE_END
);
1271 str
= g_string_new (_("Editing conditional formatting: "));
1272 sv_selection_foreach (state
->sv
,
1273 (GnmSelectionFunc
)cb_c_format_dialog_range
,
1275 g_string_truncate (str
, str
->len
-2);
1276 gtk_label_set_text(hl
, str
->str
);
1277 g_string_free (str
, TRUE
);
1279 g_signal_connect (G_OBJECT (state
->selection
), "changed",
1280 G_CALLBACK (cb_selection_changed
), state
);
1281 g_signal_connect (G_OBJECT (state
->remove
), "clicked",
1282 G_CALLBACK (cb_c_fmt_dialog_remove_clicked
), state
);
1283 g_signal_connect (G_OBJECT (state
->clear
), "clicked",
1284 G_CALLBACK (cb_c_fmt_dialog_clear_clicked
), state
);
1285 g_signal_connect (G_OBJECT (state
->expand
), "clicked",
1286 G_CALLBACK (cb_c_fmt_dialog_expand_clicked
), state
);
1289 /*****************************************************************************/
1293 dialog_cell_format_cond (WBCGtk
*wbcg
)
1296 CFormatState
*state
;
1299 g_return_if_fail (wbcg
!= NULL
);
1301 gui
= gnm_gtk_builder_load ("res:ui/cell-format-cond.ui", NULL
, GO_CMD_CONTEXT (wbcg
));
1306 state
= g_new (CFormatState
, 1);
1309 state
->sv
= wb_control_cur_sheet_view (GNM_WBC (wbcg
));
1310 state
->sheet
= sv_sheet (state
->sv
);
1311 state
->style
= NULL
;
1312 state
->editor
.style
= NULL
;
1313 state
->editor
.dialog
= NULL
;
1315 dialog
= go_gtk_builder_get_widget (state
->gui
, "CellFormat");
1316 g_return_if_fail (dialog
!= NULL
);
1318 gtk_window_set_title (GTK_WINDOW (dialog
), _("Conditional Cell Formatting"));
1321 state
->dialog
= GTK_DIALOG (dialog
);
1323 c_fmt_dialog_init_conditions_page (state
);
1324 c_fmt_dialog_init_editor_page (state
);
1326 c_fmt_dialog_load (state
);
1328 gnm_init_help_button (
1329 go_gtk_builder_get_widget (state
->gui
, "helpbutton"),
1330 GNUMERIC_HELP_LINK_CELL_FORMAT_COND
);
1332 state
->close_button
= go_gtk_builder_get_widget (state
->gui
, "closebutton");
1333 g_signal_connect (G_OBJECT (state
->close_button
),
1335 G_CALLBACK (cb_c_fmt_dialog_dialog_buttons
), state
);
1337 gnm_dialog_setup_destroy_handlers (GTK_DIALOG (dialog
), state
->wbcg
,
1338 GNM_DIALOG_DESTROY_CURRENT_SHEET_REMOVED
);
1340 /* a candidate for merging into attach guru */
1341 wbc_gtk_attach_guru (state
->wbcg
, GTK_WIDGET (state
->dialog
));
1342 g_object_set_data_full (G_OBJECT (state
->dialog
),
1343 "state", state
, (GDestroyNotify
)cb_c_fmt_dialog_dialog_destroy
);
1344 g_signal_connect (G_OBJECT (dialog
), "destroy",
1345 G_CALLBACK (cb_dialog_destroy
), NULL
);
1347 gnm_restore_window_geometry (GTK_WINDOW (state
->dialog
),
1350 go_gtk_nonmodal_dialog (wbcg_toplevel (state
->wbcg
),
1351 GTK_WINDOW (state
->dialog
));
1353 gtk_widget_show (GTK_WIDGET (state
->dialog
));