Update Spanish translation
[gnumeric.git] / src / sheet-view.c
blobe4d3cd7abbd3f34ffb647682251353f2655ce6cb
1 /*
2 * sheet-view.c:
4 * Copyright (C) 2002-2006 Jody Goldberg (jody@gnome.org)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) version 3.
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, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19 * USA
22 #include <gnumeric-config.h>
23 #include <glib/gi18n-lib.h>
24 #include <stdlib.h>
25 #include <gnumeric.h>
27 #include <sheet-view.h>
28 #include <sheet.h>
29 #include <sheet-merge.h>
30 #include <sheet-filter.h>
31 #include <gnm-sheet-slicer.h>
32 #include <sheet-private.h>
33 #include <sheet-control.h>
34 #include <sheet-control-priv.h>
35 #include <workbook-view.h>
36 #include <workbook-control.h>
37 #include <ranges.h>
38 #include <selection.h>
39 #include <application.h>
40 #include <value.h>
41 #include <parse-util.h>
42 #include <expr-name.h>
43 #include <command-context.h>
44 #include <gnumeric-conf.h>
45 #include <sheet-style.h>
46 #include <mstyle.h>
47 #include <gutils.h>
49 #include <gsf/gsf-impl-utils.h>
51 #define GNM_SHEET_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GNM_SHEET_VIEW_TYPE, SheetViewClass))
52 static GObjectClass *parent_class;
54 /*************************************************************************/
56 static void
57 auto_expr_timer_clear (SheetView *sv)
59 if (sv->auto_expr_timer != 0) {
60 g_source_remove (sv->auto_expr_timer);
61 sv->auto_expr_timer = 0;
65 static gboolean
66 cb_update_auto_expr (gpointer data)
68 SheetView *sv = (SheetView *) data;
70 if (wb_view_cur_sheet_view (sv->sv_wbv) == sv)
71 wb_view_auto_expr_recalc (sv->sv_wbv);
73 sv->auto_expr_timer = 0;
74 return FALSE;
77 /*************************************************************************/
79 static void
80 sv_sheet_name_changed (G_GNUC_UNUSED Sheet *sheet,
81 G_GNUC_UNUSED GParamSpec *pspec,
82 SheetView *sv)
84 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
85 sv->edit_pos_changed.content = TRUE;
88 static void
89 sv_sheet_visibility_changed (Sheet *sheet,
90 G_GNUC_UNUSED GParamSpec *pspec,
91 SheetView *sv)
93 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
94 /* See bug 366477. */
95 if (sheet_is_visible (sheet) && !wb_view_cur_sheet (sv->sv_wbv))
96 wb_view_sheet_focus (sv->sv_wbv, sheet);
99 static void
100 sv_sheet_r1c1_changed (G_GNUC_UNUSED Sheet *sheet,
101 G_GNUC_UNUSED GParamSpec *pspec,
102 SheetView *sv)
104 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
105 sv->edit_pos_changed.location = TRUE;
109 * sv_sheet:
110 * @sv: #SheetView
112 * Returns: (transfer none): the sheet.
114 Sheet *
115 sv_sheet (SheetView const *sv)
117 g_return_val_if_fail (GNM_IS_SHEET_VIEW (sv), NULL);
118 return sv->sheet;
122 * sv_wbv:
123 * @sv: #SheetView
125 * Returns: (transfer none): the workbook view.
127 WorkbookView *
128 sv_wbv (SheetView const *sv)
130 g_return_val_if_fail (GNM_IS_SHEET_VIEW (sv), NULL);
131 return sv->sv_wbv;
134 static void
135 sv_init_sc (SheetView const *sv, SheetControl *sc)
137 GnmCellPos initial;
139 sc_scale_changed (sc);
141 /* set_panes will change the initial so cache it */
142 initial = sv->initial_top_left;
143 sc_set_panes (sc);
145 /* And this will restore it */
146 sc_set_top_left (sc, initial.col, initial.row);
147 sc_scrollbar_config (sc);
149 /* Set the visible bound, not the logical bound */
150 sc_cursor_bound (sc, selection_first_range (sv, NULL, NULL));
151 sc_ant (sc);
154 void
155 gnm_sheet_view_attach_control (SheetView *sv, SheetControl *sc)
157 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
158 g_return_if_fail (GNM_IS_SHEET_CONTROL (sc));
159 g_return_if_fail (sc->view == NULL);
161 g_ptr_array_add (sv->controls, sc);
162 sc->view = sv;
163 sv_init_sc (sv, sc);
166 void
167 gnm_sheet_view_detach_control (SheetView *sv, SheetControl *sc)
169 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
170 g_return_if_fail (GNM_IS_SHEET_CONTROL (sc));
171 g_return_if_fail (sv == sc->view);
173 g_ptr_array_remove (sv->controls, sc);
174 sc->view = NULL;
177 static void
178 sv_weakref_notify (SheetView **ptr, GObject *sv)
180 g_return_if_fail (ptr != NULL);
181 g_return_if_fail (*ptr == (SheetView *)sv); /* remember sv is dead */
182 *ptr = NULL;
185 void
186 gnm_sheet_view_weak_ref (SheetView *sv, SheetView **ptr)
188 g_return_if_fail (ptr != NULL);
190 *ptr = sv;
191 if (sv != NULL)
192 g_object_weak_ref (G_OBJECT (sv),
193 (GWeakNotify) sv_weakref_notify,
194 ptr);
197 void
198 gnm_sheet_view_weak_unref (SheetView **ptr)
200 g_return_if_fail (ptr != NULL);
202 if (*ptr != NULL) {
203 g_object_weak_unref (G_OBJECT (*ptr),
204 (GWeakNotify) sv_weakref_notify,
205 ptr);
206 *ptr = NULL;
210 static void
211 sv_finalize (GObject *object)
213 SheetView *sv = GNM_SHEET_VIEW (object);
214 g_ptr_array_free (sv->controls, TRUE);
215 parent_class->finalize (object);
218 static void
219 sv_real_dispose (GObject *object)
221 SheetView *sv = GNM_SHEET_VIEW (object);
223 while (sv->controls->len > 0) {
224 SheetControl *control =
225 g_ptr_array_index (sv->controls,
226 sv->controls->len - 10);
227 gnm_sheet_view_detach_control (sv, control);
228 g_object_unref (control);
231 if (sv->sheet) {
232 Sheet *sheet = sv->sheet;
233 sv->sheet = NULL;
234 g_ptr_array_remove (sheet->sheet_views, sv);
235 g_signal_handlers_disconnect_by_func (sheet, sv_sheet_name_changed, sv);
236 g_signal_handlers_disconnect_by_func (sheet, sv_sheet_visibility_changed, sv);
237 g_signal_handlers_disconnect_by_func (sheet, sv_sheet_r1c1_changed, sv);
238 g_object_unref (sv);
239 g_object_unref (sheet);
242 gnm_sheet_view_unant (sv);
243 sv_selection_free (sv);
244 sv_selection_simplified_free (sv);
245 auto_expr_timer_clear (sv);
247 parent_class->dispose (object);
250 static void
251 gnm_sheet_view_class_init (GObjectClass *klass)
253 SheetViewClass *wbc_class = GNM_SHEET_VIEW_CLASS (klass);
255 g_return_if_fail (wbc_class != NULL);
257 parent_class = g_type_class_peek_parent (klass);
258 klass->dispose = sv_real_dispose;
259 klass->finalize = sv_finalize;
262 static void
263 gnm_sheet_view_init (GObject *object)
265 SheetView *sv = GNM_SHEET_VIEW (object);
267 sv->controls = g_ptr_array_new ();
269 /* Init menu states */
270 sv->enable_insert_rows = TRUE;
271 sv->enable_insert_cols = TRUE;
272 sv->enable_insert_cells = TRUE;
274 sv->edit_pos_changed.location = TRUE;
275 sv->edit_pos_changed.content = TRUE;
276 sv->edit_pos_changed.style = TRUE;
277 sv->selection_content_changed = TRUE;
278 sv->reposition_selection = TRUE;
279 sv->auto_expr_timer = 0;
281 sv->frozen_top_left.col = sv->frozen_top_left.row =
282 sv->unfrozen_top_left.col = sv->unfrozen_top_left.row = -1;
283 sv->initial_top_left.col = sv->initial_top_left.row = 0;
285 sv->selections = NULL;
286 sv->selection_mode = GNM_SELECTION_MODE_ADD;
287 sv->selections_simplified = NULL;
288 sv_selection_add_pos (sv, 0, 0, GNM_SELECTION_MODE_ADD);
291 GSF_CLASS (SheetView, gnm_sheet_view,
292 gnm_sheet_view_class_init, gnm_sheet_view_init,
293 G_TYPE_OBJECT)
295 SheetView *
296 gnm_sheet_view_new (Sheet *sheet, WorkbookView *wbv)
298 SheetView *sv;
300 g_return_val_if_fail (IS_SHEET (sheet), NULL);
302 sv = g_object_new (GNM_SHEET_VIEW_TYPE, NULL);
303 sv->sheet = g_object_ref (sheet);
304 sv->sv_wbv = wbv;
305 g_ptr_array_add (sheet->sheet_views, sv);
306 g_object_ref (sv);
308 g_signal_connect (G_OBJECT (sheet),
309 "notify::name",
310 G_CALLBACK (sv_sheet_name_changed),
311 sv);
313 g_signal_connect (G_OBJECT (sheet),
314 "notify::visibility",
315 G_CALLBACK (sv_sheet_visibility_changed),
316 sv);
318 g_signal_connect (G_OBJECT (sheet),
319 "notify::use-r1c1",
320 G_CALLBACK (sv_sheet_r1c1_changed),
321 sv);
323 SHEET_VIEW_FOREACH_CONTROL (sv, control,
324 sv_init_sc (sv, control););
325 return sv;
328 void
329 gnm_sheet_view_dispose (SheetView *sv)
331 g_object_run_dispose (G_OBJECT (sv));
334 void
335 gnm_sheet_view_unant (SheetView *sv)
337 GList *ptr;
339 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
341 if (sv->ants == NULL)
342 return;
343 for (ptr = sv->ants; ptr != NULL; ptr = ptr->next)
344 g_free (ptr->data);
345 g_list_free (sv->ants);
346 sv->ants = NULL;
348 SHEET_VIEW_FOREACH_CONTROL (sv, control,
349 sc_unant (control););
353 * gnm_sheet_view_ant:
354 * @sv:
355 * @ranges: (element-type GnmRange) (transfer none): The ranges to ant.
357 void
358 gnm_sheet_view_ant (SheetView *sv, GList *ranges)
360 GList *ptr;
362 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
363 g_return_if_fail (ranges != NULL);
365 if (sv->ants != NULL)
366 gnm_sheet_view_unant (sv);
367 for (ptr = ranges; ptr != NULL; ptr = ptr->next)
368 sv->ants = g_list_prepend (sv->ants, gnm_range_dup (ptr->data));
369 sv->ants = g_list_reverse (sv->ants);
371 SHEET_VIEW_FOREACH_CONTROL (sv, control,
372 sc_ant (control););
375 void
376 gnm_sheet_view_make_cell_visible (SheetView *sv, int col, int row,
377 gboolean couple_panes)
379 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
380 SHEET_VIEW_FOREACH_CONTROL(sv, control,
381 sc_make_cell_visible (control, col, row, couple_panes););
384 void
385 gnm_sheet_view_redraw_range (SheetView *sv, GnmRange const *r)
387 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
389 SHEET_VIEW_FOREACH_CONTROL (sv, sc, sc_redraw_range (sc, r););
392 void
393 gnm_sheet_view_redraw_headers (SheetView const *sv,
394 gboolean col, gboolean row,
395 GnmRange const* r /* optional == NULL */)
397 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
399 SHEET_VIEW_FOREACH_CONTROL (sv, control,
400 sc_redraw_headers (control, col, row, r););
403 void
404 gnm_sheet_view_resize (SheetView *sv, gboolean force_scroll)
406 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
408 SHEET_VIEW_FOREACH_CONTROL (sv, control,
409 sc_resize (control, force_scroll););
413 gboolean
414 gnm_sheet_view_selection_copy (SheetView *sv, WorkbookControl *wbc)
416 GnmRange const *sel;
418 g_return_val_if_fail (GNM_IS_SHEET_VIEW (sv), FALSE);
419 if (!(sel = selection_first_range (sv, GO_CMD_CONTEXT (wbc), _("Copy"))))
420 return FALSE;
422 gnm_app_clipboard_cut_copy (wbc, FALSE, sv, sel, TRUE);
424 return TRUE;
427 gboolean
428 gnm_sheet_view_selection_cut (SheetView *sv, WorkbookControl *wbc)
430 GnmRange const *sel;
432 /* 'cut' is a poor description of what we're
433 * doing here. 'move' would be a better
434 * approximation. The key portion of this process is that
435 * the range being moved has all
436 * - references to it adjusted to the new site.
437 * - relative references from it adjusted.
439 * NOTE : This command DOES NOT MOVE ANYTHING !
440 * We only store the src, paste does the move.
442 g_return_val_if_fail (GNM_IS_SHEET_VIEW (sv), FALSE);
444 if (!(sel = selection_first_range (sv, GO_CMD_CONTEXT (wbc), _("Cut"))))
445 return FALSE;
447 if (sheet_range_splits_region (sv_sheet (sv), sel, NULL, GO_CMD_CONTEXT (wbc), _("Cut")))
448 return FALSE;
450 gnm_app_clipboard_cut_copy (wbc, TRUE, sv, sel, TRUE);
452 return TRUE;
456 * gnm_sheet_view_cursor_set:
457 * @sv: The sheet
458 * @edit:
459 * @base_col:
460 * @base_row:
461 * @move_col:
462 * @move_row:
463 * @bound: (nullable): A range that should contain all the supplied points
465 void
466 gnm_sheet_view_cursor_set (SheetView *sv,
467 GnmCellPos const *edit,
468 int base_col, int base_row,
469 int move_col, int move_row,
470 GnmRange const *bound)
472 GnmRange r;
474 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
476 /* Change the edit position */
477 gnm_sheet_view_set_edit_pos (sv, edit);
479 sv->cursor.base_corner.col = base_col;
480 sv->cursor.base_corner.row = base_row;
481 sv->cursor.move_corner.col = move_col;
482 sv->cursor.move_corner.row = move_row;
484 if (bound == NULL) {
485 if (base_col < move_col) {
486 r.start.col = base_col;
487 r.end.col = move_col;
488 } else {
489 r.end.col = base_col;
490 r.start.col = move_col;
492 if (base_row < move_row) {
493 r.start.row = base_row;
494 r.end.row = move_row;
495 } else {
496 r.end.row = base_row;
497 r.start.row = move_row;
499 bound = &r;
502 g_return_if_fail (range_is_sane (bound));
504 SHEET_VIEW_FOREACH_CONTROL(sv, control,
505 sc_cursor_bound (control, bound););
508 void
509 gnm_sheet_view_set_edit_pos (SheetView *sv, GnmCellPos const *pos)
511 GnmCellPos old;
512 GnmRange const *merged;
514 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
515 g_return_if_fail (pos != NULL);
517 old = sv->edit_pos;
518 sv->first_tab_col = -1; /* invalidate */
520 if (old.col == pos->col && old.row == pos->row)
521 return;
523 g_return_if_fail (IS_SHEET (sv->sheet));
524 g_return_if_fail (pos->col >= 0);
525 g_return_if_fail (pos->col < gnm_sheet_get_max_cols (sv->sheet));
526 g_return_if_fail (pos->row >= 0);
527 g_return_if_fail (pos->row < gnm_sheet_get_max_rows (sv->sheet));
530 merged = gnm_sheet_merge_is_corner (sv->sheet, &old);
532 sv->edit_pos_changed.location =
533 sv->edit_pos_changed.content =
534 sv->edit_pos_changed.style = TRUE;
536 /* Redraw before change */
537 if (merged == NULL) {
538 GnmRange tmp; tmp.start = tmp.end = old;
539 gnm_sheet_view_redraw_range (sv, &tmp);
540 } else
541 gnm_sheet_view_redraw_range (sv, merged);
543 sv->edit_pos_real = *pos;
545 /* Redraw after change (handling merged cells) */
546 merged = gnm_sheet_merge_contains_pos (sv->sheet, &sv->edit_pos_real);
547 if (merged == NULL) {
548 GnmRange tmp; tmp.start = tmp.end = *pos;
549 gnm_sheet_view_redraw_range (sv, &tmp);
550 sv->edit_pos = sv->edit_pos_real;
551 } else {
552 gnm_sheet_view_redraw_range (sv, merged);
553 sv->edit_pos = merged->start;
558 * gnm_sheet_view_flag_status_update_pos:
559 * @sv:
560 * @pos:
562 * flag the view as requiring an update to the status display
563 * if the supplied cell location is the edit cursor, or part of the
564 * selected region.
566 * Will cause the format toolbar, the edit area, and the auto expressions to be
567 * updated if appropriate.
569 void
570 gnm_sheet_view_flag_status_update_pos (SheetView *sv, GnmCellPos const *pos)
572 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
573 g_return_if_fail (pos != NULL);
575 /* if a part of the selected region changed value update
576 * the auto expressions
578 if (sv_is_pos_selected (sv, pos->col, pos->row))
579 sv->selection_content_changed = TRUE;
581 /* If the edit cell changes value update the edit area
582 * and the format toolbar
584 if (pos->col == sv->edit_pos.col && pos->row == sv->edit_pos.row)
585 sv->edit_pos_changed.content =
586 sv->edit_pos_changed.style = TRUE;
590 * gnm_sheet_view_flag_status_update_range:
591 * @sv:
592 * @range: (nullable): If %NULL then force an update.
594 * flag the sheet as requiring an update to the status display if the supplied
595 * cell location contains the edit cursor, or intersects of the selected region.
597 * Will cause the format toolbar, the edit area, and the auto expressions to be
598 * updated if appropriate.
600 void
601 gnm_sheet_view_flag_status_update_range (SheetView *sv, GnmRange const *range)
603 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
605 /* Force an update */
606 if (range == NULL) {
607 sv->selection_content_changed = TRUE;
608 sv->edit_pos_changed.location =
609 sv->edit_pos_changed.content =
610 sv->edit_pos_changed.style = TRUE;
611 return;
614 /* if a part of the selected region changed value update
615 * the auto expressions
617 if (sv_is_range_selected (sv, range))
618 sv->selection_content_changed = TRUE;
620 /* If the edit cell changes value update the edit area
621 * and the format toolbar
623 if (range_contains (range, sv->edit_pos.col, sv->edit_pos.row))
624 sv->edit_pos_changed.content = sv->edit_pos_changed.style = TRUE;
628 * gnm_sheet_view_flag_style_update_range:
629 * @sv: The sheet being changed
630 * @range: the range that is changing.
632 * Flag style changes that will require updating the style indicators.
634 void
635 gnm_sheet_view_flag_style_update_range (SheetView *sv, GnmRange const *range)
637 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
638 g_return_if_fail (range != NULL);
639 if (range_contains (range, sv->edit_pos.col, sv->edit_pos.row))
640 sv->edit_pos_changed.style = TRUE;
644 * gnm_sheet_view_flag_selection_change:
645 * @sv:
647 * flag the sheet as requiring an update to the status display
649 * Will cause auto expressions to be updated
651 void
652 gnm_sheet_view_flag_selection_change (SheetView *sv)
654 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
655 sv->selection_content_changed = TRUE;
658 static void
659 sheet_view_edit_pos_tool_tips (SheetView *sv)
661 GnmStyle const *style;
662 GnmInputMsg *im = NULL;
664 style = sheet_style_get (sv->sheet,
665 sv->edit_pos.col,
666 sv->edit_pos.row);
667 if (style != NULL && gnm_style_is_element_set (style, MSTYLE_INPUT_MSG))
668 im = gnm_style_get_input_msg (style);
670 /* We need to call these even with im == NULL to remove the old tooltip.*/
671 SHEET_VIEW_FOREACH_CONTROL (sv, control,
672 sc_show_im_tooltip (control, im, &sv->edit_pos););
675 void
676 gnm_sheet_view_update (SheetView *sv)
678 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
680 if (sv->edit_pos_changed.content) {
681 sv->edit_pos_changed.content = FALSE;
682 if (wb_view_cur_sheet_view (sv->sv_wbv) == sv)
683 wb_view_edit_line_set (sv->sv_wbv, NULL);
686 if (sv->edit_pos_changed.style ) {
687 sv->edit_pos_changed.style = FALSE;
688 if (wb_view_cur_sheet_view (sv->sv_wbv) == sv)
689 wb_view_style_feedback (sv->sv_wbv);
692 if (sv->edit_pos_changed.location) {
693 sv->edit_pos_changed.location = FALSE;
694 if (wb_view_cur_sheet_view (sv->sv_wbv) == sv) {
695 wb_view_selection_desc (sv->sv_wbv, TRUE, NULL);
696 SHEET_VIEW_FOREACH_CONTROL
697 (sv, sc, wb_control_menu_state_update
698 (sc_wbc (sc),
699 MS_COMMENT_LINKS | MS_PAGE_BREAKS););
700 sheet_view_edit_pos_tool_tips (sv);
704 if (sv->selection_content_changed) {
705 int const lag = gnm_conf_get_core_gui_editing_recalclag ();
706 sv->selection_content_changed = FALSE;
707 if (sv->auto_expr_timer == 0 || lag < 0) {
708 auto_expr_timer_clear (sv);
709 sv->auto_expr_timer = g_timeout_add_full (0, abs (lag), /* seems ok */
710 cb_update_auto_expr, (gpointer) sv, NULL);
712 SHEET_VIEW_FOREACH_CONTROL (sv, sc,
713 wb_control_menu_state_update (sc_wbc (sc), MS_ADD_VS_REMOVE_FILTER |
714 MS_COMMENT_LINKS_RANGE););
717 SHEET_VIEW_FOREACH_CONTROL (sv, sc,
718 wb_control_menu_state_update
719 (sc_wbc (sc), MS_SELECT_OBJECT););
724 * gnm_sheet_view_editpos_in_filter:
725 * @sv: #SheetView
727 * Returns: (nullable): #GnmFilter that overlaps the sv::edit_pos
729 GnmFilter *
730 gnm_sheet_view_editpos_in_filter (SheetView const *sv)
732 g_return_val_if_fail (GNM_IS_SHEET_VIEW (sv), NULL);
733 return gnm_sheet_filter_at_pos (sv->sheet, &sv->edit_pos);
737 * gnm_sheet_view_selection_intersects_filter_rows:
738 * @sv: #SheetView
740 * Returns: (nullable): #GnmFilter whose rows intersect the rows
741 * of the current selection.
743 GnmFilter *
744 gnm_sheet_view_selection_intersects_filter_rows (SheetView const *sv)
746 GnmRange const *r;
747 g_return_val_if_fail (GNM_IS_SHEET_VIEW (sv), NULL);
748 r = selection_first_range (sv, NULL, NULL);
750 return r ? gnm_sheet_filter_intersect_rows
751 (sv->sheet, r->start.row, r->end.row) : NULL;
755 * gnm_sheet_view_selection_extends_filter:
756 * @sv: #SheetView
758 * Returns: (nullable): #GnmFilter whose rows intersect the rows
759 * of the current selection range to which the filter can be
760 * extended.
762 GnmRange *
763 gnm_sheet_view_selection_extends_filter (SheetView const *sv,
764 GnmFilter const *f)
766 GnmRange const *r;
767 g_return_val_if_fail (GNM_IS_SHEET_VIEW (sv), NULL);
768 r = selection_first_range (sv, NULL, NULL);
770 return gnm_sheet_filter_can_be_extended (sv->sheet, f, r);
777 * gnm_sheet_view_editpos_in_slicer:
778 * @sv: #SheetView
780 * Returns: (transfer none) (nullable): #GnmSheetSlicer that overlaps the
781 * sv::edit_pos
783 GnmSheetSlicer *
784 gnm_sheet_view_editpos_in_slicer (SheetView const *sv)
786 g_return_val_if_fail (GNM_IS_SHEET_VIEW (sv), NULL);
787 return gnm_sheet_slicers_at_pos (sv->sheet, &sv->edit_pos);
791 * gnm_sheet_view_freeze_panes:
792 * @sv: the sheet
793 * @frozen_top_left: (nullable): top left corner of the frozen region
794 * @unfrozen_top_left: (nullable): top left corner of the unfrozen region
796 * By definition the unfrozen region must be below the frozen.
797 * If @frozen_top_left == @unfrozen_top_left or @frozen_top_left == NULL unfreeze
799 void
800 gnm_sheet_view_freeze_panes (SheetView *sv,
801 GnmCellPos const *frozen,
802 GnmCellPos const *unfrozen)
804 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
806 if (gnm_debug_flag ("frozen-panes")) {
807 g_printerr ("Frozen: %-10s",
808 frozen ? cellpos_as_string (frozen) : "-");
809 g_printerr ("Unfrozen: %s\n",
810 unfrozen ? cellpos_as_string (unfrozen) : "-");
813 if (frozen != NULL) {
814 g_return_if_fail (unfrozen != NULL);
815 g_return_if_fail (unfrozen->col >= frozen->col);
816 g_return_if_fail (unfrozen->row >= frozen->row);
818 /* Just in case */
819 if (unfrozen->col != gnm_sheet_get_last_col (sv->sheet) &&
820 unfrozen->row != gnm_sheet_get_last_row (sv->sheet) &&
821 !gnm_cellpos_equal (frozen, unfrozen)) {
822 sv->frozen_top_left = *frozen;
823 sv->unfrozen_top_left = *unfrozen;
824 if (sv->frozen_top_left.col == sv->unfrozen_top_left.col)
825 sv->frozen_top_left.col = sv->unfrozen_top_left.col = 0;
826 if (sv->frozen_top_left.row == sv->unfrozen_top_left.row)
827 sv->frozen_top_left.row = sv->unfrozen_top_left.row = 0;
828 } else
829 frozen = unfrozen = NULL;
832 if (frozen == NULL) {
833 g_return_if_fail (unfrozen == NULL);
835 /* no change */
836 if (sv->frozen_top_left.col < 0 &&
837 sv->frozen_top_left.row < 0 &&
838 sv->unfrozen_top_left.col < 0 &&
839 sv->unfrozen_top_left.row < 0)
840 return;
842 sv->initial_top_left = sv->frozen_top_left;
843 sv->frozen_top_left.col = sv->frozen_top_left.row =
844 sv->unfrozen_top_left.col = sv->unfrozen_top_left.row = -1;
847 SHEET_VIEW_FOREACH_CONTROL (sv, control,
848 sv_init_sc (sv, control););
850 WORKBOOK_VIEW_FOREACH_CONTROL(sv->sv_wbv, wbc,
851 wb_control_menu_state_update (wbc, MS_FREEZE_VS_THAW););
855 * gnm_sheet_view_panes_insdel_colrow:
856 * @sv:
857 * @is_cols: %TRUE for columns, %FALSE for rows.
858 * @is_insert:
859 * @start:
860 * @count:
862 * Adjust the positions of frozen panes as necessary to handle col/row
863 * insertions and deletions. note this assumes that the ins/del operations
864 * have already set the flags that will force a resize.
866 void
867 gnm_sheet_view_panes_insdel_colrow (SheetView *sv, gboolean is_cols,
868 gboolean is_insert, int start, int count)
870 GnmCellPos tl;
871 GnmCellPos br;
873 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
875 tl = sv->frozen_top_left; /* _copy_ them */
876 br = sv->unfrozen_top_left;
878 if (is_cols) {
879 /* ignore if not frozen, or acting in unfrozen region */
880 if (br.col <= tl.col || br.col <= start)
881 return;
882 if (is_insert) {
883 br.col += count;
884 if (tl.col > start)
885 tl.col += count;
886 if (br.col < tl.col || br.col >= gnm_sheet_get_max_cols (sv->sheet))
887 return;
888 } else {
889 if (tl.col >= start)
890 tl.col -= MIN (count, tl.col - start);
891 br.col -= count;
892 if (br.col <= tl.col)
893 br.col = tl.col + 1;
895 } else {
896 /* ignore if not frozen, or acting in unfrozen region */
897 if (br.row <= tl.row || br.row <= start)
898 return;
899 if (is_insert) {
900 br.row += count;
901 if (tl.row > start)
902 tl.row += count;
903 if (br.row < tl.row || br.row >= gnm_sheet_get_max_rows (sv->sheet))
904 return;
905 } else {
906 if (tl.row >= start)
907 tl.row -= MIN (count, tl.row - start);
908 br.row -= count;
909 if (br.row <= tl.row)
910 br.row = tl.row + 1;
913 gnm_sheet_view_freeze_panes (sv, &tl, &br);
916 gboolean
917 gnm_sheet_view_is_frozen (SheetView const *sv)
919 g_return_val_if_fail (GNM_IS_SHEET_VIEW (sv), FALSE);
921 /* be flexible, in the future we will support 2 way splits too */
922 return sv->unfrozen_top_left.col >= 0 ||
923 sv->unfrozen_top_left.row >= 0;
927 gnm_sheet_view_set_initial_top_left:
928 * @sv: the sheet view.
929 * @col:
930 * @row:
932 * Sets the top left cell that a newly created sheet control should display.
933 * This corresponds to the top left cell visible in pane 0 (frozen or not).
934 * NOTE : the unfrozen_top_left != initial_top_left. Unfrozen is the first
935 * unfrozen cell, and corresponds to the _minimum_ cell in pane 0. However,
936 * the pane can scroll and may have something else currently visible as the top
937 * left.
939 void
940 gnm_sheet_view_set_initial_top_left (SheetView *sv, int col, int row)
942 g_return_if_fail (GNM_IS_SHEET_VIEW (sv));
943 g_return_if_fail (0 <= col && col < gnm_sheet_get_max_cols (sv->sheet));
944 g_return_if_fail (0 <= row && row < gnm_sheet_get_max_rows (sv->sheet));
945 g_return_if_fail (!gnm_sheet_view_is_frozen (sv) ||
946 (sv->unfrozen_top_left.col <= col &&
947 sv->unfrozen_top_left.row <= row));
949 sv->initial_top_left.col = col;
950 sv->initial_top_left.row = row;