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>
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>
50 #define CELL_FORMAT_KEY "cell-format-cond-dialog"
51 #define CELL_FORMAT_DEF_KEY "cell-format-cond-def-dialog"
53 typedef struct _CFormatState
{
57 GtkWidget
*close_button
;
61 unsigned int conflicts
;
69 GtkTreeView
*treeview
;
71 GtkTreeSelection
*selection
;
79 gboolean existing_conds_only
;
82 GtkWidget
*edit_style_button
;
83 GtkWidget
*add_button
;
84 GtkWidget
*replace_button
;
85 GtkWidget
*copy_button
;
89 GtkListStore
*typestore
;
91 GtkWidget
*style_label
;
100 CONDITIONS_NUM_COLUMNS
105 /*****************************************************************************/
106 static void c_fmt_dialog_load (CFormatState
*state
);
107 static void c_fmt_dialog_apply_add_choice (CFormatState
*state
, GnmStyleCond
*cond
, gboolean add
);
109 /*****************************************************************************/
111 /* button handlers */
113 cb_c_fmt_dialog_dialog_buttons (G_GNUC_UNUSED GtkWidget
*btn
, CFormatState
*state
)
115 /* users may accidentally click on 'close' before adding the formatting style see #733352 */
116 if (!gtk_widget_get_sensitive (GTK_WIDGET (state
->editor
.add_button
)) ||
117 gtk_widget_get_sensitive (GTK_WIDGET (state
->clear
)) ||
118 go_gtk_query_yes_no (GTK_WINDOW (state
->dialog
), FALSE
,
119 _("You did not add the defined conditional format."
120 " Do you really want to close the conditional formatting dialog?")))
121 gtk_widget_destroy (GTK_WIDGET (state
->dialog
));
124 /* Handler for destroy */
126 cb_c_fmt_dialog_dialog_destroy (CFormatState
*state
)
128 if (state
->editor
.dialog
) {
129 gtk_widget_destroy (GTK_WIDGET (state
->editor
.dialog
));
130 state
->editor
.dialog
= NULL
;
132 if (state
->editor
.style
)
133 gnm_style_unref (state
->editor
.style
);
135 gnm_style_unref (state
->style
);
136 g_object_unref (state
->gui
);
141 cb_dialog_destroy (GtkDialog
*dialog
)
143 g_object_set_data (G_OBJECT (dialog
), "state", NULL
);
146 /*****************************************************************************/
149 c_fmt_dialog_set_sensitive (CFormatState
*state
)
151 gboolean ok
= (state
->editor
.style
!= NULL
&& state
->homogeneous
);
154 gboolean not_empty
, selected
;
156 not_empty
= gtk_tree_model_get_iter_first
157 (GTK_TREE_MODEL (state
->model
), &iter
);
158 selected
= gtk_tree_selection_get_selected
159 (state
->selection
, NULL
, NULL
);
161 gtk_widget_set_sensitive (GTK_WIDGET (state
->clear
), not_empty
);
163 gtk_widget_set_sensitive (GTK_WIDGET (state
->remove
),
164 state
->homogeneous
&& selected
);
165 gtk_widget_set_sensitive (GTK_WIDGET (state
->expand
),
166 (!state
->homogeneous
) && selected
);
168 parse_pos_init_editpos (&pp
, state
->sv
);
170 if (ok
&& gtk_widget_get_sensitive (state
->editor
.expr_x
)) {
171 GnmExprTop
const *texpr
= gnm_expr_entry_parse (GNM_EXPR_ENTRY (state
->editor
.expr_x
), &pp
,
173 GNM_EXPR_PARSE_UNKNOWN_NAMES_ARE_STRINGS
);
174 ok
= (texpr
!= NULL
);
176 gnm_expr_top_unref (texpr
);
178 if (ok
&& gtk_widget_get_sensitive (state
->editor
.expr_y
)) {
179 GnmExprTop
const *texpr
= gnm_expr_entry_parse (GNM_EXPR_ENTRY (state
->editor
.expr_y
), &pp
,
181 GNM_EXPR_PARSE_UNKNOWN_NAMES_ARE_STRINGS
);
182 ok
= (texpr
!= NULL
);
184 gnm_expr_top_unref (texpr
);
187 gtk_widget_set_sensitive (state
->editor
.add_button
, ok
);
188 gtk_widget_set_sensitive (state
->editor
.replace_button
, ok
&& selected
);
189 gtk_widget_set_sensitive (state
->editor
.copy_button
, selected
&& state
->homogeneous
);
193 c_fmt_dialog_set_expr_sensitive (CFormatState
*state
)
198 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (state
->editor
.combo
), &iter
))
199 gtk_tree_model_get (GTK_TREE_MODEL (state
->editor
.typestore
),
204 gtk_widget_set_sensitive (state
->editor
.expr_x
, FALSE
);
205 gtk_entry_set_text (gnm_expr_entry_get_entry (GNM_EXPR_ENTRY (state
->editor
.expr_x
)), "");
207 gtk_widget_set_sensitive (state
->editor
.expr_x
, TRUE
);
209 gtk_widget_set_sensitive (state
->editor
.expr_y
, FALSE
);
210 gtk_entry_set_text (gnm_expr_entry_get_entry (GNM_EXPR_ENTRY (state
->editor
.expr_y
)), "");
212 gtk_widget_set_sensitive (state
->editor
.expr_y
, TRUE
);
216 cb_c_fmt_dialog_chooser_type_changed (G_GNUC_UNUSED GtkComboBox
*widget
, CFormatState
*state
)
218 c_fmt_dialog_set_expr_sensitive (state
);
219 c_fmt_dialog_set_sensitive (state
);
223 cb_c_fmt_dialog_chooser_entry_changed (G_GNUC_UNUSED GnmExprEntry
*widget
, G_GNUC_UNUSED GdkEvent
*event
,
226 c_fmt_dialog_set_sensitive (state
);
231 dialog_cell_format_style_added (gpointer closure
, GnmStyle
*style
)
233 CFormatState
*state
= closure
;
235 if (state
->editor
.style
)
236 gnm_style_unref (state
->editor
.style
);
237 state
->editor
.style
= style
;
238 gtk_label_set_text (GTK_LABEL (state
->editor
.style_label
),
239 style
? _("(defined)") : _("(undefined)"));
240 c_fmt_dialog_set_sensitive (state
);
244 c_fmt_dialog_set_component (CFormatState
*state
, GnmStyle
*overlay
, gchar
const *name
,
245 GnmStyleElement elem
, gboolean uncheck
)
247 GtkWidget
*w
= go_gtk_builder_get_widget (state
->gui
, name
);
249 if (gnm_style_is_element_set (overlay
, elem
))
250 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w
), TRUE
);
252 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w
), FALSE
);
257 cb_c_fmt_dialog_chooser_check_page (CFormatState
*state
, gchar
const *name
,
260 GtkWidget
*w
= go_gtk_builder_get_widget (state
->gui
, name
);
262 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w
)))
269 editor_destroy_cb (G_GNUC_UNUSED GObject
*obj
, CFormatState
*state
)
271 state
->editor
.dialog
= NULL
;
275 c_fmt_dialog_select_style (CFormatState
*state
, int pages
)
277 if (state
->editor
.dialog
)
278 gtk_widget_destroy (GTK_WIDGET (state
->editor
.dialog
));
279 state
->editor
.dialog
= dialog_cell_format_select_style
281 GTK_WINDOW (state
->dialog
),
282 state
->editor
.style
, state
);
283 if (state
->editor
.dialog
)
285 (G_OBJECT (state
->editor
.dialog
),
286 "destroy", G_CALLBACK (editor_destroy_cb
), state
);
290 cb_c_fmt_dialog_edit_style_button (G_GNUC_UNUSED GtkWidget
*btn
, CFormatState
*state
)
293 pages
|= cb_c_fmt_dialog_chooser_check_page
294 (state
, "check-background", FD_BACKGROUND
);
295 pages
|= cb_c_fmt_dialog_chooser_check_page
296 (state
, "check-number", FD_NUMBER
);
297 pages
|= cb_c_fmt_dialog_chooser_check_page
298 (state
, "check-align", FD_ALIGNMENT
);
299 pages
|= cb_c_fmt_dialog_chooser_check_page
300 (state
, "check-font", FD_FONT
);
301 pages
|= cb_c_fmt_dialog_chooser_check_page
302 (state
, "check-border", FD_BORDER
);
303 pages
|= cb_c_fmt_dialog_chooser_check_page
304 (state
, "check-protection", FD_PROTECTION
);
305 pages
|= cb_c_fmt_dialog_chooser_check_page
306 (state
, "check-validation", FD_VALIDATION
);
308 if (state
->editor
.style
!= NULL
)
309 gnm_style_ref (state
->editor
.style
);
310 c_fmt_dialog_select_style (state
, pages
);
313 static GnmStyleCond
*
314 c_fmt_dialog_get_condition (CFormatState
*state
)
323 parse_pos_init_editpos (&pp
, state
->sv
);
325 overlay
= gnm_style_new ();
326 if (state
->editor
.style
) {
327 if (cb_c_fmt_dialog_chooser_check_page
328 (state
, "check-background", FD_BACKGROUND
)) {
329 gnm_style_merge_element (overlay
, state
->editor
.style
,
331 gnm_style_merge_element (overlay
, state
->editor
.style
,
332 MSTYLE_COLOR_PATTERN
);
333 gnm_style_merge_element (overlay
, state
->editor
.style
,
336 if (cb_c_fmt_dialog_chooser_check_page
337 (state
, "check-number", FD_NUMBER
)) {
338 gnm_style_merge_element (overlay
, state
->editor
.style
,
341 if (cb_c_fmt_dialog_chooser_check_page
342 (state
, "check-align", FD_ALIGNMENT
)) {
343 gnm_style_merge_element (overlay
, state
->editor
.style
,
345 gnm_style_merge_element (overlay
, state
->editor
.style
,
347 gnm_style_merge_element (overlay
, state
->editor
.style
,
349 gnm_style_merge_element (overlay
, state
->editor
.style
,
351 gnm_style_merge_element (overlay
, state
->editor
.style
,
353 gnm_style_merge_element (overlay
, state
->editor
.style
,
355 gnm_style_merge_element (overlay
, state
->editor
.style
,
356 MSTYLE_SHRINK_TO_FIT
);
358 if (cb_c_fmt_dialog_chooser_check_page
359 (state
, "check-font", FD_FONT
)) {
360 gnm_style_merge_element (overlay
, state
->editor
.style
,
362 gnm_style_merge_element (overlay
, state
->editor
.style
,
364 gnm_style_merge_element (overlay
, state
->editor
.style
,
366 gnm_style_merge_element (overlay
, state
->editor
.style
,
368 gnm_style_merge_element (overlay
, state
->editor
.style
,
369 MSTYLE_FONT_UNDERLINE
);
370 gnm_style_merge_element (overlay
, state
->editor
.style
,
371 MSTYLE_FONT_STRIKETHROUGH
);
372 gnm_style_merge_element (overlay
, state
->editor
.style
,
374 gnm_style_merge_element (overlay
, state
->editor
.style
,
377 if (cb_c_fmt_dialog_chooser_check_page
378 (state
, "check-border", FD_BORDER
)) {
379 gnm_style_merge_element (overlay
, state
->editor
.style
,
381 gnm_style_merge_element (overlay
, state
->editor
.style
,
382 MSTYLE_BORDER_BOTTOM
);
383 gnm_style_merge_element (overlay
, state
->editor
.style
,
385 gnm_style_merge_element (overlay
, state
->editor
.style
,
386 MSTYLE_BORDER_RIGHT
);
387 gnm_style_merge_element (overlay
, state
->editor
.style
,
388 MSTYLE_BORDER_REV_DIAGONAL
);
389 gnm_style_merge_element (overlay
, state
->editor
.style
,
390 MSTYLE_BORDER_DIAGONAL
);
392 if (cb_c_fmt_dialog_chooser_check_page
393 (state
, "check-protection", FD_PROTECTION
)) {
396 if (cb_c_fmt_dialog_chooser_check_page
397 (state
, "check-validation", FD_VALIDATION
)) {
401 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (state
->editor
.combo
), &iter
))
402 gtk_tree_model_get (GTK_TREE_MODEL (state
->editor
.typestore
),
408 op
= GNM_STYLE_COND_CONTAINS_ERR
;
410 cond
= gnm_style_cond_new (op
, state
->sheet
);
411 gnm_style_cond_set_overlay (cond
, overlay
);
412 gnm_style_unref (overlay
);
415 GnmExprTop
const *texpr
= gnm_expr_entry_parse (GNM_EXPR_ENTRY (state
->editor
.expr_x
), &pp
,
417 GNM_EXPR_PARSE_UNKNOWN_NAMES_ARE_STRINGS
);
418 gnm_style_cond_set_expr (cond
, texpr
, 0);
419 gnm_expr_top_unref (texpr
);
422 GnmExprTop
const *texpr
= gnm_expr_entry_parse (GNM_EXPR_ENTRY (state
->editor
.expr_y
), &pp
,
424 GNM_EXPR_PARSE_UNKNOWN_NAMES_ARE_STRINGS
);
425 gnm_style_cond_set_expr (cond
, texpr
, 1);
426 gnm_expr_top_unref (texpr
);
432 cb_c_fmt_dialog_add_button (G_GNUC_UNUSED GtkWidget
*btn
, CFormatState
*state
)
434 GnmStyleCond
*cond
= c_fmt_dialog_get_condition (state
);
435 c_fmt_dialog_apply_add_choice (state
, cond
, TRUE
);
436 gnm_style_cond_free (cond
);
440 cb_c_fmt_dialog_replace_button (G_GNUC_UNUSED GtkWidget
*btn
, CFormatState
*state
)
442 GnmStyleCond
*cond
= c_fmt_dialog_get_condition (state
);
443 c_fmt_dialog_apply_add_choice (state
, cond
, FALSE
);
444 gnm_style_cond_free (cond
);
448 cb_c_fmt_dialog_copy_button (G_GNUC_UNUSED GtkWidget
*btn
, CFormatState
*state
)
450 GnmStyleConditions
*sc
;
452 sc
= gnm_style_get_conditions (state
->style
);
453 if (sc
!= NULL
&& gtk_tree_selection_get_selected (state
->selection
, NULL
, &iter
)) {
454 GtkTreePath
*path
= gtk_tree_model_get_path
455 (GTK_TREE_MODEL (state
->model
), &iter
);
456 gint
*pind
= gtk_tree_path_get_indices (path
);
457 GPtrArray
const *conds
= gnm_style_conditions_details (sc
);
460 GnmStyleCond
*gsc
= g_ptr_array_index (conds
, ind
);
464 GnmStyleConditions
*conds
;
466 /* Set the condition op */
467 if (gtk_tree_model_get_iter_first
468 (GTK_TREE_MODEL (state
->editor
.typestore
), &iter
)) {
471 gtk_tree_model_get (GTK_TREE_MODEL (state
->editor
.typestore
),
476 gtk_combo_box_set_active_iter
477 (GTK_COMBO_BOX (state
->editor
.combo
), &iter
);
480 } while (gtk_tree_model_iter_next
481 (GTK_TREE_MODEL (state
->editor
.typestore
), &iter
));
483 /* Set the expressions */
484 parse_pos_init_editpos (&pp
, state
->sv
);
485 if (gnm_style_cond_get_expr (gsc
, 0))
486 gnm_expr_entry_load_from_expr (GNM_EXPR_ENTRY (state
->editor
.expr_x
),
487 gnm_style_cond_get_expr (gsc
, 0),
490 gnm_expr_entry_load_from_text (GNM_EXPR_ENTRY (state
->editor
.expr_x
),
492 if (gnm_style_cond_get_expr (gsc
, 1))
493 gnm_expr_entry_load_from_expr (GNM_EXPR_ENTRY (state
->editor
.expr_y
),
494 gnm_style_cond_get_expr (gsc
, 1),
497 gnm_expr_entry_load_from_text (GNM_EXPR_ENTRY (state
->editor
.expr_y
),
501 ? gnm_style_get_conditions (state
->style
)
504 style
= gnm_style_dup
505 (gnm_style_get_cond_style (state
->style
, ind
));
507 style
= gnm_style_new_default ();
508 gnm_style_merge (style
, gsc
->overlay
);
510 dialog_cell_format_style_added (state
, style
);
511 /* Set the appl. style components */
512 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-background",
513 MSTYLE_COLOR_BACK
, TRUE
);
514 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-background",
515 MSTYLE_COLOR_PATTERN
, FALSE
);
516 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-background",
517 MSTYLE_PATTERN
, FALSE
);
518 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-number",
519 MSTYLE_FORMAT
, TRUE
);
520 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-align",
521 MSTYLE_ALIGN_V
, TRUE
);
522 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-align",
523 MSTYLE_ALIGN_H
, FALSE
);
524 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-align",
525 MSTYLE_ROTATION
, FALSE
);
526 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-align",
527 MSTYLE_INDENT
, FALSE
);
528 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-align",
529 MSTYLE_TEXT_DIR
, FALSE
);
530 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-align",
531 MSTYLE_WRAP_TEXT
, FALSE
);
532 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-align",
533 MSTYLE_SHRINK_TO_FIT
, FALSE
);
534 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-font",
535 MSTYLE_FONT_COLOR
, TRUE
);
536 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-font",
537 MSTYLE_FONT_NAME
, FALSE
);
538 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-font",
539 MSTYLE_FONT_BOLD
, FALSE
);
540 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-font",
541 MSTYLE_FONT_ITALIC
, FALSE
);
542 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-font",
543 MSTYLE_FONT_UNDERLINE
, FALSE
);
544 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-font",
545 MSTYLE_FONT_STRIKETHROUGH
, FALSE
);
546 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-font",
547 MSTYLE_FONT_SCRIPT
, FALSE
);
548 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-font",
549 MSTYLE_FONT_SIZE
, FALSE
);
550 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-border",
551 MSTYLE_BORDER_TOP
, TRUE
);
552 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-border",
553 MSTYLE_BORDER_BOTTOM
, FALSE
);
554 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-border",
555 MSTYLE_BORDER_LEFT
, FALSE
);
556 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-border",
557 MSTYLE_BORDER_RIGHT
, FALSE
);
558 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-border",
559 MSTYLE_BORDER_REV_DIAGONAL
, FALSE
);
560 c_fmt_dialog_set_component (state
, gsc
->overlay
, "check-border",
561 MSTYLE_BORDER_DIAGONAL
, FALSE
);
563 gtk_tree_path_free (path
);
568 c_fmt_dialog_chooser_load_combo (CFormatState
*state
)
575 /* without any expression */
576 { N_("Cell contains an error value."), GNM_STYLE_COND_CONTAINS_ERR
, 0},
577 { N_("Cell does not contain an error value."), GNM_STYLE_COND_NOT_CONTAINS_ERR
, 0},
578 { N_("Cell contains whitespace."), GNM_STYLE_COND_CONTAINS_BLANKS
, 0},
579 { N_("Cell does not contain whitespace."), GNM_STYLE_COND_NOT_CONTAINS_BLANKS
, 0},
580 /* with one expression */
581 { N_("Cell value is = x."), GNM_STYLE_COND_EQUAL
, 1},
582 { N_("Cell value is \xe2\x89\xa0 x."), GNM_STYLE_COND_NOT_EQUAL
, 1},
583 { N_("Cell value is > x."), GNM_STYLE_COND_GT
, 1},
584 { N_("Cell value is < x."), GNM_STYLE_COND_LT
, 1},
585 { N_("Cell value is \xe2\x89\xa7 x."), GNM_STYLE_COND_GTE
, 1},
586 { N_("Cell value is \xe2\x89\xa6 x."), GNM_STYLE_COND_LTE
, 1},
587 { N_("Expression x evaluates to TRUE."), GNM_STYLE_COND_CUSTOM
, 1},
588 { N_("Cell contains the string x."), GNM_STYLE_COND_CONTAINS_STR
, 1},
589 { N_("Cell does not contain the string x."), GNM_STYLE_COND_NOT_CONTAINS_STR
, 1},
590 { N_("Cell value begins with the string x."), GNM_STYLE_COND_BEGINS_WITH_STR
, 1},
591 { N_("Cell value does not begin with the string x."), GNM_STYLE_COND_NOT_BEGINS_WITH_STR
, 1},
592 { N_("Cell value ends with the string x."), GNM_STYLE_COND_ENDS_WITH_STR
, 1},
593 { N_("Cell value does not end with the string x."), GNM_STYLE_COND_NOT_ENDS_WITH_STR
, 1},
594 /* with two expressions */
595 { N_("Cell value is between x and y (incl.)."), GNM_STYLE_COND_BETWEEN
, 2},
596 { N_("Cell value is not between x and y (incl.)."), GNM_STYLE_COND_NOT_BETWEEN
, 2}
599 GtkCellRenderer
*cell
;
602 for (i
= 0; i
< G_N_ELEMENTS (cond_types
); i
++)
603 gtk_list_store_insert_with_values (state
->editor
.typestore
,
605 0, _(cond_types
[i
].label
),
606 1, cond_types
[i
].type
,
607 2, cond_types
[i
].n_expressions
,
609 cell
= gtk_cell_renderer_text_new();
610 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(state
->editor
.combo
), cell
, TRUE
);
611 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(state
->editor
.combo
), cell
, "text", 0, NULL
);
612 if (gtk_tree_model_get_iter_first
613 (GTK_TREE_MODEL (state
->editor
.typestore
), &iter
))
614 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (state
->editor
.combo
), &iter
);
618 /*****************************************************************************/
619 /*****************************************************************************/
621 c_fmt_dialog_condition_setter (SheetView
*sv
, GnmRange
const *range
, CFormatState
*state
)
623 GnmSheetRange
*sr
= g_new (GnmSheetRange
, 1);
625 sr
->sheet
= sv
->sheet
;
626 state
->action
.redo
= go_undo_combine
628 sheet_apply_style_undo (sr
, state
->action
.new_style
));
629 sr
= g_new (GnmSheetRange
, 1);
631 sr
->sheet
= sv
->sheet
;
632 state
->action
.undo
= go_undo_combine
633 (sheet_apply_style_undo (sr
, state
->action
.old_style
),
635 state
->action
.size
++;
640 c_fmt_dialog_condition_setter_tiled (G_GNUC_UNUSED SheetView
*sv
, GnmRange
const *range
,
643 GnmStyleList
*l
, *list
;
644 if (state
->action
.existing_conds_only
)
645 list
= sheet_style_collect_conditions (state
->sheet
, range
);
647 list
= sheet_style_get_range (state
->sheet
, range
);
648 for (l
= list
; l
!= NULL
; l
= l
->next
) {
649 GnmStyleConditions
*old_cond
;
650 GnmStyleRegion
const *sr
= l
->data
;
651 GnmRange r
= *((GnmRange
*) l
->data
);
653 r
.start
.row
+= range
->start
.row
;
654 r
.end
.row
+= range
->start
.row
;
655 r
.start
.col
+= range
->start
.col
;
656 r
.end
.col
+= range
->start
.col
;
657 state
->action
.old_style
= gnm_style_new ();
658 if (gnm_style_is_element_set (sr
->style
, MSTYLE_CONDITIONS
) &&
659 NULL
!= (old_cond
= gnm_style_get_conditions (sr
->style
)))
660 gnm_style_set_conditions (state
->action
.old_style
,
661 g_object_ref (old_cond
));
663 gnm_style_set_conditions (state
->action
.old_style
, NULL
);
664 c_fmt_dialog_condition_setter (state
->sv
, &r
, state
);
665 gnm_style_unref (state
->action
.old_style
);
666 state
->action
.old_style
= NULL
;
668 style_list_free (list
);
673 c_fmt_dialog_set_conditions (CFormatState
*state
, char const *cmd_label
)
675 GnmStyleConditions
*old_cond
;
677 state
->action
.undo
= NULL
;
678 state
->action
.redo
= NULL
;
679 state
->action
.size
= 0;
681 if (state
->homogeneous
) {
682 state
->action
.old_style
= gnm_style_new ();
683 old_cond
= gnm_style_get_conditions (state
->style
);
684 gnm_style_set_conditions (state
->action
.old_style
,
685 old_cond
? g_object_ref (old_cond
) : NULL
);
687 sv_selection_foreach (state
->sv
,
688 (GnmSelectionFunc
)c_fmt_dialog_condition_setter
,
691 sv_selection_foreach (state
->sv
,
692 (GnmSelectionFunc
)c_fmt_dialog_condition_setter_tiled
,
695 cmd_generic_with_size (GNM_WBC (state
->wbcg
), cmd_label
,
696 state
->action
.size
, state
->action
.undo
, state
->action
.redo
);
698 state
->action
.undo
= NULL
;
699 state
->action
.redo
= NULL
;
700 if (state
->action
.old_style
) {
701 gnm_style_unref (state
->action
.old_style
);
702 state
->action
.old_style
= NULL
;
707 c_fmt_dialog_apply_add_choice (CFormatState
*state
, GnmStyleCond
*cond
, gboolean add
)
710 GnmStyleConditions
*sc
;
712 sc
= gnm_style_conditions_dup (gnm_style_get_conditions (state
->style
));
714 sc
= gnm_style_conditions_new (state
->sheet
);
717 if (gtk_tree_selection_get_selected (state
->selection
, NULL
, &iter
)) {
718 GtkTreePath
*path
= gtk_tree_model_get_path
719 (GTK_TREE_MODEL (state
->model
), &iter
);
720 gint
*ind
= gtk_tree_path_get_indices (path
);
722 gnm_style_conditions_delete (sc
, *ind
);
725 gtk_tree_path_free (path
);
728 gnm_style_conditions_insert (sc
, cond
, index
);
729 state
->action
.new_style
= gnm_style_new ();
730 gnm_style_set_conditions (state
->action
.new_style
, sc
);
731 state
->action
.existing_conds_only
= FALSE
;
733 c_fmt_dialog_set_conditions (state
, _("Set conditional formatting"));
735 gnm_style_unref (state
->action
.new_style
);
736 state
->action
.new_style
= NULL
;
738 c_fmt_dialog_load (state
);
743 cb_c_fmt_dialog_clear_clicked (G_GNUC_UNUSED GtkButton
*button
, CFormatState
*state
)
745 state
->action
.new_style
= gnm_style_new ();
746 gnm_style_set_conditions (state
->action
.new_style
, NULL
);
747 state
->action
.existing_conds_only
= TRUE
;
749 c_fmt_dialog_set_conditions (state
, _("Clear conditional formatting"));
751 gnm_style_unref (state
->action
.new_style
);
752 state
->action
.new_style
= NULL
;
754 c_fmt_dialog_load (state
);
758 cb_c_fmt_dialog_remove_clicked (GtkButton
*button
, CFormatState
*state
)
760 if (1 == gtk_tree_model_iter_n_children (GTK_TREE_MODEL (state
->model
), NULL
))
761 cb_c_fmt_dialog_clear_clicked (button
, state
);
764 if (gtk_tree_selection_get_selected (state
->selection
, NULL
, &iter
)) {
765 GtkTreePath
*path
= gtk_tree_model_get_path
766 (GTK_TREE_MODEL (state
->model
), &iter
);
767 gint
*ind
= gtk_tree_path_get_indices (path
);
769 GnmStyleConditions
*sc
;
770 sc
= gnm_style_conditions_dup
771 (gnm_style_get_conditions (state
->style
));
773 gnm_style_conditions_delete (sc
, *ind
);
774 state
->action
.new_style
= gnm_style_new ();
775 gnm_style_set_conditions
776 (state
->action
.new_style
, sc
);
777 state
->action
.existing_conds_only
= TRUE
;
779 c_fmt_dialog_set_conditions
781 _("Remove condition from conditional "
784 gnm_style_unref (state
->action
.new_style
);
785 state
->action
.new_style
= NULL
;
787 c_fmt_dialog_load (state
);
790 gtk_tree_path_free (path
);
796 cb_c_fmt_dialog_expand_clicked (G_GNUC_UNUSED GtkButton
*button
, CFormatState
*state
)
799 if (!state
->homogeneous
&& gtk_tree_selection_get_selected (state
->selection
, NULL
, &iter
)) {
800 GnmStyleConditions
*sc
;
801 gtk_tree_model_get (GTK_TREE_MODEL (state
->model
),
803 CONDITIONS_REFERENCE
, &sc
,
806 state
->action
.new_style
= gnm_style_new ();
807 gnm_style_set_conditions
808 (state
->action
.new_style
, sc
);
809 state
->action
.existing_conds_only
= FALSE
;
811 c_fmt_dialog_set_conditions
813 _("Expand conditional formatting"));
815 gnm_style_unref (state
->action
.new_style
);
816 state
->action
.new_style
= NULL
;
818 c_fmt_dialog_load (state
);
824 c_fmt_dialog_conditions_page_load_cond_single_f (CFormatState
*state
,
825 GnmExprTop
const *texpr
, GtkTreeIter
*iter1
)
831 gtk_tree_store_append (state
->model
, &iter2
, iter1
);
833 parse_pos_init_editpos (&pp
, state
->sv
);
835 formula
= gnm_expr_top_as_string (texpr
, &pp
, gnm_conventions_default
);
836 gtk_tree_store_set (state
->model
, &iter2
, CONDITIONS_RANGE
, NULL
,
837 CONDITIONS_COND
, formula
, CONDITIONS_REFERENCE
, NULL
, -1);
843 c_fmt_dialog_conditions_page_load_cond_double_f (CFormatState
*state
,
844 GnmStyleCond
const *cond
, GtkTreeIter
*iter1
)
846 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), iter1
);
847 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 1), iter1
);
851 c_fmt_dialog_conditions_page_load_cond (CFormatState
*state
, GnmStyleCond
const *cond
,
856 gtk_tree_store_append (state
->model
, &iter1
, iter
);
859 case GNM_STYLE_COND_BETWEEN
:
860 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
862 _("If the cell content is between these "
863 "two values, a special style is used."),
864 CONDITIONS_REFERENCE
, NULL
, -1);
865 c_fmt_dialog_conditions_page_load_cond_double_f (state
, cond
, &iter1
);
867 case GNM_STYLE_COND_NOT_BETWEEN
:
868 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
870 _("If the cell content is not between these"
871 " two values, a special style is used."),
872 CONDITIONS_REFERENCE
, NULL
, -1);
873 c_fmt_dialog_conditions_page_load_cond_double_f (state
, cond
, &iter1
);
875 case GNM_STYLE_COND_EQUAL
:
876 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
878 _("If the cell content is equal to this value"
879 ", a special style is used."),
880 CONDITIONS_REFERENCE
, NULL
, -1);
881 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
883 case GNM_STYLE_COND_NOT_EQUAL
:
884 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
886 _("If the cell content is not equal to this value"
887 ", a special style is used."),
888 CONDITIONS_REFERENCE
, NULL
, -1);
889 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
891 case GNM_STYLE_COND_GT
:
892 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
894 _("If the cell content is > this value, a "
895 "special style is used."), -1);
896 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
898 case GNM_STYLE_COND_LT
:
899 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
901 _("If the cell content is < this value, a "
902 "special style is used."),
903 CONDITIONS_REFERENCE
, NULL
, -1);
904 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
906 case GNM_STYLE_COND_GTE
:
907 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
909 _("If the cell content is \xe2\x89\xa7 this "
910 "value, a special style is used."),
911 CONDITIONS_REFERENCE
, NULL
, -1);
913 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
915 case GNM_STYLE_COND_LTE
:
916 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
918 _("If the cell content is \xe2\x89\xa6 this "
919 "value, a special style is used."),
920 CONDITIONS_REFERENCE
, NULL
, -1);
921 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
924 case GNM_STYLE_COND_CUSTOM
:
925 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
927 _("If this formula evaluates to TRUE, a special style is used."),
928 CONDITIONS_REFERENCE
, NULL
, -1);
929 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
931 case GNM_STYLE_COND_CONTAINS_STR
:
932 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
934 _("If the cell content contains this string"
935 ", a special style is used."),
936 CONDITIONS_REFERENCE
, NULL
, -1);
937 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
939 case GNM_STYLE_COND_NOT_CONTAINS_STR
:
940 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
942 _("If the cell content does not contain this string"
943 ", a special style is used."),
944 CONDITIONS_REFERENCE
, NULL
, -1);
945 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
947 case GNM_STYLE_COND_BEGINS_WITH_STR
:
948 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
950 _("If the cell content begins with this string"
951 ", a special style is used."),
952 CONDITIONS_REFERENCE
, NULL
, -1);
953 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
955 case GNM_STYLE_COND_NOT_BEGINS_WITH_STR
:
956 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
958 _("If the cell content does not begin with this string,"
959 " a special style is used."), -1);
960 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
962 case GNM_STYLE_COND_ENDS_WITH_STR
:
963 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
965 _("If the cell content ends with this string"
966 ", a special style is used."),
967 CONDITIONS_REFERENCE
, NULL
, -1);
968 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
970 case GNM_STYLE_COND_NOT_ENDS_WITH_STR
:
971 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
973 _("If the cell content does not end "
974 "with this string, a special style is used."),
975 CONDITIONS_REFERENCE
, NULL
, -1);
976 c_fmt_dialog_conditions_page_load_cond_single_f (state
, gnm_style_cond_get_expr (cond
, 0), &iter1
);
978 case GNM_STYLE_COND_CONTAINS_ERR
:
979 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
981 _("If the cell contains an error "
982 "value, a special style is used."), -1);
984 case GNM_STYLE_COND_NOT_CONTAINS_ERR
:
985 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
987 _("If the cell does not contain an error value"
988 ", a special style is used."),
989 CONDITIONS_REFERENCE
, NULL
, -1);
991 case GNM_STYLE_COND_CONTAINS_BLANKS
:
992 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
994 _("If the cell content "
995 "contains blanks, a special style is used."),
996 CONDITIONS_REFERENCE
, NULL
, -1);
998 case GNM_STYLE_COND_NOT_CONTAINS_BLANKS
:
999 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
1001 _("If the cell content does not contain blanks"
1002 ", a special style is used."),
1003 CONDITIONS_REFERENCE
, NULL
, -1);
1006 gtk_tree_store_set (state
->model
, &iter1
, CONDITIONS_RANGE
, NULL
,
1008 _("This is an unknown condition type."),
1009 CONDITIONS_REFERENCE
, NULL
, -1);
1015 c_fmt_dialog_conditions_page_load_conditions (GnmStyle
*style
, char const *range
, CFormatState
*state
)
1017 GnmStyleConditions
const *sc
;
1018 GPtrArray
const *conds
;
1020 GtkTreeIter iter1
, *iter
;
1022 if (gnm_style_is_element_set (style
, MSTYLE_CONDITIONS
) &&
1023 NULL
!= (sc
= gnm_style_get_conditions (style
)) &&
1024 NULL
!= (conds
= gnm_style_conditions_details (sc
))) {
1029 gtk_tree_store_append (state
->model
, iter
, NULL
);
1030 gtk_tree_store_set (state
->model
, iter
, CONDITIONS_RANGE
, range
,
1031 CONDITIONS_COND
, NULL
,
1032 CONDITIONS_REFERENCE
, sc
, -1);
1034 for (i
= 0 ; i
< conds
->len
; i
++)
1035 c_fmt_dialog_conditions_page_load_cond
1036 (state
, g_ptr_array_index (conds
, i
), iter
);
1042 c_fmt_dialog_condition_collector (G_GNUC_UNUSED SheetView
*sv
, GnmRange
const *range
,
1045 CFormatState
*state
= user_data
;
1046 GnmStyleList
*l
, *list
= sheet_style_collect_conditions (state
->sheet
, range
);
1048 for (l
= list
; l
!= NULL
; l
= l
->next
) {
1049 GnmStyleRegion
const *sr
= l
->data
;
1050 GnmRange r
= *((GnmRange
*) l
->data
);
1051 r
.start
.row
+= range
->start
.row
;
1052 r
.end
.row
+= range
->start
.row
;
1053 r
.start
.col
+= range
->start
.col
;
1054 r
.end
.col
+= range
->start
.col
;
1055 c_fmt_dialog_conditions_page_load_conditions
1056 (sr
->style
, range_as_string (&r
), state
);
1059 style_list_free (list
);
1065 c_fmt_dialog_selection_type (SheetView
*sv
,
1066 GnmRange
const *range
,
1069 GnmBorder
*borders
[GNM_STYLE_BORDER_EDGE_MAX
] = {NULL
};
1070 CFormatState
*state
= user_data
;
1072 GSList
*merged
= gnm_sheet_merge_get_overlap (sv
->sheet
, range
);
1073 GnmRange r
= *range
;
1074 gboolean allow_multi
=
1076 merged
->next
!= NULL
||
1077 !range_equal ((GnmRange
*)merged
->data
, range
);
1080 g_slist_free (merged
);
1082 /* allow_multi == FALSE && !is_singleton (range) means that we are in
1083 * an merge cell, use only the top left */
1085 if (r
.start
.col
!= r
.end
.col
)
1086 r
.end
.col
= r
.start
.col
;
1087 if (range
->start
.row
!= range
->end
.row
)
1088 r
.end
.row
= r
.start
.row
;
1091 state
->conflicts
= sheet_style_find_conflicts (state
->sheet
, &r
,
1092 &(state
->style
), borders
);
1094 for (i
= GNM_STYLE_BORDER_TOP
; i
< GNM_STYLE_BORDER_EDGE_MAX
; i
++) {
1095 gnm_style_border_unref (borders
[i
]);
1102 c_fmt_dialog_load (CFormatState
*state
)
1104 gtk_tree_store_clear (state
->model
);
1106 gnm_style_unref (state
->style
);
1107 state
->style
= NULL
;
1109 (void) sv_selection_foreach (state
->sv
,
1110 c_fmt_dialog_selection_type
, state
);
1112 state
->homogeneous
= !(state
->conflicts
& (1 << MSTYLE_CONDITIONS
));
1114 if (state
->homogeneous
) {
1115 gtk_label_set_markup (state
->label
,
1116 _("The selection is homogeneous with "
1117 "respect to conditions."));
1118 if (state
->style
!= NULL
)
1119 c_fmt_dialog_conditions_page_load_conditions
1120 (state
->style
, NULL
, state
);
1121 gtk_tree_view_expand_all (state
->treeview
);
1123 gtk_label_set_markup (state
->label
,
1124 _("The selection is <b>not</b> "
1126 "with respect to conditions!"));
1127 (void) sv_selection_foreach (state
->sv
,
1128 c_fmt_dialog_condition_collector
, state
);
1130 gtk_tree_view_column_queue_resize
1131 (gtk_tree_view_get_column (state
->treeview
, CONDITIONS_RANGE
));
1132 c_fmt_dialog_set_sensitive (state
);
1136 cb_selection_changed (G_GNUC_UNUSED GtkTreeSelection
*treeselection
, CFormatState
*state
)
1138 c_fmt_dialog_set_sensitive (state
);
1142 cb_can_select (G_GNUC_UNUSED GtkTreeSelection
*selection
,
1143 G_GNUC_UNUSED GtkTreeModel
*model
,
1145 gboolean path_currently_selected
,
1146 G_GNUC_UNUSED CFormatState
*state
)
1148 if (path_currently_selected
)
1151 return (gtk_tree_path_get_depth (path
) == 1);
1155 cb_c_format_dialog_range (G_GNUC_UNUSED SheetView
*sv
, GnmRange
const *range
, GString
*str
)
1157 g_string_append (str
, range_as_string (range
));
1158 g_string_append (str
, ", ");
1163 c_fmt_dialog_init_editor_page (CFormatState
*state
)
1167 state
->editor
.add_button
= go_gtk_builder_get_widget (state
->gui
, "add-button");
1168 state
->editor
.replace_button
= go_gtk_builder_get_widget (state
->gui
, "replace-button");
1169 state
->editor
.copy_button
= go_gtk_builder_get_widget (state
->gui
, "copy-button");
1170 state
->editor
.edit_style_button
= go_gtk_builder_get_widget (state
->gui
, "edit-style-button");
1171 state
->editor
.combo
= go_gtk_builder_get_widget (state
->gui
, "condition-combo");
1172 grid
= GTK_GRID (go_gtk_builder_get_widget (state
->gui
, "condition-grid"));
1173 state
->editor
.expr_x
= GTK_WIDGET (gnm_expr_entry_new (state
->wbcg
, TRUE
));
1174 gtk_grid_attach (grid
, state
->editor
.expr_x
, 1, 2, 2, 1);
1175 gtk_widget_set_hexpand (state
->editor
.expr_x
, TRUE
);
1176 gtk_widget_show(state
->editor
.expr_x
);
1177 gnm_expr_entry_set_flags (GNM_EXPR_ENTRY (state
->editor
.expr_x
),
1178 GNM_EE_SHEET_OPTIONAL
|
1179 GNM_EE_CONSTANT_ALLOWED
,
1182 state
->editor
.expr_y
= GTK_WIDGET (gnm_expr_entry_new (state
->wbcg
, TRUE
));
1183 gtk_grid_attach (grid
, state
->editor
.expr_y
, 1, 3, 2, 1);
1184 gtk_widget_set_hexpand (state
->editor
.expr_y
, TRUE
);
1185 gtk_widget_show(state
->editor
.expr_y
);
1186 gnm_expr_entry_set_flags (GNM_EXPR_ENTRY (state
->editor
.expr_y
),
1187 GNM_EE_SHEET_OPTIONAL
|
1188 GNM_EE_CONSTANT_ALLOWED
,
1191 state
->editor
.typestore
= GTK_LIST_STORE (gtk_combo_box_get_model
1192 (GTK_COMBO_BOX (state
->editor
.combo
)));
1193 c_fmt_dialog_chooser_load_combo (state
);
1195 state
->editor
.style_label
= go_gtk_builder_get_widget (state
->gui
, "style-label");
1196 gtk_label_set_text (GTK_LABEL (state
->editor
.style_label
), _("(undefined)"));
1198 c_fmt_dialog_set_expr_sensitive (state
);
1200 g_signal_connect (G_OBJECT (state
->editor
.add_button
),
1202 G_CALLBACK (cb_c_fmt_dialog_add_button
), state
);
1203 g_signal_connect (G_OBJECT (state
->editor
.replace_button
),
1205 G_CALLBACK (cb_c_fmt_dialog_replace_button
), state
);
1206 g_signal_connect (G_OBJECT (state
->editor
.copy_button
),
1208 G_CALLBACK (cb_c_fmt_dialog_copy_button
), state
);
1209 g_signal_connect (G_OBJECT (state
->editor
.edit_style_button
),
1211 G_CALLBACK (cb_c_fmt_dialog_edit_style_button
), state
);
1212 g_signal_connect (G_OBJECT (state
->editor
.combo
),
1214 G_CALLBACK (cb_c_fmt_dialog_chooser_type_changed
), state
);
1215 g_signal_connect (G_OBJECT (gnm_expr_entry_get_entry (GNM_EXPR_ENTRY (state
->editor
.expr_x
))),
1217 G_CALLBACK (cb_c_fmt_dialog_chooser_entry_changed
), state
);
1218 g_signal_connect (G_OBJECT (gnm_expr_entry_get_entry (GNM_EXPR_ENTRY (state
->editor
.expr_y
))),
1220 G_CALLBACK (cb_c_fmt_dialog_chooser_entry_changed
), state
);
1225 c_fmt_dialog_init_conditions_page (CFormatState
*state
)
1227 GtkTreeViewColumn
* column
;
1228 GtkCellRenderer
*renderer
;
1232 g_return_if_fail (state
!= NULL
);
1234 state
->remove
= GTK_BUTTON (go_gtk_builder_get_widget (state
->gui
,
1235 "conditions_remove"));
1236 gtk_widget_set_sensitive (GTK_WIDGET (state
->remove
), FALSE
);
1237 state
->clear
= GTK_BUTTON (go_gtk_builder_get_widget (state
->gui
,
1238 "conditions_clear"));
1239 gtk_widget_set_sensitive (GTK_WIDGET (state
->clear
), FALSE
);
1240 state
->expand
= GTK_BUTTON (go_gtk_builder_get_widget (state
->gui
,
1241 "conditions_expand"));
1242 gtk_widget_set_sensitive (GTK_WIDGET (state
->expand
), FALSE
);
1244 state
->model
= gtk_tree_store_new (CONDITIONS_NUM_COLUMNS
,
1248 state
->treeview
= GTK_TREE_VIEW (go_gtk_builder_get_widget
1249 (state
->gui
, "conditions_treeview"));
1250 gtk_tree_view_set_fixed_height_mode (state
->treeview
, FALSE
);
1251 gtk_tree_view_set_model (state
->treeview
, GTK_TREE_MODEL (state
->model
));
1252 g_object_unref (state
->model
);
1253 state
->selection
= gtk_tree_view_get_selection (state
->treeview
);
1254 gtk_tree_selection_set_mode (state
->selection
, GTK_SELECTION_SINGLE
);
1255 gtk_tree_selection_set_select_function (state
->selection
,
1256 (GtkTreeSelectionFunc
) cb_can_select
,
1258 renderer
= gtk_cell_renderer_text_new ();
1259 column
= gtk_tree_view_column_new_with_attributes
1260 ("Range", renderer
, "text", CONDITIONS_RANGE
, NULL
);
1261 gtk_tree_view_insert_column (state
->treeview
, column
, -1);
1262 renderer
= gtk_cell_renderer_text_new ();
1263 column
= gtk_tree_view_column_new_with_attributes
1264 ("Conditions", renderer
, "text", CONDITIONS_COND
, NULL
);
1265 gtk_tree_view_insert_column (state
->treeview
, column
, -1);
1266 gtk_tree_view_set_expander_column (state
->treeview
, column
);
1268 state
->label
= GTK_LABEL (go_gtk_builder_get_widget (state
->gui
,
1269 "conditions_label"));
1270 hl
= GTK_LABEL (go_gtk_builder_get_widget (state
->gui
, "header-label"));
1271 gtk_label_set_ellipsize (hl
, PANGO_ELLIPSIZE_END
);
1272 str
= g_string_new (_("Editing conditional formatting: "));
1273 sv_selection_foreach (state
->sv
,
1274 (GnmSelectionFunc
)cb_c_format_dialog_range
,
1276 g_string_truncate (str
, str
->len
-2);
1277 gtk_label_set_text(hl
, str
->str
);
1278 g_string_free (str
, TRUE
);
1280 g_signal_connect (G_OBJECT (state
->selection
), "changed",
1281 G_CALLBACK (cb_selection_changed
), state
);
1282 g_signal_connect (G_OBJECT (state
->remove
), "clicked",
1283 G_CALLBACK (cb_c_fmt_dialog_remove_clicked
), state
);
1284 g_signal_connect (G_OBJECT (state
->clear
), "clicked",
1285 G_CALLBACK (cb_c_fmt_dialog_clear_clicked
), state
);
1286 g_signal_connect (G_OBJECT (state
->expand
), "clicked",
1287 G_CALLBACK (cb_c_fmt_dialog_expand_clicked
), state
);
1290 /*****************************************************************************/
1294 dialog_cell_format_cond (WBCGtk
*wbcg
)
1297 CFormatState
*state
;
1300 g_return_if_fail (wbcg
!= NULL
);
1302 gui
= gnm_gtk_builder_load ("res:ui/cell-format-cond.ui", NULL
, GO_CMD_CONTEXT (wbcg
));
1307 state
= g_new (CFormatState
, 1);
1310 state
->sv
= wb_control_cur_sheet_view (GNM_WBC (wbcg
));
1311 state
->sheet
= sv_sheet (state
->sv
);
1312 state
->style
= NULL
;
1313 state
->editor
.style
= NULL
;
1314 state
->editor
.dialog
= NULL
;
1316 dialog
= go_gtk_builder_get_widget (state
->gui
, "CellFormat");
1317 g_return_if_fail (dialog
!= NULL
);
1319 gtk_window_set_title (GTK_WINDOW (dialog
), _("Conditional Cell Formatting"));
1322 state
->dialog
= GTK_DIALOG (dialog
);
1324 c_fmt_dialog_init_conditions_page (state
);
1325 c_fmt_dialog_init_editor_page (state
);
1327 c_fmt_dialog_load (state
);
1329 gnm_init_help_button (
1330 go_gtk_builder_get_widget (state
->gui
, "helpbutton"),
1331 GNUMERIC_HELP_LINK_CELL_FORMAT_COND
);
1333 state
->close_button
= go_gtk_builder_get_widget (state
->gui
, "closebutton");
1334 g_signal_connect (G_OBJECT (state
->close_button
),
1336 G_CALLBACK (cb_c_fmt_dialog_dialog_buttons
), state
);
1338 gnm_dialog_setup_destroy_handlers (GTK_DIALOG (dialog
), state
->wbcg
,
1339 GNM_DIALOG_DESTROY_CURRENT_SHEET_REMOVED
);
1341 /* a candidate for merging into attach guru */
1342 wbc_gtk_attach_guru (state
->wbcg
, GTK_WIDGET (state
->dialog
));
1343 g_object_set_data_full (G_OBJECT (state
->dialog
),
1344 "state", state
, (GDestroyNotify
)cb_c_fmt_dialog_dialog_destroy
);
1345 g_signal_connect (G_OBJECT (dialog
), "destroy",
1346 G_CALLBACK (cb_dialog_destroy
), NULL
);
1348 gnm_restore_window_geometry (GTK_WINDOW (state
->dialog
),
1351 go_gtk_nonmodal_dialog (wbcg_toplevel (state
->wbcg
),
1352 GTK_WINDOW (state
->dialog
));
1354 gtk_widget_show (GTK_WIDGET (state
->dialog
));