Whitespace.
[gnumeric.git] / src / sheet-view.c
blob97318d979f4ac254ce59ab62562e8f1aa61a7cba
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * sheet-view.c:
5 * Copyright (C) 2002-2006 Jody Goldberg (jody@gnome.org)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) version 3.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20 * USA
23 #include <gnumeric-config.h>
24 #include <glib/gi18n-lib.h>
25 #include <stdlib.h>
26 #include "gnumeric.h"
28 #include "sheet-view.h"
29 #include "sheet.h"
30 #include "sheet-merge.h"
31 #include "sheet-filter.h"
32 #include "gnm-sheet-slicer.h"
33 #include "sheet-private.h"
34 #include "sheet-control.h"
35 #include "sheet-control-priv.h"
36 #include "workbook-view.h"
37 #include "workbook-control.h"
38 #include "ranges.h"
39 #include "selection.h"
40 #include "application.h"
41 #include "value.h"
42 #include "parse-util.h"
43 #include "expr-name.h"
44 #include "command-context.h"
45 #include "gnumeric-conf.h"
46 #include "sheet-style.h"
47 #include "mstyle.h"
48 #include "gutils.h"
50 #include <gsf/gsf-impl-utils.h>
52 /*************************************************************************/
54 static void
55 auto_expr_timer_clear (SheetView *sv)
57 if (sv->auto_expr_timer != 0) {
58 g_source_remove (sv->auto_expr_timer);
59 sv->auto_expr_timer = 0;
63 static gboolean
64 cb_update_auto_expr (gpointer data)
66 SheetView *sv = (SheetView *) data;
68 if (wb_view_cur_sheet_view (sv->sv_wbv) == sv)
69 wb_view_auto_expr_recalc (sv->sv_wbv);
71 sv->auto_expr_timer = 0;
72 return FALSE;
75 /*************************************************************************/
77 static void
78 sv_sheet_name_changed (G_GNUC_UNUSED Sheet *sheet,
79 G_GNUC_UNUSED GParamSpec *pspec,
80 SheetView *sv)
82 g_return_if_fail (GNM_IS_SV (sv));
83 sv->edit_pos_changed.content = TRUE;
86 static void
87 sv_sheet_visibility_changed (Sheet *sheet,
88 G_GNUC_UNUSED GParamSpec *pspec,
89 SheetView *sv)
91 g_return_if_fail (GNM_IS_SV (sv));
92 /* See bug 366477. */
93 if (sheet_is_visible (sheet) && !wb_view_cur_sheet (sv->sv_wbv))
94 wb_view_sheet_focus (sv->sv_wbv, sheet);
97 static void
98 sv_sheet_r1c1_changed (G_GNUC_UNUSED Sheet *sheet,
99 G_GNUC_UNUSED GParamSpec *pspec,
100 SheetView *sv)
102 g_return_if_fail (GNM_IS_SV (sv));
103 sv->edit_pos_changed.location = TRUE;
107 * sv_sheet:
108 * @sv: #SheetView
110 * Returns: (transfer none): the sheet.
112 Sheet *
113 sv_sheet (SheetView const *sv)
115 g_return_val_if_fail (GNM_IS_SV (sv), NULL);
116 return sv->sheet;
120 * sv_wbv:
121 * @sv: #SheetView
123 * Returns: (transfer none): the workbook view.
125 WorkbookView *
126 sv_wbv (SheetView const *sv)
128 g_return_val_if_fail (GNM_IS_SV (sv), NULL);
129 return sv->sv_wbv;
132 static void
133 sv_init_sc (SheetView const *sv, SheetControl *sc)
135 GnmCellPos initial;
137 sc_scale_changed (sc);
139 /* set_panes will change the initial so cache it */
140 initial = sv->initial_top_left;
141 sc_set_panes (sc);
143 /* And this will restore it */
144 sc_set_top_left (sc, initial.col, initial.row);
145 sc_scrollbar_config (sc);
147 /* Set the visible bound, not the logical bound */
148 sc_cursor_bound (sc, selection_first_range (sv, NULL, NULL));
149 sc_ant (sc);
152 void
153 sv_attach_control (SheetView *sv, SheetControl *sc)
155 g_return_if_fail (GNM_IS_SV (sv));
156 g_return_if_fail (GNM_IS_SC (sc));
157 g_return_if_fail (sc->view == NULL);
159 if (sv->controls == NULL)
160 sv->controls = g_ptr_array_new ();
161 g_ptr_array_add (sv->controls, sc);
162 sc->view = sv;
163 sv_init_sc (sv, sc);
166 void
167 sv_detach_control (SheetControl *sc)
169 g_return_if_fail (GNM_IS_SC (sc));
170 g_return_if_fail (GNM_IS_SV (sc->view));
172 g_ptr_array_remove (sc->view->controls, sc);
173 if (sc->view->controls->len == 0) {
174 g_ptr_array_free (sc->view->controls, TRUE);
175 sc->view->controls = NULL;
177 sc->view = NULL;
180 static void
181 sv_weakref_notify (SheetView **ptr, GObject *sv)
183 g_return_if_fail (ptr != NULL);
184 g_return_if_fail (*ptr == (SheetView *)sv); /* remember sv is dead */
185 *ptr = NULL;
188 void
189 sv_weak_ref (SheetView *sv, SheetView **ptr)
191 g_return_if_fail (ptr != NULL);
193 *ptr = sv;
194 if (sv != NULL)
195 g_object_weak_ref (G_OBJECT (sv),
196 (GWeakNotify) sv_weakref_notify,
197 ptr);
200 void
201 sv_weak_unref (SheetView **ptr)
203 g_return_if_fail (ptr != NULL);
205 if (*ptr != NULL) {
206 g_object_weak_unref (G_OBJECT (*ptr),
207 (GWeakNotify) sv_weakref_notify,
208 ptr);
209 *ptr = NULL;
213 static GObjectClass *parent_class;
215 static void
216 sv_real_dispose (GObject *object)
218 SheetView *sv = GNM_SV (object);
220 if (sv->controls != NULL) {
221 SHEET_VIEW_FOREACH_CONTROL (sv, control, {
222 sv_detach_control (control);
223 g_object_unref (control);
225 if (sv->controls != NULL)
226 g_warning ("Unexpected left-over controls");
229 if (sv->sheet) {
230 Sheet *sheet = sv->sheet;
231 sv->sheet = NULL;
232 g_ptr_array_remove (sheet->sheet_views, sv);
233 g_signal_handlers_disconnect_by_func (sheet, sv_sheet_name_changed, sv);
234 g_signal_handlers_disconnect_by_func (sheet, sv_sheet_visibility_changed, sv);
235 g_signal_handlers_disconnect_by_func (sheet, sv_sheet_r1c1_changed, sv);
236 g_object_unref (sv);
237 g_object_unref (sheet);
240 sv_unant (sv);
241 sv_selection_free (sv);
242 sv_selection_simplified_free (sv);
243 auto_expr_timer_clear (sv);
245 parent_class->dispose (object);
248 static void
249 sheet_view_class_init (GObjectClass *klass)
251 SheetViewClass *wbc_class = GNM_SV_CLASS (klass);
253 g_return_if_fail (wbc_class != NULL);
255 parent_class = g_type_class_peek_parent (klass);
256 klass->dispose = sv_real_dispose;
259 static void
260 sheet_view_init (GObject *object)
262 SheetView *sv = GNM_SV (object);
264 /* Init menu states */
265 sv->enable_insert_rows = TRUE;
266 sv->enable_insert_cols = TRUE;
267 sv->enable_insert_cells = TRUE;
269 sv->edit_pos_changed.location = TRUE;
270 sv->edit_pos_changed.content = TRUE;
271 sv->edit_pos_changed.style = TRUE;
272 sv->selection_content_changed = TRUE;
273 sv->reposition_selection = TRUE;
274 sv->auto_expr_timer = 0;
276 sv->frozen_top_left.col = sv->frozen_top_left.row =
277 sv->unfrozen_top_left.col = sv->unfrozen_top_left.row = -1;
278 sv->initial_top_left.col = sv->initial_top_left.row = 0;
280 sv->selections = NULL;
281 sv->selection_mode = GNM_SELECTION_MODE_ADD;
282 sv->selections_simplified = NULL;
283 sv_selection_add_pos (sv, 0, 0, GNM_SELECTION_MODE_ADD);
286 GSF_CLASS (SheetView, sheet_view,
287 sheet_view_class_init, sheet_view_init,
288 G_TYPE_OBJECT)
290 SheetView *
291 sheet_view_new (Sheet *sheet, WorkbookView *wbv)
293 SheetView *sv;
295 g_return_val_if_fail (IS_SHEET (sheet), NULL);
297 sv = g_object_new (GNM_SV_TYPE, NULL);
298 sv->sheet = g_object_ref (sheet);
299 sv->sv_wbv = wbv;
300 g_ptr_array_add (sheet->sheet_views, sv);
301 g_object_ref (sv);
303 g_signal_connect (G_OBJECT (sheet),
304 "notify::name",
305 G_CALLBACK (sv_sheet_name_changed),
306 sv);
308 g_signal_connect (G_OBJECT (sheet),
309 "notify::visibility",
310 G_CALLBACK (sv_sheet_visibility_changed),
311 sv);
313 g_signal_connect (G_OBJECT (sheet),
314 "notify::use-r1c1",
315 G_CALLBACK (sv_sheet_r1c1_changed),
316 sv);
318 SHEET_VIEW_FOREACH_CONTROL (sv, control,
319 sv_init_sc (sv, control););
320 return sv;
323 void
324 sv_dispose (SheetView *sv)
326 g_object_run_dispose (G_OBJECT (sv));
329 void
330 sv_unant (SheetView *sv)
332 GList *ptr;
334 g_return_if_fail (GNM_IS_SV (sv));
336 if (sv->ants == NULL)
337 return;
338 for (ptr = sv->ants; ptr != NULL; ptr = ptr->next)
339 g_free (ptr->data);
340 g_list_free (sv->ants);
341 sv->ants = NULL;
343 SHEET_VIEW_FOREACH_CONTROL (sv, control,
344 sc_unant (control););
348 * sv_ant:
349 * @sv:
350 * @ranges: (element-type GnmRange):
352 void
353 sv_ant (SheetView *sv, GList *ranges)
355 GList *ptr;
357 g_return_if_fail (GNM_IS_SV (sv));
358 g_return_if_fail (ranges != NULL);
360 if (sv->ants != NULL)
361 sv_unant (sv);
362 for (ptr = ranges; ptr != NULL; ptr = ptr->next)
363 sv->ants = g_list_prepend (sv->ants, gnm_range_dup (ptr->data));
364 sv->ants = g_list_reverse (sv->ants);
366 SHEET_VIEW_FOREACH_CONTROL (sv, control,
367 sc_ant (control););
370 void
371 sv_make_cell_visible (SheetView *sv, int col, int row,
372 gboolean couple_panes)
374 g_return_if_fail (GNM_IS_SV (sv));
375 SHEET_VIEW_FOREACH_CONTROL(sv, control,
376 sc_make_cell_visible (control, col, row, couple_panes););
379 void
380 sv_redraw_range (SheetView *sv, GnmRange const *r)
382 g_return_if_fail (GNM_IS_SV (sv));
384 SHEET_VIEW_FOREACH_CONTROL (sv, sc, sc_redraw_range (sc, r););
387 void
388 sv_redraw_headers (SheetView const *sv,
389 gboolean col, gboolean row,
390 GnmRange const* r /* optional == NULL */)
392 g_return_if_fail (GNM_IS_SV (sv));
394 SHEET_VIEW_FOREACH_CONTROL (sv, control,
395 sc_redraw_headers (control, col, row, r););
398 gboolean
399 sv_selection_copy (SheetView *sv, WorkbookControl *wbc)
401 GnmRange const *sel;
403 g_return_val_if_fail (GNM_IS_SV (sv), FALSE);
404 if (!(sel = selection_first_range (sv, GO_CMD_CONTEXT (wbc), _("Copy"))))
405 return FALSE;
407 gnm_app_clipboard_cut_copy (wbc, FALSE, sv, sel, TRUE);
409 return TRUE;
412 gboolean
413 sv_selection_cut (SheetView *sv, WorkbookControl *wbc)
415 GnmRange const *sel;
417 /* 'cut' is a poor description of what we're
418 * doing here. 'move' would be a better
419 * approximation. The key portion of this process is that
420 * the range being moved has all
421 * - references to it adjusted to the new site.
422 * - relative references from it adjusted.
424 * NOTE : This command DOES NOT MOVE ANYTHING !
425 * We only store the src, paste does the move.
427 g_return_val_if_fail (GNM_IS_SV (sv), FALSE);
429 if (!(sel = selection_first_range (sv, GO_CMD_CONTEXT (wbc), _("Cut"))))
430 return FALSE;
432 if (sheet_range_splits_region (sv_sheet (sv), sel, NULL, GO_CMD_CONTEXT (wbc), _("Cut")))
433 return FALSE;
435 gnm_app_clipboard_cut_copy (wbc, TRUE, sv, sel, TRUE);
437 return TRUE;
441 * sv_cursor_set:
442 * @sv: The sheet
443 * @edit:
444 * @base_col:
445 * @base_row:
446 * @move_col:
447 * @move_row:
448 * @bound: An optionally NULL range that should contain all the supplied points
450 void
451 sv_cursor_set (SheetView *sv,
452 GnmCellPos const *edit,
453 int base_col, int base_row,
454 int move_col, int move_row,
455 GnmRange const *bound)
457 GnmRange r;
459 g_return_if_fail (GNM_IS_SV (sv));
461 /* Change the edit position */
462 sv_set_edit_pos (sv, edit);
464 sv->cursor.base_corner.col = base_col;
465 sv->cursor.base_corner.row = base_row;
466 sv->cursor.move_corner.col = move_col;
467 sv->cursor.move_corner.row = move_row;
469 if (bound == NULL) {
470 if (base_col < move_col) {
471 r.start.col = base_col;
472 r.end.col = move_col;
473 } else {
474 r.end.col = base_col;
475 r.start.col = move_col;
477 if (base_row < move_row) {
478 r.start.row = base_row;
479 r.end.row = move_row;
480 } else {
481 r.end.row = base_row;
482 r.start.row = move_row;
484 bound = &r;
487 g_return_if_fail (range_is_sane (bound));
489 SHEET_VIEW_FOREACH_CONTROL(sv, control,
490 sc_cursor_bound (control, bound););
493 void
494 sv_set_edit_pos (SheetView *sv, GnmCellPos const *pos)
496 GnmCellPos old;
497 GnmRange const *merged;
499 g_return_if_fail (GNM_IS_SV (sv));
500 g_return_if_fail (pos != NULL);
502 old = sv->edit_pos;
503 sv->first_tab_col = -1; /* invalidate */
505 if (old.col == pos->col && old.row == pos->row)
506 return;
508 g_return_if_fail (IS_SHEET (sv->sheet));
509 g_return_if_fail (pos->col >= 0);
510 g_return_if_fail (pos->col < gnm_sheet_get_max_cols (sv->sheet));
511 g_return_if_fail (pos->row >= 0);
512 g_return_if_fail (pos->row < gnm_sheet_get_max_rows (sv->sheet));
515 merged = gnm_sheet_merge_is_corner (sv->sheet, &old);
517 sv->edit_pos_changed.location =
518 sv->edit_pos_changed.content =
519 sv->edit_pos_changed.style = TRUE;
521 /* Redraw before change */
522 if (merged == NULL) {
523 GnmRange tmp; tmp.start = tmp.end = old;
524 sv_redraw_range (sv, &tmp);
525 } else
526 sv_redraw_range (sv, merged);
528 sv->edit_pos_real = *pos;
530 /* Redraw after change (handling merged cells) */
531 merged = gnm_sheet_merge_contains_pos (sv->sheet, &sv->edit_pos_real);
532 if (merged == NULL) {
533 GnmRange tmp; tmp.start = tmp.end = *pos;
534 sv_redraw_range (sv, &tmp);
535 sv->edit_pos = sv->edit_pos_real;
536 } else {
537 sv_redraw_range (sv, merged);
538 sv->edit_pos = merged->start;
543 * sv_flag_status_update_pos:
544 * @sv:
545 * @pos:
547 * flag the view as requiring an update to the status display
548 * if the supplied cell location is the edit cursor, or part of the
549 * selected region.
551 * Will cause the format toolbar, the edit area, and the auto expressions to be
552 * updated if appropriate.
554 void
555 sv_flag_status_update_pos (SheetView *sv, GnmCellPos const *pos)
557 g_return_if_fail (GNM_IS_SV (sv));
558 g_return_if_fail (pos != NULL);
560 /* if a part of the selected region changed value update
561 * the auto expressions
563 if (sv_is_pos_selected (sv, pos->col, pos->row))
564 sv->selection_content_changed = TRUE;
566 /* If the edit cell changes value update the edit area
567 * and the format toolbar
569 if (pos->col == sv->edit_pos.col && pos->row == sv->edit_pos.row)
570 sv->edit_pos_changed.content =
571 sv->edit_pos_changed.style = TRUE;
575 * sv_flag_status_update_range:
576 * @sv:
577 * @range: If NULL then force an update.
579 * flag the sheet as requiring an update to the status display if the supplied
580 * cell location contains the edit cursor, or intersects of the selected region.
582 * Will cause the format toolbar, the edit area, and the auto expressions to be
583 * updated if appropriate.
585 void
586 sv_flag_status_update_range (SheetView *sv, GnmRange const *range)
588 g_return_if_fail (GNM_IS_SV (sv));
590 /* Force an update */
591 if (range == NULL) {
592 sv->selection_content_changed = TRUE;
593 sv->edit_pos_changed.location =
594 sv->edit_pos_changed.content =
595 sv->edit_pos_changed.style = TRUE;
596 return;
599 /* if a part of the selected region changed value update
600 * the auto expressions
602 if (sv_is_range_selected (sv, range))
603 sv->selection_content_changed = TRUE;
605 /* If the edit cell changes value update the edit area
606 * and the format toolbar
608 if (range_contains (range, sv->edit_pos.col, sv->edit_pos.row))
609 sv->edit_pos_changed.content = sv->edit_pos_changed.style = TRUE;
613 * sv_flag_style_update_range:
614 * @sv: The sheet being changed
615 * @range: the range that is changing.
617 * Flag style changes that will require updating the style indicators.
619 void
620 sv_flag_style_update_range (SheetView *sv, GnmRange const *range)
622 g_return_if_fail (GNM_IS_SV (sv));
623 g_return_if_fail (range != NULL);
624 if (range_contains (range, sv->edit_pos.col, sv->edit_pos.row))
625 sv->edit_pos_changed.style = TRUE;
629 * sv_flag_selection_change:
630 * @sv:
632 * flag the sheet as requiring an update to the status display
634 * Will cause auto expressions to be updated
636 void
637 sv_flag_selection_change (SheetView *sv)
639 g_return_if_fail (GNM_IS_SV (sv));
640 sv->selection_content_changed = TRUE;
643 static void
644 sheet_view_edit_pos_tool_tips (SheetView *sv)
646 GnmStyle const *style;
647 GnmInputMsg *im = NULL;
649 style = sheet_style_get (sv->sheet,
650 sv->edit_pos.col,
651 sv->edit_pos.row);
652 if (style != NULL && gnm_style_is_element_set (style, MSTYLE_INPUT_MSG))
653 im = gnm_style_get_input_msg (style);
655 /* We need to call these even with im == NULL to remove the old tooltip.*/
656 SHEET_VIEW_FOREACH_CONTROL (sv, control,
657 sc_show_im_tooltip (control, im, &sv->edit_pos););
660 void
661 sv_update (SheetView *sv)
663 g_return_if_fail (GNM_IS_SV (sv));
665 if (sv->edit_pos_changed.content) {
666 sv->edit_pos_changed.content = FALSE;
667 if (wb_view_cur_sheet_view (sv->sv_wbv) == sv)
668 wb_view_edit_line_set (sv->sv_wbv, NULL);
671 if (sv->edit_pos_changed.style ) {
672 sv->edit_pos_changed.style = FALSE;
673 if (wb_view_cur_sheet_view (sv->sv_wbv) == sv)
674 wb_view_style_feedback (sv->sv_wbv);
677 if (sv->edit_pos_changed.location) {
678 sv->edit_pos_changed.location = FALSE;
679 if (wb_view_cur_sheet_view (sv->sv_wbv) == sv) {
680 wb_view_selection_desc (sv->sv_wbv, TRUE, NULL);
681 SHEET_VIEW_FOREACH_CONTROL
682 (sv, sc, wb_control_menu_state_update
683 (sc_wbc (sc),
684 MS_COMMENT_LINKS | MS_PAGE_BREAKS););
685 sheet_view_edit_pos_tool_tips (sv);
689 if (sv->selection_content_changed) {
690 int const lag = gnm_conf_get_core_gui_editing_recalclag ();
691 sv->selection_content_changed = FALSE;
692 if (sv->auto_expr_timer == 0 || lag < 0) {
693 auto_expr_timer_clear (sv);
694 sv->auto_expr_timer = g_timeout_add_full (0, abs (lag), /* seems ok */
695 cb_update_auto_expr, (gpointer) sv, NULL);
697 SHEET_VIEW_FOREACH_CONTROL (sv, sc,
698 wb_control_menu_state_update (sc_wbc (sc), MS_ADD_VS_REMOVE_FILTER |
699 MS_COMMENT_LINKS_RANGE););
702 SHEET_VIEW_FOREACH_CONTROL (sv, sc,
703 wb_control_menu_state_update
704 (sc_wbc (sc), MS_SELECT_OBJECT););
709 * sv_editpos_in_filter:
710 * @sv: #SheetView
712 * Returns: %NULL or GnmFilter that overlaps the sv::edit_pos
714 GnmFilter *
715 sv_editpos_in_filter (SheetView const *sv)
717 g_return_val_if_fail (GNM_IS_SV (sv), NULL);
718 return gnm_sheet_filter_at_pos (sv->sheet, &sv->edit_pos);
722 * sv_selection_intersects_filter_rows:
723 * @sv: #SheetView
725 * Returns: %NULL or GnmFilter whose rows intersect the rows
726 * of the current selection.
728 GnmFilter *
729 sv_selection_intersects_filter_rows (SheetView const *sv)
731 GnmRange const *r;
732 g_return_val_if_fail (GNM_IS_SV (sv), NULL);
733 r = selection_first_range (sv, NULL, NULL);
735 return r ? gnm_sheet_filter_intersect_rows
736 (sv->sheet, r->start.row, r->end.row) : NULL;
740 * sv_selection_extends_filter:
741 * @sv: #SheetView
743 * Returns: %NULL or GnmFilter whose rows intersect the rows
744 * of the current selectiona range to which the filter can be
745 * extended.
747 GnmRange *
748 sv_selection_extends_filter (SheetView const *sv, GnmFilter const *f)
750 GnmRange const *r;
751 g_return_val_if_fail (GNM_IS_SV (sv), NULL);
752 r = selection_first_range (sv, NULL, NULL);
754 return gnm_sheet_filter_can_be_extended (sv->sheet, f, r);
761 * sv_editpos_in_slicer:
762 * @sv: #SheetView
764 * Returns: (transfer none): %NULL or #GnmSheetSlicer that overlaps the
765 * sv::edit_pos
767 GnmSheetSlicer *
768 sv_editpos_in_slicer (SheetView const *sv)
770 g_return_val_if_fail (GNM_IS_SV (sv), NULL);
771 return gnm_sheet_slicers_at_pos (sv->sheet, &sv->edit_pos);
775 * sv_freeze_panes:
776 * @sv: the sheet
777 * @frozen_top_left: top left corner of the frozen region
778 * @unfrozen_top_left: top left corner of the unfrozen region
780 * By definition the unfrozen region must be below the frozen.
781 * If @frozen_top_left == @unfrozen_top_left or @frozen_top_left == NULL unfreeze
783 void
784 sv_freeze_panes (SheetView *sv,
785 GnmCellPos const *frozen,
786 GnmCellPos const *unfrozen)
788 g_return_if_fail (GNM_IS_SV (sv));
790 if (gnm_debug_flag ("frozen-panes")) {
791 g_printerr ("Frozen: %-10s",
792 frozen ? cellpos_as_string (frozen) : "-");
793 g_printerr ("Unfrozen: %s\n",
794 unfrozen ? cellpos_as_string (unfrozen) : "-");
797 if (frozen != NULL) {
798 g_return_if_fail (unfrozen != NULL);
799 g_return_if_fail (unfrozen->col >= frozen->col);
800 g_return_if_fail (unfrozen->row >= frozen->row);
802 /* Just in case */
803 if (unfrozen->col != gnm_sheet_get_last_col (sv->sheet) &&
804 unfrozen->row != gnm_sheet_get_last_row (sv->sheet) &&
805 !gnm_cellpos_equal (frozen, unfrozen)) {
806 sv->frozen_top_left = *frozen;
807 sv->unfrozen_top_left = *unfrozen;
808 if (sv->frozen_top_left.col == sv->unfrozen_top_left.col)
809 sv->frozen_top_left.col = sv->unfrozen_top_left.col = 0;
810 if (sv->frozen_top_left.row == sv->unfrozen_top_left.row)
811 sv->frozen_top_left.row = sv->unfrozen_top_left.row = 0;
812 } else
813 frozen = unfrozen = NULL;
816 if (frozen == NULL) {
817 g_return_if_fail (unfrozen == NULL);
819 /* no change */
820 if (sv->frozen_top_left.col < 0 &&
821 sv->frozen_top_left.row < 0 &&
822 sv->unfrozen_top_left.col < 0 &&
823 sv->unfrozen_top_left.row < 0)
824 return;
826 sv->initial_top_left = sv->frozen_top_left;
827 sv->frozen_top_left.col = sv->frozen_top_left.row =
828 sv->unfrozen_top_left.col = sv->unfrozen_top_left.row = -1;
831 SHEET_VIEW_FOREACH_CONTROL (sv, control,
832 sv_init_sc (sv, control););
834 WORKBOOK_VIEW_FOREACH_CONTROL(sv->sv_wbv, wbc,
835 wb_control_menu_state_update (wbc, MS_FREEZE_VS_THAW););
839 * sv_panes_insdel_colrow:
840 * @sv:
841 * @is_cols:
842 * @is_insert:
843 * @start:
844 * @count:
846 * Adjust the positions of frozen panes as necessary to handle col/row
847 * insertions and deletions. note this assumes that the ins/del operations
848 * have already set the flags that will force a resize.
850 void
851 sv_panes_insdel_colrow (SheetView *sv, gboolean is_cols,
852 gboolean is_insert, int start, int count)
854 GnmCellPos tl;
855 GnmCellPos br;
857 g_return_if_fail (GNM_IS_SV (sv));
859 tl = sv->frozen_top_left; /* _copy_ them */
860 br = sv->unfrozen_top_left;
862 if (is_cols) {
863 /* ignore if not frozen, or acting in unfrozen region */
864 if (br.col <= tl.col || br.col <= start)
865 return;
866 if (is_insert) {
867 br.col += count;
868 if (tl.col > start)
869 tl.col += count;
870 if (br.col < tl.col || br.col >= gnm_sheet_get_max_cols (sv->sheet))
871 return;
872 } else {
873 if (tl.col >= start)
874 tl.col -= MIN (count, tl.col - start);
875 br.col -= count;
876 if (br.col <= tl.col)
877 br.col = tl.col + 1;
879 } else {
880 /* ignore if not frozen, or acting in unfrozen region */
881 if (br.row <= tl.row || br.row <= start)
882 return;
883 if (is_insert) {
884 br.row += count;
885 if (tl.row > start)
886 tl.row += count;
887 if (br.row < tl.row || br.row >= gnm_sheet_get_max_rows (sv->sheet))
888 return;
889 } else {
890 if (tl.row >= start)
891 tl.row -= MIN (count, tl.row - start);
892 br.row -= count;
893 if (br.row <= tl.row)
894 br.row = tl.row + 1;
897 sv_freeze_panes (sv, &tl, &br);
900 gboolean
901 sv_is_frozen (SheetView const *sv)
903 g_return_val_if_fail (GNM_IS_SV (sv), FALSE);
905 /* be flexible, in the future we will support 2 way splits too */
906 return sv->unfrozen_top_left.col >= 0 ||
907 sv->unfrozen_top_left.row >= 0;
911 sv_set_initial_top_left:
912 * @sv: the sheet view.
913 * @col:
914 * @row:
916 * Sets the top left cell that a newly created sheet control should display.
917 * This corresponds to the top left cell visible in pane 0 (frozen or not).
918 * NOTE : the unfrozen_top_left != initial_top_left. Unfrozen is the first
919 * unfrozen cell, and corresponds to the _minimum_ cell in pane 0. However,
920 * the pane can scroll and may have something else currently visible as the top
921 * left.
923 void
924 sv_set_initial_top_left (SheetView *sv, int col, int row)
926 g_return_if_fail (GNM_IS_SV (sv));
927 g_return_if_fail (0 <= col && col < gnm_sheet_get_max_cols (sv->sheet));
928 g_return_if_fail (0 <= row && row < gnm_sheet_get_max_rows (sv->sheet));
929 g_return_if_fail (!sv_is_frozen (sv) ||
930 (sv->unfrozen_top_left.col <= col &&
931 sv->unfrozen_top_left.row <= row));
933 sv->initial_top_left.col = col;
934 sv->initial_top_left.row = row;