3 * commands.c: Handlers to undo & redo commands
5 * Copyright (C) 1999-2008 Jody Goldberg (jody@gnome.org)
6 * Copyright (C) 2002-2008 Morten Welinder (terra@gnome.org)
8 * Contributors : Almer S. Tigelaar (almer@gnome.org)
9 * Andreas J. Guelzow (aguelzow@taliesin.ca)
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of the
14 * License, or (at your option) version 3.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
26 #include <gnumeric-config.h>
27 #include <glib/gi18n-lib.h>
30 #include <gnm-command-impl.h>
32 #include <application.h>
34 #include <sheet-view.h>
35 #include <sheet-style.h>
36 #include <gnm-format.h>
37 #include <format-template.h>
38 #include <command-context.h>
39 #include <workbook-control.h>
40 #include <workbook-view.h>
41 #include <workbook-priv.h> /* For the undo/redo queues and the FOREACH */
44 #include <dependent.h>
48 #include <expr-name.h>
50 #include <sheet-merge.h>
51 #include <parse-util.h>
52 #include <print-info.h>
53 #include <clipboard.h>
54 #include <selection.h>
56 #include <style-border.h>
57 #include <tools/auto-correct.h>
58 #include <sheet-autofill.h>
63 #include <sheet-object-cell-comment.h>
64 #include <sheet-object-widget.h>
65 #include <sheet-object.h>
66 #include <sheet-object-component.h>
67 #include <sheet-object-graph.h>
68 #include <sheet-control.h>
69 #include <sheet-control-gui.h>
70 #include <sheet-utils.h>
71 #include <style-color.h>
72 #include <sheet-filter.h>
73 #include <auto-format.h>
74 #include <tools/dao.h>
75 #include <gnumeric-conf.h>
76 #include <tools/scenarios.h>
77 #include <tools/data-shuffling.h>
78 #include <tools/tabulate.h>
82 #include <goffice/goffice.h>
83 #include <gsf/gsf-doc-meta-data.h>
86 #define UNICODE_ELLIPSIS "\xe2\x80\xa6"
90 * There are several distinct stages to wrapping each command.
92 * 1) Find the appropriate place(s) in the catch all calls to activations
93 * of this logical function. Be careful. This should only be called by
94 * user initiated actions, not internal commands.
96 * 2) Copy the boiler plate code into place and implement the descriptor.
98 * 3) Implement the guts of the support functions.
100 * That way undo redo just become applications of the old or the new styles.
103 * 1) redo : this should be renamed 'exec' and should be the place that the
104 * the actual command executes. This avoid duplicating the code for
105 * application and re-application.
107 * 2) The command objects are responsible for generating recalc and redraw
108 * events. None of the internal utility routines should do so. Those are
109 * expensive events and should only be done once per command to avoid
110 * duplicating work. The lower levels can queue redraws if they must, and
111 * flag state changes but the call to gnm_app_recalc and sheet_update is
114 * FIXME: Filter the list of commands when a sheet is deleted.
116 * TODO : Possibly clear lists on save.
118 * TODO : Reqs for selective undo
121 * - undoable preference setting ? XL does not have this. Do we want it ?
123 /******************************************************************/
125 #define GNM_COMMAND(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GNM_COMMAND_TYPE, GnmCommand))
126 #define GNM_COMMAND_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GNM_COMMAND_TYPE, GnmCommandClass))
127 #define GNM_IS_COMMAND(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GNM_COMMAND_TYPE))
128 #define CMD_CLASS(o) GNM_COMMAND_CLASS (G_OBJECT_GET_CLASS(cmd))
130 GSF_CLASS (GnmCommand
, gnm_command
, NULL
, NULL
, G_TYPE_OBJECT
)
133 gnm_command_finalize (GObject
*obj
)
135 GnmCommand
*cmd
= GNM_COMMAND (obj
);
136 GObjectClass
*parent
;
138 /* The const was to avoid accidental changes elsewhere */
139 g_free ((gchar
*)cmd
->cmd_descriptor
);
140 cmd
->cmd_descriptor
= NULL
;
142 parent
= g_type_class_peek (g_type_parent(G_TYPE_FROM_INSTANCE (obj
)));
143 (*parent
->finalize
) (obj
);
146 /******************************************************************/
149 gnm_cmd_trunc_descriptor (GString
*src
, gboolean
*truncated
)
151 int max_len
= gnm_conf_get_undo_max_descriptor_width ();
158 while ((pos
= strchr(src
->str
, '\n')) != NULL
||
159 (pos
= strchr(src
->str
, '\r')) != NULL
)
162 len
= g_utf8_strlen (src
->str
, -1);
165 *truncated
= (len
> max_len
);
168 gchar
* last
= g_utf8_offset_to_pointer (src
->str
,
170 g_string_truncate (src
, last
- src
->str
);
171 g_string_append (src
, UNICODE_ELLIPSIS
);
178 * cmd_cell_range_is_locked_effective:
181 * @wbc: #WorkbookControl
182 * @cmd_name: the command name.
184 * checks whether the cells are effectively locked
186 * static gboolean cmd_cell_range_is_locked_effective
189 * Do not use this function unless the sheet is part of the
190 * workbook with the given wbc (otherwise the results may be strange)
193 cmd_cell_range_is_locked_effective (Sheet
*sheet
, GnmRange
*range
,
194 WorkbookControl
*wbc
, char const *cmd_name
)
197 WorkbookView
*wbv
= wb_control_view (wbc
);
199 if (wbv
->is_protected
|| sheet
->is_protected
)
200 for (i
= range
->start
.row
; i
<= range
->end
.row
; i
++)
201 for (j
= range
->start
.col
; j
<= range
->end
.col
; j
++)
202 if (gnm_style_get_contents_locked (sheet_style_get (sheet
, j
, i
))) {
203 char *r
= global_range_name (sheet
, range
);
204 char *text
= g_strdup_printf (wbv
->is_protected
?
205 _("%s is locked. Unprotect the workbook to enable editing.") :
206 _("%s is locked. Unprotect the sheet to enable editing."),
208 go_cmd_context_error_invalid (GO_CMD_CONTEXT (wbc
),
218 * checks whether the cells are effectively locked
220 * static gboolean cmd_dao_is_locked_effective
223 * Do not use this function unless the sheet is part of the
224 * workbook with the given wbcg (otherwise the results may be strange)
229 cmd_dao_is_locked_effective (data_analysis_output_t
*dao
,
230 WorkbookControl
*wbc
, char const *cmd_name
)
233 range_init (&range
, dao
->start_col
, dao
->start_row
,
234 dao
->start_col
+ dao
->cols
- 1, dao
->start_row
+ dao
->rows
- 1);
235 return (dao
->type
!= NewWorkbookOutput
&&
236 cmd_cell_range_is_locked_effective (dao
->sheet
, &range
, wbc
, cmd_name
));
240 * cmd_selection_is_locked_effective: (skip)
241 * checks whether the selection is effectively locked
243 * static gboolean cmd_selection_is_locked_effective
246 * Do not use this function unless the sheet is part of the
247 * workbook with the given wbcg (otherwise the results may be strange)
251 cmd_selection_is_locked_effective (Sheet
*sheet
, GSList
*selection
,
252 WorkbookControl
*wbc
, char const *cmd_name
)
254 for (; selection
; selection
= selection
->next
) {
255 GnmRange
*range
= selection
->data
;
256 if (cmd_cell_range_is_locked_effective (sheet
, range
, wbc
, cmd_name
))
263 * A helper routine to select a range and make sure the top-left
267 select_range (Sheet
*sheet
, const GnmRange
*r
, WorkbookControl
*wbc
)
271 if (sheet
->workbook
!= wb_control_get_workbook (wbc
)) {
273 * We could try to pick a random wbc for the sheet's
274 * workbook. But not right now.
279 wb_control_sheet_focus (wbc
, sheet
);
280 sv
= sheet_get_view (sheet
, wb_control_view (wbc
));
281 sv_selection_reset (sv
);
282 sv_selection_add_range (sv
, r
);
283 gnm_sheet_view_make_cell_visible (sv
, r
->start
.col
, r
->start
.row
, FALSE
);
287 * A helper routine to select a list of ranges and make sure the top-left
288 * corner of the last is visible.
291 select_selection (Sheet
*sheet
, GSList
*selection
, WorkbookControl
*wbc
)
293 SheetView
*sv
= sheet_get_view (sheet
, wb_control_view (wbc
));
294 const GnmRange
*r0
= NULL
;
297 g_return_if_fail (selection
!= NULL
);
299 wb_control_sheet_focus (wbc
, sheet
);
300 sv_selection_reset (sv
);
301 for (l
= selection
; l
; l
= l
->next
) {
302 GnmRange
const *r
= l
->data
;
303 sv_selection_add_range (sv
, r
);
306 gnm_sheet_view_make_cell_visible (sv
, r0
->start
.col
, r0
->start
.row
, FALSE
);
311 * with a list of commands.
312 * @cmd_list: The command list to check.
314 * Utility routine to get the descriptor associated
315 * Returns : A static reference to a descriptor. DO NOT free this.
318 get_menu_label (GSList
*cmd_list
)
320 if (cmd_list
!= NULL
) {
321 GnmCommand
*cmd
= GNM_COMMAND (cmd_list
->data
);
322 return cmd
->cmd_descriptor
;
329 * undo_redo_menu_labels:
330 * @wb: The book whose undo/redo queues we are modifying
332 * Another utility to set the menus correctly.
335 undo_redo_menu_labels (Workbook
*wb
)
337 char const *undo_label
= get_menu_label (wb
->undo_commands
);
338 char const *redo_label
= get_menu_label (wb
->redo_commands
);
340 WORKBOOK_FOREACH_CONTROL (wb
, view
, control
,
341 wb_control_undo_redo_labels (control
, undo_label
, redo_label
);
346 update_after_action (Sheet
*sheet
, WorkbookControl
*wbc
)
351 g_return_if_fail (IS_SHEET (sheet
));
353 sheet_mark_dirty (sheet
);
354 sheet_update (sheet
);
356 if (sheet
->workbook
== wb_control_get_workbook (wbc
))
357 WORKBOOK_VIEW_FOREACH_CONTROL (wb_control_view (wbc
), control
,
358 wb_control_sheet_focus (control
, sheet
););
359 } else if (wbc
!= NULL
) {
360 Sheet
*sheet
= wb_control_cur_sheet (wbc
);
362 sheet_update (sheet
);
369 * @wbc: The workbook control which issued the request.
370 * Any user level errors generated by undoing will be reported
373 * Undo the last command executed.
376 command_undo (WorkbookControl
*wbc
)
379 GnmCommandClass
*klass
;
380 Workbook
*wb
= wb_control_get_workbook (wbc
);
382 g_return_if_fail (wb
!= NULL
);
383 g_return_if_fail (wb
->undo_commands
!= NULL
);
385 cmd
= GNM_COMMAND (wb
->undo_commands
->data
);
386 g_return_if_fail (cmd
!= NULL
);
388 klass
= CMD_CLASS (cmd
);
389 g_return_if_fail (klass
!= NULL
);
393 /* TRUE indicates a failure to undo. Leave the command where it is */
394 if (!klass
->undo_cmd (cmd
, wbc
)) {
395 gboolean undo_cleared
;
397 update_after_action (cmd
->sheet
, wbc
);
399 if (!cmd
->workbook_modified_before_do
)
400 go_doc_set_dirty (GO_DOC (wb
), FALSE
);
403 * A few commands clear the undo queue. For those, we do not
404 * want to stuff the cmd object on the redo queue.
406 undo_cleared
= (wb
->undo_commands
== NULL
);
409 wb
->undo_commands
= g_slist_remove (wb
->undo_commands
, cmd
);
410 wb
->redo_commands
= g_slist_prepend (wb
->redo_commands
, cmd
);
412 WORKBOOK_FOREACH_CONTROL (wb
, view
, control
, {
413 wb_control_undo_redo_pop (control
, TRUE
);
414 wb_control_undo_redo_push (control
, FALSE
, cmd
->cmd_descriptor
, cmd
);
416 undo_redo_menu_labels (wb
);
417 /* TODO : Should we mark the workbook as clean or pristine too */
421 g_object_unref (cmd
);
426 * @wbc: The workbook control which issued the request.
428 * Redo the last command that was undone.
429 * Any user level errors generated by redoing will be reported
433 command_redo (WorkbookControl
*wbc
)
436 GnmCommandClass
*klass
;
437 Workbook
*wb
= wb_control_get_workbook (wbc
);
439 g_return_if_fail (wb
);
440 g_return_if_fail (wb
->redo_commands
);
442 cmd
= GNM_COMMAND (wb
->redo_commands
->data
);
443 g_return_if_fail (cmd
!= NULL
);
445 klass
= CMD_CLASS (cmd
);
446 g_return_if_fail (klass
!= NULL
);
450 cmd
->workbook_modified_before_do
=
451 go_doc_is_dirty (wb_control_get_doc (wbc
));
453 /* TRUE indicates a failure to redo. Leave the command where it is */
454 if (!klass
->redo_cmd (cmd
, wbc
)) {
455 gboolean redo_cleared
;
457 update_after_action (cmd
->sheet
, wbc
);
460 * A few commands clear the undo queue. For those, we do not
461 * want to stuff the cmd object on the redo queue.
463 redo_cleared
= (wb
->redo_commands
== NULL
);
466 wb
->redo_commands
= g_slist_remove (wb
->redo_commands
, cmd
);
467 wb
->undo_commands
= g_slist_prepend (wb
->undo_commands
, cmd
);
469 WORKBOOK_FOREACH_CONTROL (wb
, view
, control
, {
470 wb_control_undo_redo_push (control
, TRUE
, cmd
->cmd_descriptor
, cmd
);
471 wb_control_undo_redo_pop (control
, FALSE
);
473 undo_redo_menu_labels (wb
);
477 g_object_unref (cmd
);
482 * @wbc: The workbook control which issued the request.
484 * Repeat the last command (if possible)
486 * Any user level errors generated by redoing will be reported
490 command_repeat (WorkbookControl
*wbc
)
493 GnmCommandClass
*klass
;
494 Workbook
*wb
= wb_control_get_workbook (wbc
);
496 g_return_if_fail (wb
);
497 g_return_if_fail (wb
->undo_commands
);
499 cmd
= GNM_COMMAND (wb
->undo_commands
->data
);
500 g_return_if_fail (cmd
!= NULL
);
502 klass
= CMD_CLASS (cmd
);
503 g_return_if_fail (klass
!= NULL
);
505 if (klass
->repeat_cmd
!= NULL
)
506 (*klass
->repeat_cmd
) (cmd
, wbc
);
510 * command_setup_combos:
513 * Initialize the combos to correspond to the current undo/redo state.
516 command_setup_combos (WorkbookControl
*wbc
)
518 char const *undo_label
= NULL
, *redo_label
= NULL
;
520 Workbook
*wb
= wb_control_get_workbook (wbc
);
522 g_return_if_fail (wb
);
524 wb_control_undo_redo_truncate (wbc
, 0, TRUE
);
525 tmp
= g_slist_reverse (wb
->undo_commands
);
526 for (ptr
= tmp
; ptr
!= NULL
; ptr
= ptr
->next
) {
527 undo_label
= get_menu_label (ptr
);
528 wb_control_undo_redo_push (wbc
, TRUE
, undo_label
, ptr
->data
);
530 if (g_slist_reverse (tmp
)) {} /* ignore, list is in undo_commands */
532 wb_control_undo_redo_truncate (wbc
, 0, FALSE
);
533 tmp
= g_slist_reverse (wb
->redo_commands
);
534 for (ptr
= tmp
; ptr
!= NULL
; ptr
= ptr
->next
) {
535 redo_label
= get_menu_label (ptr
);
536 wb_control_undo_redo_push (wbc
, FALSE
, redo_label
, ptr
->data
);
538 if (g_slist_reverse (tmp
)) {} /* ignore, list is in redo_commands */
540 /* update the menus too */
541 wb_control_undo_redo_labels (wbc
, undo_label
, redo_label
);
545 * command_list_release:
546 * @cmds: (element-type GObject): the set of commands to free.
548 * command_list_release : utility routine to free the resources associated
549 * with a list of commands.
551 * NOTE : remember to NULL the list when you are done.
554 command_list_release (GSList
*cmd_list
)
556 while (cmd_list
!= NULL
) {
557 GObject
*cmd
= G_OBJECT (cmd_list
->data
);
559 g_return_if_fail (cmd
!= NULL
);
561 g_object_unref (cmd
);
562 cmd_list
= g_slist_remove (cmd_list
, cmd_list
->data
);
567 * Each undo item has a certain size. The size of typing a value into
568 * a cell is the unit size. A large autoformat could have a size of
569 * hundreds or even thousands.
571 * We wish to have the same undo behaviour across platforms, so please
572 * don't use sizeof in computing the undo size.
575 #undef DEBUG_TRUNCATE_UNDO
578 * Truncate the undo list if it is too big.
580 * Returns -1 if no truncation was done, or else the number of elements
584 truncate_undo_info (Workbook
*wb
)
591 size_left
= gnm_conf_get_undo_size ();
592 max_num
= gnm_conf_get_undo_maxnum ();
594 #ifdef DEBUG_TRUNCATE_UNDO
595 g_printerr ("Undo sizes:");
598 for (l
= wb
->undo_commands
, prev
= NULL
, ok_count
= 0;
600 prev
= l
, l
= l
->next
, ok_count
++) {
602 GnmCommand
*cmd
= GNM_COMMAND (l
->data
);
603 int size
= cmd
->size
;
607 * We could g_assert, but that would cause data loss.
608 * Instead, just continue.
610 g_warning ("Faulty undo_size_func, please report.");
614 #ifdef DEBUG_TRUNCATE_UNDO
615 g_printerr (" %d", size
);
618 /* Keep at least one undo item. */
619 if (ok_count
>= max_num
|| (size
> size_left
&& ok_count
>= 1)) {
620 /* Current item is too big; truncate list here. */
621 command_list_release (l
);
625 wb
->undo_commands
= NULL
;
626 #ifdef DEBUG_TRUNCATE_UNDO
627 g_printerr ("[trunc]\n");
633 * In order to allow a series of useful small items behind
634 * a big item, leave at least 10% of current item's size.
636 min_leave
= size
/ 10;
637 size_left
= MAX (size_left
- size
, min_leave
);
640 #ifdef DEBUG_TRUNCATE_UNDO
648 * command_register_undo:
649 * @wbc: The workbook control that issued the command.
650 * @cmd: The new command to add.
652 * An internal utility to tack a new command
653 * onto the undo list.
656 command_register_undo (WorkbookControl
*wbc
, GObject
*obj
)
662 g_return_if_fail (wbc
!= NULL
);
663 wb
= wb_control_get_workbook (wbc
);
665 cmd
= GNM_COMMAND (obj
);
666 g_return_if_fail (cmd
!= NULL
);
668 command_list_release (wb
->redo_commands
);
669 wb
->redo_commands
= NULL
;
671 g_object_ref (obj
); /* keep a ref in case it gets truncated away */
672 wb
->undo_commands
= g_slist_prepend (wb
->undo_commands
, cmd
);
673 undo_trunc
= truncate_undo_info (wb
);
675 WORKBOOK_FOREACH_CONTROL (wb
, view
, control
, {
676 wb_control_undo_redo_push (control
, TRUE
, cmd
->cmd_descriptor
, cmd
);
678 wb_control_undo_redo_truncate (control
, undo_trunc
, TRUE
);
679 wb_control_undo_redo_truncate (control
, 0, FALSE
);
681 undo_redo_menu_labels (wb
);
682 g_object_unref (obj
);
687 * gnm_command_push_undo:
688 * @wbc: The workbook control that issued the command.
689 * @obj: The new command to add.
691 * An internal utility to tack a new command
692 * onto the undo list.
694 * returns : TRUE if there was an error.
697 gnm_command_push_undo (WorkbookControl
*wbc
, GObject
*obj
)
701 GnmCommandClass
*klass
;
703 g_return_val_if_fail (wbc
!= NULL
, TRUE
);
705 cmd
= GNM_COMMAND (obj
);
706 cmd
->workbook_modified_before_do
=
707 go_doc_is_dirty (wb_control_get_doc (wbc
));
709 g_return_val_if_fail (cmd
!= NULL
, TRUE
);
711 klass
= CMD_CLASS (cmd
);
712 g_return_val_if_fail (klass
!= NULL
, TRUE
);
714 /* TRUE indicates a failure to do the command */
715 trouble
= klass
->redo_cmd (cmd
, wbc
);
716 update_after_action (cmd
->sheet
, wbc
);
719 command_register_undo (wbc
, obj
);
721 g_object_unref (obj
);
727 * command_undo_sheet_delete deletes the sheet without deleting the current cmd.
728 * returns true if is indeed deleted the sheet.
729 * Note: only call this for a sheet of your current workbook from the undo procedure
733 command_undo_sheet_delete (Sheet
* sheet
)
735 Workbook
*wb
= sheet
->workbook
;
737 g_return_val_if_fail (IS_SHEET (sheet
), FALSE
);
739 if (wb
->redo_commands
!= NULL
) {
740 command_list_release (wb
->redo_commands
);
741 wb
->redo_commands
= NULL
;
742 WORKBOOK_FOREACH_CONTROL (wb
, view
, ctl
,
743 wb_control_undo_redo_truncate (ctl
, 0, FALSE
););
744 undo_redo_menu_labels (wb
);
747 workbook_sheet_delete (sheet
);
752 /******************************************************************/
755 cmd_set_text_full_check_texpr (GnmCellIter
const *iter
, GnmExprTop
const *texpr
)
757 if (iter
->cell
== NULL
||
758 !gnm_expr_top_equal (iter
->cell
->base
.texpr
, texpr
))
759 return VALUE_TERMINATE
;
764 cmd_set_text_full_check_text (GnmCellIter
const *iter
, char *text
)
768 gboolean quoted
= FALSE
;
770 if (gnm_cell_is_blank (iter
->cell
))
771 return ((text
== NULL
|| text
[0] == '\0') ? NULL
: VALUE_TERMINATE
);
773 if (text
== NULL
|| text
[0] == '\0')
774 return VALUE_TERMINATE
;
776 old_text
= gnm_cell_get_text_for_editing (iter
->cell
, NULL
, "ed
);
777 same
= g_strcmp0 (old_text
, text
) == 0;
779 if (!same
&& !quoted
&& iter
->cell
->value
&& VALUE_IS_STRING (iter
->cell
->value
)
781 same
= g_strcmp0 (old_text
, text
+ 1) == 0;
785 return (same
? NULL
: VALUE_TERMINATE
);
789 cmd_set_text_full_check_markup (GnmCellIter
const *iter
, PangoAttrList
*markup
)
791 PangoAttrList
const *old_markup
= NULL
;
792 gboolean same_markup
;
794 g_return_val_if_fail (iter
->cell
!= NULL
, NULL
);
796 if (iter
->cell
->value
&& VALUE_IS_STRING (iter
->cell
->value
)) {
797 const GOFormat
*fmt
= VALUE_FMT (iter
->cell
->value
);
798 if (fmt
&& go_format_is_markup (fmt
)) {
799 old_markup
= go_format_get_markup (fmt
);
800 if (go_pango_attr_list_is_empty (old_markup
))
805 same_markup
= gnm_pango_attr_list_equal (old_markup
, markup
);
807 return same_markup
? NULL
: VALUE_TERMINATE
;
813 * the caller is expected to have ensured:
815 * 1) that no array is being split
816 * 2) that the range is not locked.
819 * We will free the selection but nothing else.
824 cmd_set_text_full (WorkbookControl
*wbc
, GSList
*selection
, GnmEvalPos
*ep
,
825 char const *new_text
, PangoAttrList
*markup
,
826 gboolean autocorrect
)
829 char const *expr_txt
;
830 GnmExprTop
const *texpr
= NULL
;
833 gboolean result
, autofit_col
= FALSE
, same_text_and_not_same_markup
= FALSE
;
836 Sheet
*sheet
= ep
->sheet
;
838 ColRowIndexList
*cri_col_list
= NULL
, *cri_row_list
= NULL
;
839 GOFormat
const *format
= gnm_style_get_format
840 (sheet_style_get (sheet
, ep
->eval
.col
, ep
->eval
.row
));
842 g_return_val_if_fail (selection
!= NULL
, TRUE
);
844 parse_pos_init_evalpos (&pp
, ep
);
845 name
= undo_range_list_name (sheet
, selection
);
847 if ((format
== NULL
) || !go_format_is_text (format
)) {
848 expr_txt
= gnm_expr_char_start_p (new_text
);
849 if (expr_txt
!= NULL
)
850 texpr
= gnm_expr_parse_str
851 (expr_txt
, &pp
, GNM_EXPR_PARSE_DEFAULT
,
852 sheet_get_conventions (sheet
), NULL
);
857 GnmStyle
*new_style
= NULL
;
858 gboolean same_texpr
= TRUE
;
860 /* We should check whether we are in fact changing anything: */
861 for (l
= selection
; l
!= NULL
&& same_texpr
; l
= l
->next
) {
862 GnmRange
*r
= l
->data
;
864 sheet_foreach_cell_in_range
865 (sheet
, CELL_ITER_ALL
, r
,
866 (CellIterFunc
) cmd_set_text_full_check_texpr
,
869 same_texpr
= (val
!= VALUE_TERMINATE
);
870 if (val
!= NULL
&& same_texpr
)
875 gnm_expr_top_unref (texpr
);
877 range_fragment_free (selection
);
881 text
= g_strdup_printf (_("Inserting expression in %s"), name
);
883 if (go_format_is_general (format
)) {
884 sf
= gnm_auto_style_format_suggest (texpr
, ep
);
886 new_style
= gnm_style_new ();
887 gnm_style_set_format (new_style
, sf
);
888 go_format_unref (sf
);
892 for (l
= selection
; l
!= NULL
; l
= l
->next
) {
894 undo
= go_undo_combine
895 (undo
, clipboard_copy_range_undo (sheet
, l
->data
));
896 sr
= gnm_sheet_range_new (sheet
, l
->data
);
897 redo
= go_undo_combine
898 (redo
, sheet_range_set_expr_undo (sr
, texpr
));
900 sr
= gnm_sheet_range_new (sheet
, l
->data
);
901 redo
= go_undo_combine
902 (redo
, sheet_apply_style_undo (sr
, new_style
));
906 gnm_style_unref (new_style
);
907 gnm_expr_top_unref (texpr
);
911 PangoAttrList
*adj_markup
= NULL
;
913 gboolean same_text
= TRUE
;
914 gboolean same_markup
= TRUE
;
916 if (new_text
== NULL
)
918 else if (autocorrect
)
919 corrected
= autocorrect_tool (new_text
);
921 corrected
= g_strdup (new_text
);
923 if (corrected
&& (corrected
[0] == '\'') && corrected
[1] == '\0') {
925 corrected
= g_strdup ("");
928 /* We should check whether we are in fact changing anything: */
930 for (l
= selection
; l
!= NULL
&& same_text
; l
= l
->next
) {
931 GnmRange
*r
= l
->data
;
933 sheet_foreach_cell_in_range
934 (sheet
, CELL_ITER_ALL
, r
,
935 (CellIterFunc
) cmd_set_text_full_check_text
,
936 (gpointer
) corrected
);
938 same_text
= (val
!= VALUE_TERMINATE
);
939 if (val
!= NULL
&& same_text
)
943 if (go_pango_attr_list_is_empty (markup
))
945 if (markup
&& corrected
&& corrected
[0] == '\'') {
946 markup
= adj_markup
= pango_attr_list_copy (markup
);
947 go_pango_attr_list_erase (adj_markup
, 0, 1);
951 for (l
= selection
; l
!= NULL
&& same_text
; l
= l
->next
) {
952 GnmRange
*r
= l
->data
;
954 sheet_foreach_cell_in_range
955 (sheet
, CELL_ITER_IGNORE_BLANK
, r
,
956 (CellIterFunc
) cmd_set_text_full_check_markup
,
959 same_markup
= (val
!= VALUE_TERMINATE
);
960 if (val
!= NULL
&& same_markup
)
967 range_fragment_free (selection
);
969 pango_attr_list_unref (adj_markup
);
973 text
= g_strdup_printf (_("Editing style of %s"), name
);
975 text_str
= gnm_cmd_trunc_descriptor (g_string_new (corrected
), NULL
);
976 text
= g_strdup_printf (_("Typing \"%s\" in %s"), text_str
->str
, name
);
977 g_string_free (text_str
, TRUE
);
980 for (l
= selection
; l
!= NULL
; l
= l
->next
) {
982 undo
= go_undo_combine
983 (undo
, clipboard_copy_range_undo (sheet
, l
->data
));
985 sr
= gnm_sheet_range_new (sheet
, l
->data
);
986 redo
= go_undo_combine
987 (redo
, sheet_range_set_text_undo
991 sr
= gnm_sheet_range_new (sheet
, l
->data
);
992 /* Note: order of combination matters!! */
993 redo
= go_undo_combine
994 (sheet_range_set_markup_undo (sr
, markup
), redo
);
999 pango_attr_list_unref (adj_markup
);
1002 same_text_and_not_same_markup
= (same_text
&& !same_markup
);
1006 /* We are combining this since we don't want to apply and undo twice.*/
1007 if (same_text_and_not_same_markup
|| !autofit_col
) {
1008 GnmCell
*cell
= sheet_cell_fetch
1009 (sheet
, ep
->eval
.col
, ep
->eval
.row
);
1012 go_undo_undo (redo
);
1013 nvis
= !VALUE_IS_STRING (cell
->value
);
1016 if (same_text_and_not_same_markup
)
1017 /* We only have to do something if at least one cell */
1018 /* now contains a string, but they contain all the same thing. */
1019 same_text_and_not_same_markup
= nvis
;
1020 go_undo_undo (undo
);
1022 if (same_text_and_not_same_markup
) {
1023 /*We had the same text and different markup but we are not entering strings. */
1024 g_object_unref (undo
);
1025 g_object_unref (redo
);
1027 range_fragment_free (selection
);
1030 for (l
= selection
; l
!= NULL
; l
= l
->next
) {
1031 GnmRange
*r
= l
->data
;
1034 new_r
= g_new (GnmRange
, 1);
1036 redo
= go_undo_combine
1039 (GOUndoBinaryFunc
) colrow_autofit_row
,
1042 cri_row_list
= colrow_get_index_list
1043 (r
->start
.row
, r
->end
.row
, cri_row_list
);
1046 new_r
= g_new (GnmRange
, 1);
1048 redo
= go_undo_combine
1051 (GOUndoBinaryFunc
) colrow_autofit_col
,
1054 cri_col_list
= colrow_get_index_list
1055 (r
->start
.col
, r
->end
.col
, cri_col_list
);
1059 undo
= go_undo_combine (undo
,
1060 gnm_undo_colrow_restore_state_group_new
1063 colrow_get_sizes (sheet
, TRUE
,
1064 cri_col_list
, -1)));
1065 undo
= go_undo_combine (undo
,
1066 gnm_undo_colrow_restore_state_group_new
1069 colrow_get_sizes (sheet
, FALSE
,
1070 cri_row_list
, -1)));
1072 result
= cmd_generic (wbc
, text
, undo
, redo
);
1074 range_fragment_free (selection
);
1081 * the caller is expected to have ensured:
1083 * 1) that no array is being split
1084 * 2) that the range is not locked.
1089 cmd_area_set_text (WorkbookControl
*wbc
, SheetView
*sv
,
1090 char const *new_text
, PangoAttrList
*markup
)
1094 GSList
*selection
= selection_get_ranges (sv
, FALSE
);
1096 eval_pos_init_editpos (&ep
, sv
);
1097 result
= cmd_set_text_full (wbc
, selection
, &ep
,
1098 new_text
, markup
, TRUE
);
1103 cmd_set_text (WorkbookControl
*wbc
,
1104 Sheet
*sheet
, GnmCellPos
const *pos
,
1105 char const *new_text
,
1106 PangoAttrList
*markup
,
1107 gboolean autocorrect
)
1109 GnmCell
const *cell
;
1115 g_return_val_if_fail (IS_SHEET (sheet
), TRUE
);
1116 g_return_val_if_fail (new_text
!= NULL
, TRUE
);
1118 /* Ensure that we are not splitting up an array */
1119 cell
= sheet_cell_get (sheet
, pos
->col
, pos
->row
);
1120 if (gnm_cell_is_nonsingleton_array (cell
)) {
1121 gnm_cmd_context_error_splits_array (GO_CMD_CONTEXT (wbc
),
1122 _("Set Text"), NULL
);
1126 eval_pos_init_pos (&ep
, sheet
, pos
);
1127 r
= g_new (GnmRange
, 1);
1128 r
->start
= r
->end
= *pos
;
1129 selection
= g_slist_prepend (NULL
, r
);
1130 result
= cmd_set_text_full (wbc
, selection
, &ep
,
1131 new_text
, markup
, autocorrect
);
1137 * cmd_area_set_array_expr
1139 * the caller is expected to have ensured:
1141 * 1) that no array is being split
1142 * 2) that the selection consists of a single range
1143 * 3) that the range is not locked.
1148 cmd_area_set_array_expr (WorkbookControl
*wbc
, SheetView
*sv
,
1149 GnmExprTop
const *texpr
)
1151 GSList
*selection
= selection_get_ranges (sv
, FALSE
);
1152 GOUndo
*undo
= NULL
;
1153 GOUndo
*redo
= NULL
;
1155 Sheet
*sheet
= sv_sheet (sv
);
1161 g_return_val_if_fail (selection
!= NULL
, TRUE
);
1162 g_return_val_if_fail (selection
->next
== NULL
, TRUE
);
1164 name
= undo_range_list_name (sheet
, selection
);
1165 text
= g_strdup_printf (_("Inserting array expression in %s"), name
);
1168 r
= selection
->data
;
1170 undo
= clipboard_copy_range_undo (sheet
, selection
->data
);
1172 sr
= gnm_sheet_range_new (sheet
, r
);
1173 redo
= gnm_cell_set_array_formula_undo (sr
, texpr
);
1174 redo
= go_undo_combine
1176 (sheet
, g_memdup (r
, sizeof (*r
)),
1177 (GOUndoBinaryFunc
) colrow_autofit_col
,
1180 redo
= go_undo_combine
1182 (sheet
, g_memdup (r
, sizeof (*r
)),
1183 (GOUndoBinaryFunc
) colrow_autofit_row
,
1187 range_fragment_free (selection
);
1188 result
= cmd_generic (wbc
, text
, undo
, redo
);
1194 * cmd_create_data_table
1196 * the caller is expected to have ensured:
1198 * 1) that no array is being split
1199 * 2) that the range is not locked.
1203 cmd_create_data_table (WorkbookControl
*wbc
, Sheet
*sheet
, GnmRange
const *r
,
1204 char const *col_input
, char const *row_input
)
1206 GOUndo
*undo
= NULL
;
1207 GOUndo
*redo
= NULL
;
1213 GnmExprTop
const *texpr
;
1215 name
= undo_range_name (sheet
, r
);
1216 text
= g_strdup_printf (_("Creating a Data Table in %s"), name
);
1219 undo
= clipboard_copy_range_undo (sheet
, r
);
1221 sr
= gnm_sheet_range_new (sheet
, r
);
1222 parse_pos_init (&pp
, NULL
, sheet
, r
->start
.col
, r
->start
.row
);
1223 name
= g_strdup_printf ("TABLE(%s,%s)", row_input
, col_input
);
1224 texpr
= gnm_expr_parse_str
1225 (name
, &pp
, GNM_EXPR_PARSE_DEFAULT
,
1226 sheet_get_conventions (sheet
), NULL
);
1229 if (texpr
== NULL
) {
1230 g_object_unref (undo
);
1235 redo
= gnm_cell_set_array_formula_undo (sr
, texpr
);
1236 gnm_expr_top_unref (texpr
);
1238 result
= cmd_generic (wbc
, text
, undo
, redo
);
1243 /******************************************************************/
1245 #define CMD_INS_DEL_COLROW_TYPE (cmd_ins_del_colrow_get_type ())
1246 #define CMD_INS_DEL_COLROW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_INS_DEL_COLROW_TYPE, CmdInsDelColRow))
1257 GnmRange
*cutcopied
;
1258 SheetView
*cut_copy_view
;
1260 gboolean (*redo_action
) (Sheet
*sheet
, int col
, int count
,
1261 GOUndo
**pundo
, GOCmdContext
*cc
);
1263 gboolean (*repeat_action
) (WorkbookControl
*wbc
, Sheet
*sheet
,
1264 int start
, int count
);
1270 cmd_ins_del_colrow_repeat (GnmCommand
const *cmd
, WorkbookControl
*wbc
)
1272 CmdInsDelColRow
const *orig
= (CmdInsDelColRow
const *) cmd
;
1273 SheetView
*sv
= wb_control_cur_sheet_view (wbc
);
1274 Sheet
*sheet
= sv_sheet (sv
);
1275 GnmRange
const *r
= selection_first_range (sv
,
1276 GO_CMD_CONTEXT (wbc
), _("Ins/Del Column/Row"));
1283 start
= r
->start
.col
, count
= range_width (r
);
1285 start
= r
->start
.row
, count
= range_height (r
);
1287 orig
->repeat_action (wbc
, sheet
, start
, count
);
1290 MAKE_GNM_COMMAND (CmdInsDelColRow
, cmd_ins_del_colrow
, cmd_ins_del_colrow_repeat
)
1293 cmd_ins_del_colrow_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
1295 CmdInsDelColRow
*me
= CMD_INS_DEL_COLROW (cmd
);
1298 go_undo_undo (me
->undo
);
1299 g_object_unref (me
->undo
);
1303 /* Ins/Del Row/Col re-ants things completely to account
1304 * for the shift of col/rows.
1306 if (me
->cutcopied
!= NULL
&& me
->cut_copy_view
!= NULL
)
1307 gnm_app_clipboard_cut_copy (wbc
, me
->is_cut
, me
->cut_copy_view
,
1308 me
->cutcopied
, FALSE
);
1314 cmd_ins_del_colrow_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
1316 CmdInsDelColRow
*me
= CMD_INS_DEL_COLROW (cmd
);
1317 GOCmdContext
*cc
= GO_CMD_CONTEXT (wbc
);
1318 int idx
= me
->index
;
1319 int count
= me
->count
;
1321 if (me
->redo_action (me
->sheet
, idx
, count
, &me
->undo
, cc
)) {
1326 /* Ins/Del Row/Col re-ants things completely to account
1327 * for the shift of col/rows. */
1328 if (me
->cutcopied
!= NULL
&& me
->cut_copy_view
!= NULL
) {
1330 GnmRange s
= *me
->cutcopied
;
1331 int key
= me
->is_insert
? count
: -count
;
1332 int threshold
= me
->is_insert
? idx
: idx
+ 1;
1335 * Really only applies if the regions that are
1336 * inserted/deleted are above the cut/copied region.
1339 if (threshold
<= s
.start
.col
) {
1343 } else if (threshold
<= s
.start
.row
) {
1348 gnm_app_clipboard_cut_copy (wbc
, me
->is_cut
,
1352 gnm_app_clipboard_unant ();
1359 cmd_ins_del_colrow_finalize (GObject
*cmd
)
1361 CmdInsDelColRow
*me
= CMD_INS_DEL_COLROW (cmd
);
1364 g_object_unref (me
->undo
);
1366 g_free (me
->cutcopied
);
1368 gnm_sheet_view_weak_unref (&(me
->cut_copy_view
));
1370 gnm_command_finalize (cmd
);
1374 cmd_ins_del_colrow (WorkbookControl
*wbc
,
1376 gboolean is_cols
, gboolean is_insert
,
1377 char const *descriptor
, int index
, int count
)
1379 CmdInsDelColRow
*me
;
1383 g_return_val_if_fail (IS_SHEET (sheet
), TRUE
);
1384 g_return_val_if_fail (count
> 0, TRUE
);
1386 me
= g_object_new (CMD_INS_DEL_COLROW_TYPE
, NULL
);
1389 me
->is_cols
= is_cols
;
1390 me
->is_insert
= is_insert
;
1393 me
->redo_action
= me
->is_insert
1394 ? (me
->is_cols
? sheet_insert_cols
: sheet_insert_rows
)
1395 : (me
->is_cols
? sheet_delete_cols
: sheet_delete_rows
);
1396 me
->repeat_action
= me
->is_insert
1397 ? (me
->is_cols
? cmd_insert_cols
: cmd_insert_rows
)
1398 : (me
->is_cols
? cmd_delete_cols
: cmd_delete_rows
);
1400 /* Range that will get deleted. */
1401 first
= me
->is_insert
1402 ? colrow_max (is_cols
, sheet
) - count
1404 last
= first
+ count
- 1;
1405 (is_cols
? range_init_cols
: range_init_rows
) (&r
, sheet
, first
, last
);
1407 /* Note: redo_action checks for array subdivision. */
1409 /* Check for locks */
1410 if (cmd_cell_range_is_locked_effective (sheet
, &r
, wbc
, descriptor
)) {
1411 g_object_unref (me
);
1415 /* We store the cut or/copied range if applicable */
1416 if (!gnm_app_clipboard_is_empty () &&
1417 gnm_app_clipboard_area_get () &&
1418 sheet
== gnm_app_clipboard_sheet_get ()) {
1419 me
->cutcopied
= gnm_range_dup (gnm_app_clipboard_area_get ());
1420 me
->is_cut
= gnm_app_clipboard_is_cut ();
1421 gnm_sheet_view_weak_ref (gnm_app_clipboard_sheet_view_get (),
1422 &(me
->cut_copy_view
));
1424 me
->cutcopied
= NULL
;
1426 me
->cmd
.sheet
= sheet
;
1427 me
->cmd
.size
= count
* 10; /* FIXME? */
1428 me
->cmd
.cmd_descriptor
= descriptor
;
1430 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
1434 cmd_insert_cols (WorkbookControl
*wbc
,
1435 Sheet
*sheet
, int start_col
, int count
)
1440 range_init_full_sheet (&r
, sheet
);
1441 r
.start
.col
= r
.end
.col
- count
+ 1;
1443 if (!sheet_range_trim (sheet
, &r
, FALSE
, FALSE
)) {
1444 go_gtk_notice_dialog (wbcg_toplevel (WBC_GTK (wbc
)), GTK_MESSAGE_ERROR
,
1445 ngettext ("Inserting %i column before column %s would push data off the sheet. "
1446 "Please enlarge the sheet first.",
1447 "Inserting %i columns before column %s would push data off the sheet. "
1448 "Please enlarge the sheet first.",
1450 count
, col_name (start_col
));
1454 mesg
= g_strdup_printf
1455 (ngettext ("Inserting %d column before %s",
1456 "Inserting %d columns before %s",
1458 count
, col_name (start_col
));
1459 return cmd_ins_del_colrow (wbc
, sheet
, TRUE
, TRUE
, mesg
, start_col
, count
);
1463 cmd_insert_rows (WorkbookControl
*wbc
,
1464 Sheet
*sheet
, int start_row
, int count
)
1469 range_init_full_sheet (&r
, sheet
);
1470 r
.start
.row
= r
.end
.row
- count
+ 1;
1472 if (!sheet_range_trim (sheet
, &r
, FALSE
, FALSE
)) {
1473 go_gtk_notice_dialog (wbcg_toplevel (WBC_GTK (wbc
)), GTK_MESSAGE_ERROR
,
1474 ngettext ("Inserting %i row before row %s would push data off the sheet. "
1475 "Please enlarge the sheet first.",
1476 "Inserting %i rows before row %s would push data off the sheet. "
1477 "Please enlarge the sheet first.",
1479 count
, row_name (start_row
));
1483 mesg
= g_strdup_printf
1484 (ngettext ("Inserting %d row before %s",
1485 "Inserting %d rows before %s",
1487 count
, row_name (start_row
));
1488 return cmd_ins_del_colrow (wbc
, sheet
, FALSE
, TRUE
, mesg
, start_row
, count
);
1492 cmd_delete_cols (WorkbookControl
*wbc
,
1493 Sheet
*sheet
, int start_col
, int count
)
1495 char *mesg
= g_strdup_printf ((count
> 1)
1496 ? _("Deleting columns %s")
1497 : _("Deleting column %s"),
1498 cols_name (start_col
, start_col
+ count
- 1));
1499 return cmd_ins_del_colrow (wbc
, sheet
, TRUE
, FALSE
, mesg
, start_col
, count
);
1503 cmd_delete_rows (WorkbookControl
*wbc
,
1504 Sheet
*sheet
, int start_row
, int count
)
1506 char *mesg
= g_strdup_printf ((count
> 1)
1507 ? _("Deleting rows %s")
1508 : _("Deleting row %s"),
1509 rows_name (start_row
, start_row
+ count
- 1));
1510 return cmd_ins_del_colrow (wbc
, sheet
, FALSE
, FALSE
, mesg
, start_row
, count
);
1513 /******************************************************************/
1518 } cmd_selection_clear_row_handler_t
;
1521 cmd_selection_clear_row_handler (GnmColRowIter
const *iter
,
1522 cmd_selection_clear_row_handler_t
*data
)
1524 if ((!iter
->cri
->in_filter
) || iter
->cri
->visible
) {
1525 GnmRange
*r
= gnm_range_dup (data
->r
);
1526 r
->start
.row
= r
->end
.row
= iter
->pos
;
1527 data
->selection
= g_slist_prepend (data
->selection
, r
);
1533 cmd_selection_clear (WorkbookControl
*wbc
, int clear_flags
)
1535 char *names
, *descriptor
;
1537 SheetView
*sv
= wb_control_cur_sheet_view (wbc
);
1538 GSList
*selection
= selection_get_ranges (sv
, FALSE
/* No intersection */);
1539 Sheet
*sheet
= sv_sheet (sv
);
1542 GOUndo
*undo
= NULL
;
1543 GOUndo
*redo
= NULL
;
1546 if ((clear_flags
& CLEAR_FILTERED_ONLY
) != 0 && sheet
->filters
!= NULL
) {
1547 /* We need to modify the selection to only include filtered rows. */
1548 cmd_selection_clear_row_handler_t data
;
1549 data
.selection
= selection
;
1550 for (ranges
= selection
; ranges
!= NULL
; ranges
= ranges
->next
) {
1552 data
.r
= ranges
->data
;
1553 filter
= gnm_sheet_filter_intersect_rows
1554 (sheet
, data
.r
->start
.row
, data
.r
->end
.row
);
1556 sheet_colrow_foreach (sheet
, FALSE
,
1559 (ColRowHandler
) cmd_selection_clear_row_handler
,
1561 g_free (ranges
->data
);
1562 ranges
->data
= NULL
;
1565 selection
= g_slist_remove_all (data
.selection
, NULL
);
1568 /* We should first determine whether we break anything by clearing */
1569 /* Check for array subdivision *//* Check for locked cells */
1570 if (sheet_ranges_split_region (sheet
, selection
,
1571 GO_CMD_CONTEXT (wbc
), _("Clear")) ||
1572 cmd_selection_is_locked_effective (sheet
, selection
, wbc
, _("Clear"))) {
1573 range_fragment_free (selection
);
1578 /* We now need to build the descriptor */
1579 /* Collect clear types for descriptor */
1580 if (clear_flags
!= (CLEAR_VALUES
| CLEAR_FORMATS
| CLEAR_COMMENTS
)) {
1581 GSList
*m
, *l
= NULL
;
1582 types
= g_string_new (NULL
);
1583 if (clear_flags
& CLEAR_VALUES
)
1584 l
= g_slist_append (l
, g_string_new (_("contents")));
1585 if (clear_flags
& CLEAR_FORMATS
)
1586 l
= g_slist_append (l
, g_string_new (_("formats")));
1587 if (clear_flags
& CLEAR_COMMENTS
)
1588 l
= g_slist_append (l
, g_string_new (_("comments")));
1589 /* Using a list for this may seem overkill, but is really the only
1590 * right way to do this
1592 for (m
= l
; m
!= NULL
; m
= m
->next
) {
1593 GString
*s
= m
->data
;
1595 g_string_append_len (types
, s
->str
, s
->len
);
1596 g_string_free (s
, TRUE
);
1599 g_string_append (types
, ", ");
1603 types
= g_string_new (_("all"));
1604 /* The range name string will automatically be truncated, we don't
1605 * need to truncate the "types" list because it will not grow
1608 names
= undo_range_list_name (sheet
, selection
);
1609 descriptor
= g_strdup_printf (_("Clearing %s in %s"), types
->str
, names
);
1611 g_string_free (types
, TRUE
);
1612 size
= g_slist_length (selection
);
1614 clear_flags
|= CLEAR_NOCHECKARRAY
;
1616 if (clear_flags
& (CLEAR_VALUES
| CLEAR_FORMATS
))
1617 clear_flags
|= CLEAR_RECALC_DEPS
;
1619 /* We are now ready to build the redo and undo items */
1620 for (ranges
= selection
; ranges
!= NULL
; ranges
= ranges
->next
) {
1621 GnmRange
const *r
= ranges
->data
;
1622 GnmSheetRange
*sr
= gnm_sheet_range_new (sheet
, r
);
1624 undo
= go_undo_combine (undo
, clipboard_copy_range_undo (sheet
, r
));
1625 redo
= go_undo_combine
1626 (redo
, sheet_clear_region_undo
1630 range_fragment_free (selection
);
1632 result
= cmd_generic_with_size (wbc
, descriptor
, size
, undo
, redo
);
1633 g_free (descriptor
);
1638 /******************************************************************/
1640 #define CMD_FORMAT_TYPE (cmd_format_get_type ())
1641 #define CMD_FORMAT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_FORMAT_TYPE, CmdFormat))
1645 GnmStyleList
*styles
;
1646 ColRowIndexList
*rows
;
1647 ColRowStateGroup
*old_heights
;
1648 } CmdFormatOldStyle
;
1654 GnmStyle
*new_style
;
1655 GnmBorder
**borders
;
1659 cmd_format_repeat (GnmCommand
const *cmd
, WorkbookControl
*wbc
)
1661 CmdFormat
const *orig
= (CmdFormat
const *) cmd
;
1664 if (orig
->new_style
)
1665 gnm_style_ref (orig
->new_style
);
1667 for (i
= GNM_STYLE_BORDER_TOP
; i
< GNM_STYLE_BORDER_EDGE_MAX
; i
++)
1668 gnm_style_border_ref (orig
->borders
[i
]);
1670 cmd_selection_format (wbc
, orig
->new_style
, orig
->borders
, NULL
);
1672 MAKE_GNM_COMMAND (CmdFormat
, cmd_format
, cmd_format_repeat
)
1675 cmd_format_undo (GnmCommand
*cmd
,
1676 G_GNUC_UNUSED WorkbookControl
*wbc
)
1678 CmdFormat
*me
= CMD_FORMAT (cmd
);
1680 g_return_val_if_fail (me
!= NULL
, TRUE
);
1682 if (me
->old_styles
) {
1683 GSList
*rstyles
= g_slist_reverse (g_slist_copy (me
->old_styles
));
1684 GSList
*rsel
= g_slist_reverse (g_slist_copy (me
->selection
));
1687 for (l1
= rstyles
, l2
= rsel
; l1
; l1
= l1
->next
, l2
= l2
->next
) {
1688 CmdFormatOldStyle
*os
= l1
->data
;
1689 GnmRange
const *r
= l2
->data
;
1690 GnmSpanCalcFlags flags
= sheet_style_set_list
1692 &os
->pos
, os
->styles
, NULL
, NULL
);
1694 if (os
->old_heights
) {
1695 colrow_restore_state_group (me
->cmd
.sheet
, FALSE
,
1698 colrow_state_group_destroy (os
->old_heights
);
1699 os
->old_heights
= NULL
;
1700 colrow_index_list_destroy (os
->rows
);
1704 sheet_range_calc_spans (me
->cmd
.sheet
, r
, flags
);
1705 sheet_flag_style_update_range (me
->cmd
.sheet
, r
);
1708 sheet_redraw_all (me
->cmd
.sheet
, FALSE
);
1709 g_slist_free (rstyles
);
1710 g_slist_free (rsel
);
1713 select_selection (me
->cmd
.sheet
, me
->selection
, wbc
);
1719 cmd_format_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
1721 CmdFormat
*me
= CMD_FORMAT (cmd
);
1723 gboolean re_fit_height
;
1725 g_return_val_if_fail (me
!= NULL
, TRUE
);
1727 /* Check for locked cells */
1728 if (cmd_selection_is_locked_effective (me
->cmd
.sheet
, me
->selection
,
1729 wbc
, _("Changing Format")))
1732 re_fit_height
= me
->new_style
&&
1733 (GNM_SPANCALC_ROW_HEIGHT
& gnm_style_required_spanflags (me
->new_style
));
1735 for (l1
= me
->old_styles
, l2
= me
->selection
; l2
; l1
= l1
->next
, l2
= l2
->next
) {
1736 CmdFormatOldStyle
*os
= l1
->data
;
1737 GnmRange
const *r
= l2
->data
;
1740 sheet_apply_border (me
->cmd
.sheet
, r
, me
->borders
);
1741 if (me
->new_style
) {
1742 gnm_style_ref (me
->new_style
);
1743 sheet_apply_style (me
->cmd
.sheet
, r
, me
->new_style
);
1745 colrow_autofit (me
->cmd
.sheet
, r
, FALSE
, FALSE
,
1747 &os
->rows
, &os
->old_heights
);
1750 sheet_flag_style_update_range (me
->cmd
.sheet
, r
);
1752 sheet_redraw_all (me
->cmd
.sheet
, FALSE
);
1753 sheet_mark_dirty (me
->cmd
.sheet
);
1755 select_selection (me
->cmd
.sheet
, me
->selection
, wbc
);
1761 cmd_format_finalize (GObject
*cmd
)
1763 CmdFormat
*me
= CMD_FORMAT (cmd
);
1767 gnm_style_unref (me
->new_style
);
1768 me
->new_style
= NULL
;
1771 for (i
= GNM_STYLE_BORDER_TOP
; i
< GNM_STYLE_BORDER_EDGE_MAX
; i
++)
1772 gnm_style_border_unref (me
->borders
[i
]);
1773 g_free (me
->borders
);
1777 if (me
->old_styles
!= NULL
) {
1780 for (l
= me
->old_styles
; l
!= NULL
; l
= g_slist_remove (l
, l
->data
)) {
1781 CmdFormatOldStyle
*os
= l
->data
;
1783 style_list_free (os
->styles
);
1784 colrow_index_list_destroy (os
->rows
);
1785 colrow_state_group_destroy (os
->old_heights
);
1788 me
->old_styles
= NULL
;
1791 range_fragment_free (me
->selection
);
1792 me
->selection
= NULL
;
1794 gnm_command_finalize (cmd
);
1799 * @wbc: the workbook control.
1801 * @style: style to apply to the selection
1802 * @borders: borders to apply to the selection
1803 * @opt_translated_name: An optional name to use in place of 'Format Cells'
1805 * If borders is non NULL, then the GnmBorder references are passed,
1806 * the GnmStyle reference is also passed.
1808 * It absorbs the reference to the style.
1810 * Return value: TRUE if there was a problem
1813 cmd_selection_format (WorkbookControl
*wbc
,
1814 GnmStyle
*style
, GnmBorder
**borders
,
1815 char const *opt_translated_name
)
1819 SheetView
*sv
= wb_control_cur_sheet_view (wbc
);
1821 me
= g_object_new (CMD_FORMAT_TYPE
, NULL
);
1823 me
->selection
= selection_get_ranges (sv
, FALSE
); /* TRUE ? */
1824 me
->new_style
= style
;
1826 me
->cmd
.sheet
= sv_sheet (sv
);
1827 me
->cmd
.size
= 1; /* Updated below. */
1829 me
->old_styles
= NULL
;
1830 for (l
= me
->selection
; l
; l
= l
->next
) {
1831 GnmRange
const *sel_r
= l
->data
;
1832 GnmRange range
= *sel_r
;
1833 CmdFormatOldStyle
*os
;
1835 /* Store the containing range to handle borders */
1836 if (borders
!= NULL
) {
1837 if (range
.start
.col
> 0) range
.start
.col
--;
1838 if (range
.start
.row
> 0) range
.start
.row
--;
1839 if (range
.end
.col
< gnm_sheet_get_last_col (me
->cmd
.sheet
)) range
.end
.col
++;
1840 if (range
.end
.row
< gnm_sheet_get_last_row (me
->cmd
.sheet
)) range
.end
.row
++;
1843 os
= g_new (CmdFormatOldStyle
, 1);
1845 os
->styles
= sheet_style_get_range (me
->cmd
.sheet
, &range
);
1846 os
->pos
= range
.start
;
1848 os
->old_heights
= NULL
;
1850 me
->cmd
.size
+= g_slist_length (os
->styles
);
1851 me
->old_styles
= g_slist_append (me
->old_styles
, os
);
1857 me
->borders
= g_new (GnmBorder
*, GNM_STYLE_BORDER_EDGE_MAX
);
1858 for (i
= GNM_STYLE_BORDER_TOP
; i
< GNM_STYLE_BORDER_EDGE_MAX
; i
++)
1859 me
->borders
[i
] = borders
[i
];
1863 if (opt_translated_name
== NULL
) {
1864 char *names
= undo_range_list_name (me
->cmd
.sheet
, me
->selection
);
1866 me
->cmd
.cmd_descriptor
= g_strdup_printf (_("Changing format of %s"), names
);
1869 me
->cmd
.cmd_descriptor
= g_strdup (opt_translated_name
);
1871 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
1874 /******************************************************************/
1877 cmd_selection_format_toggle_font_style_filter (PangoAttribute
*attribute
, PangoAttrType
*pt
)
1879 return ((attribute
->klass
->type
== *pt
) ||
1880 ((PANGO_ATTR_RISE
== *pt
) && (attribute
->klass
->type
== PANGO_ATTR_SCALE
)));
1889 cmd_selection_format_toggle_font_style_cb (GnmCellIter
const *iter
, csftfs
*closure
)
1891 if (iter
->cell
&& iter
->cell
->value
&& VALUE_IS_STRING (iter
->cell
->value
)) {
1892 const GOFormat
*fmt
= VALUE_FMT (iter
->cell
->value
);
1893 if (fmt
&& go_format_is_markup (fmt
)) {
1894 const PangoAttrList
*old_markup
=
1895 go_format_get_markup (fmt
);
1896 PangoAttrList
*new_markup
= pango_attr_list_copy ((PangoAttrList
*)old_markup
);
1897 PangoAttrList
*other
= pango_attr_list_filter
1899 (PangoAttrFilterFunc
) cmd_selection_format_toggle_font_style_filter
,
1901 if (other
!= NULL
) {
1904 range_init_cellpos (&r
, &iter
->pp
.eval
);
1905 sr
= gnm_sheet_range_new (iter
->pp
.sheet
, &r
);
1906 closure
->undo
= go_undo_combine (closure
->undo
,
1907 sheet_range_set_markup_undo (sr
, new_markup
));
1909 pango_attr_list_unref (new_markup
);
1910 pango_attr_list_unref (other
);
1917 cmd_selection_format_toggle_font_style (WorkbookControl
*wbc
,
1918 GnmStyle
*style
, GnmStyleElement t
)
1920 SheetView
*sv
= wb_control_cur_sheet_view (wbc
);
1921 Sheet
*sheet
= sv
->sheet
;
1922 GSList
*selection
= selection_get_ranges (sv
, FALSE
), *l
;
1925 GOUndo
*undo
= NULL
;
1926 GOUndo
*redo
= NULL
;
1931 case MSTYLE_FONT_BOLD
:
1932 pt
= PANGO_ATTR_WEIGHT
;
1934 case MSTYLE_FONT_ITALIC
:
1935 pt
= PANGO_ATTR_STYLE
;
1937 case MSTYLE_FONT_UNDERLINE
:
1938 pt
= PANGO_ATTR_UNDERLINE
;
1940 case MSTYLE_FONT_STRIKETHROUGH
:
1941 pt
= PANGO_ATTR_STRIKETHROUGH
;
1943 case MSTYLE_FONT_SCRIPT
:
1944 pt
= PANGO_ATTR_RISE
; /* and PANGO_ATTR_SCALE (see ) */
1947 pt
= PANGO_ATTR_INVALID
;
1952 name
= undo_range_list_name (sheet
, selection
);
1953 text
= g_strdup_printf (_("Setting Font Style of %s"), name
);
1956 for (l
= selection
; l
!= NULL
; l
= l
->next
) {
1958 undo
= go_undo_combine
1959 (undo
, clipboard_copy_range_undo (sheet
, l
->data
));
1960 sr
= gnm_sheet_range_new (sheet
, l
->data
);
1961 redo
= go_undo_combine
1962 (redo
, sheet_apply_style_undo (sr
, style
));
1963 if (pt
!= PANGO_ATTR_INVALID
) {
1965 closure
.undo
= NULL
;
1967 sheet_foreach_cell_in_range
1968 (sheet
, CELL_ITER_IGNORE_BLANK
, &sr
->range
,
1969 (CellIterFunc
) cmd_selection_format_toggle_font_style_cb
,
1971 redo
= go_undo_combine (redo
, closure
.undo
);
1974 gnm_style_unref (style
);
1975 result
= cmd_generic (wbc
, text
, undo
, redo
);
1977 range_fragment_free (selection
);
1983 /******************************************************************/
1987 cmd_resize_colrow (WorkbookControl
*wbc
, Sheet
*sheet
,
1988 gboolean is_cols
, ColRowIndexList
*selection
,
1993 GOUndo
*undo
= NULL
;
1994 GOUndo
*redo
= NULL
;
1995 gboolean is_single
, result
;
1997 ColRowStateGroup
*saved_state
;
1999 list
= colrow_index_list_to_string (selection
, is_cols
, &is_single
);
2000 gnm_cmd_trunc_descriptor (list
, NULL
);
2005 ? g_strdup_printf (_("Autofitting column %s"), list
->str
)
2006 : g_strdup_printf (_("Autofitting row %s"), list
->str
);
2007 else if (new_size
> 0)
2009 ? g_strdup_printf (ngettext ("Setting width of column %s to %d pixel",
2010 "Setting width of column %s to %d pixels",
2012 list
->str
, new_size
)
2013 : g_strdup_printf (ngettext ("Setting height of row %s to %d pixel",
2014 "Setting height of row %s to %d pixels",
2016 list
->str
, new_size
);
2018 ? g_strdup_printf (_("Setting width of column %s to default"),
2021 _("Setting height of row %s to default"), list
->str
);
2025 ? g_strdup_printf (_("Autofitting columns %s"), list
->str
)
2026 : g_strdup_printf (_("Autofitting rows %s"), list
->str
);
2027 else if (new_size
> 0)
2029 ? g_strdup_printf (ngettext("Setting width of columns %s to %d pixel",
2030 "Setting width of columns %s to %d pixels",
2032 list
->str
, new_size
)
2033 : g_strdup_printf (ngettext("Setting height of rows %s to %d pixel",
2034 "Setting height of rows %s to %d pixels",
2036 list
->str
, new_size
);
2039 _("Setting width of columns %s to default"), list
->str
)
2041 _("Setting height of rows %s to default"), list
->str
);
2043 g_string_free (list
, TRUE
);
2045 saved_state
= colrow_get_sizes (sheet
, is_cols
, selection
, new_size
);
2046 undo
= gnm_undo_colrow_restore_state_group_new
2047 (sheet
, is_cols
, colrow_index_list_copy (selection
), saved_state
);
2049 redo
= gnm_undo_colrow_set_sizes_new (sheet
, is_cols
, selection
, new_size
, NULL
);
2051 result
= cmd_generic_with_size (wbc
, text
, size
, undo
, redo
);
2058 cmd_autofit_selection (WorkbookControl
*wbc
, SheetView
*sv
, Sheet
*sheet
, gboolean fit_width
,
2059 ColRowIndexList
*selectionlist
)
2061 GOUndo
*undo
= NULL
;
2062 GOUndo
*redo
= NULL
;
2064 ColRowStateGroup
*saved_state
;
2065 GSList
*l
, *selection
= selection_get_ranges (sv
, TRUE
);
2066 gchar
*names
= undo_range_list_name (sheet
, selection
);
2067 gchar
const *format
= fit_width
?
2068 N_("Autofitting width of %s") : N_("Autofitting height of %s");
2069 gchar
*text
= g_strdup_printf (_(format
), names
);
2073 saved_state
= colrow_get_sizes (sheet
, fit_width
, selectionlist
, -1);
2074 undo
= gnm_undo_colrow_restore_state_group_new
2075 (sheet
, fit_width
, colrow_index_list_copy (selectionlist
), saved_state
);
2077 for (l
= selection
; l
!= NULL
; l
= l
->next
)
2078 redo
= go_undo_combine
2079 (redo
, gnm_undo_colrow_set_sizes_new
2080 (sheet
, fit_width
, NULL
, -1, l
->data
));
2082 result
= cmd_generic (wbc
, text
, undo
, redo
);
2088 /******************************************************************/
2090 #define CMD_SORT_TYPE (cmd_sort_get_type ())
2091 #define CMD_SORT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_SORT_TYPE, CmdSort))
2098 GnmCellRegion
*old_contents
;
2101 MAKE_GNM_COMMAND (CmdSort
, cmd_sort
, NULL
)
2104 cmd_sort_finalize (GObject
*cmd
)
2106 CmdSort
*me
= CMD_SORT (cmd
);
2108 if (me
->data
!= NULL
)
2109 gnm_sort_data_destroy (me
->data
);
2111 if (me
->old_contents
!= NULL
)
2112 cellregion_unref (me
->old_contents
);
2114 gnm_command_finalize (cmd
);
2118 cmd_sort_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
2120 CmdSort
*me
= CMD_SORT (cmd
);
2121 GnmSortData
*data
= me
->data
;
2124 paste_target_init (&pt
, data
->sheet
, data
->range
,
2125 PASTE_CONTENTS
| PASTE_FORMATS
|
2126 (data
->retain_formats
? PASTE_FORMATS
: 0));
2127 clipboard_paste_region (me
->old_contents
,
2129 GO_CMD_CONTEXT (wbc
));
2135 cmd_sort_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
2137 CmdSort
*me
= CMD_SORT (cmd
);
2138 GnmSortData
*data
= me
->data
;
2140 /* Check for locks */
2141 if (cmd_cell_range_is_locked_effective
2142 (data
->sheet
, data
->range
, wbc
, _("Sorting")))
2146 gnm_sort_position (data
, me
->perm
, GO_CMD_CONTEXT (wbc
));
2149 clipboard_copy_range (data
->sheet
, data
->range
);
2150 me
->cmd
.size
= cellregion_cmd_size (me
->old_contents
);
2151 me
->perm
= gnm_sort_contents (data
, GO_CMD_CONTEXT (wbc
));
2158 cmd_sort (WorkbookControl
*wbc
, GnmSortData
*data
)
2163 g_return_val_if_fail (data
!= NULL
, TRUE
);
2165 desc
= g_strdup_printf (_("Sorting %s"), range_as_string (data
->range
));
2166 if (sheet_range_contains_merges_or_arrays (data
->sheet
, data
->range
, GO_CMD_CONTEXT (wbc
), desc
, TRUE
, TRUE
)) {
2167 gnm_sort_data_destroy (data
);
2172 me
= g_object_new (CMD_SORT_TYPE
, NULL
);
2176 me
->cmd
.sheet
= data
->sheet
;
2177 me
->cmd
.size
= 1; /* Changed in initial redo. */
2178 me
->cmd
.cmd_descriptor
= desc
;
2180 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
2183 /******************************************************************/
2185 #define CMD_COLROW_HIDE_TYPE (cmd_colrow_hide_get_type ())
2186 #define CMD_COLROW_HIDE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_COLROW_HIDE_TYPE, CmdColRowHide))
2192 ColRowVisList
*hide
, *show
;
2196 cmd_colrow_hide_repeat (GnmCommand
const *cmd
, WorkbookControl
*wbc
)
2198 CmdColRowHide
const *orig
= (CmdColRowHide
const *) cmd
;
2199 cmd_selection_colrow_hide (wbc
, orig
->is_cols
, orig
->show
!= NULL
);
2201 MAKE_GNM_COMMAND (CmdColRowHide
, cmd_colrow_hide
, cmd_colrow_hide_repeat
)
2204 * cmd_colrow_hide_correct_selection:
2206 * Try to ensure that the selection/cursor is set to a visible row/col
2208 * Added to fix bug 38179
2209 * Removed because the result is irritating and the bug is actually XL
2213 cmd_colrow_hide_correct_selection (G_GNUC_UNUSED CmdColRowHide
*me
, G_GNUC_UNUSED WorkbookControl
*wbc
)
2217 SheetView
*sv
= sheet_get_view (me
->cmd
.sheet
,
2218 wb_control_view (wbc
));
2220 index
= colrow_find_adjacent_visible (me
->cmd
.sheet
, me
->is_cols
,
2221 me
->is_cols
? sv
->edit_pos
.col
: sv
->edit_pos
.row
,
2224 x
= me
->is_cols
? sv
->edit_pos
.row
: index
;
2225 y
= me
->is_cols
? index
: sv
->edit_pos
.col
;
2228 sv_selection_reset (sv
);
2230 sv_selection_add_full (sv
, y
, x
, y
, 0,
2231 y
, gnm_sheet_get_last_row (sheet
),
2232 GNM_SELECTION_MODE_ADD
);
2234 sv_selection_add_full (sv
, y
, x
, 0, x
,
2235 gnm_sheet_get_last_col (sheet
), x
,
2236 GNM_SELECTION_MODE_ADD
);
2242 cmd_colrow_hide_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
2244 CmdColRowHide
*me
= CMD_COLROW_HIDE (cmd
);
2246 g_return_val_if_fail (me
!= NULL
, TRUE
);
2248 colrow_set_visibility_list (me
->cmd
.sheet
, me
->is_cols
,
2250 colrow_set_visibility_list (me
->cmd
.sheet
, me
->is_cols
,
2253 if (me
->show
!= NULL
)
2254 cmd_colrow_hide_correct_selection (me
, wbc
);
2260 cmd_colrow_hide_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
2262 CmdColRowHide
*me
= CMD_COLROW_HIDE (cmd
);
2264 g_return_val_if_fail (me
!= NULL
, TRUE
);
2266 colrow_set_visibility_list (me
->cmd
.sheet
, me
->is_cols
,
2268 colrow_set_visibility_list (me
->cmd
.sheet
, me
->is_cols
,
2271 if (me
->hide
!= NULL
)
2272 cmd_colrow_hide_correct_selection (me
, wbc
);
2278 cmd_colrow_hide_finalize (GObject
*cmd
)
2280 CmdColRowHide
*me
= CMD_COLROW_HIDE (cmd
);
2281 colrow_vis_list_destroy (me
->hide
);
2283 colrow_vis_list_destroy (me
->show
);
2285 gnm_command_finalize (cmd
);
2289 cmd_selection_colrow_hide (WorkbookControl
*wbc
,
2290 gboolean is_cols
, gboolean visible
)
2293 SheetView
*sv
= wb_control_cur_sheet_view (wbc
);
2296 GSList
*show
= NULL
, *hide
= NULL
;
2299 show
= colrow_get_visibility_toggle (sv
, is_cols
, TRUE
);
2301 hide
= colrow_get_visibility_toggle (sv
, is_cols
, FALSE
);
2302 n
= colrow_vis_list_length (hide
) + colrow_vis_list_length (show
);
2303 sheet
= sv_sheet (sv
);
2306 /* If these are the last colrows to hide, check with the user */
2309 int i
, max
= gnm_sheet_get_max_cols (sheet
);
2311 for (i
= 0 ; i
< max
; i
++)
2313 (ci
= sheet_col_get (sheet
, i
)) ||
2317 int i
, max
= gnm_sheet_get_max_rows (sheet
);
2319 for (i
= 0 ; i
< max
; i
++)
2321 (ci
= sheet_row_get (sheet
, i
)) ||
2326 gchar
const *text
= is_cols
?
2327 _("Are you sure that you want to hide all columns? "
2328 "If you do so you can unhide them with the "
2329 "'Format\342\206\222Column\342\206\222Unhide' "
2331 _("Are you sure that you want to hide all rows? "
2332 "If you do so you can unhide them with the "
2333 "'Format\342\206\222Row\342\206\222Unhide' "
2335 if (!go_gtk_query_yes_no (wbcg_toplevel (WBC_GTK (wbc
)),
2336 FALSE
, "%s", text
)) {
2337 colrow_vis_list_destroy (show
);
2338 colrow_vis_list_destroy (hide
);
2344 me
= g_object_new (CMD_COLROW_HIDE_TYPE
, NULL
);
2347 me
->is_cols
= is_cols
;
2348 me
->cmd
.sheet
= sheet
;
2349 me
->cmd
.size
= 1 + g_slist_length (hide
) + g_slist_length (show
);
2350 me
->cmd
.cmd_descriptor
= g_strdup (is_cols
2351 ? (visible
? _("Unhide columns") : _("Hide columns"))
2352 : (visible
? _("Unhide rows") : _("Hide rows")));
2354 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
2358 cmd_selection_outline_change (WorkbookControl
*wbc
,
2359 gboolean is_cols
, int index
, int depth
)
2362 ColRowInfo
const *cri
;
2363 int first
= -1, last
= -1;
2364 gboolean visible
= FALSE
;
2366 Sheet
*sheet
= wb_control_cur_sheet (wbc
);
2367 SheetView
*sv
= wb_control_cur_sheet_view (wbc
);
2369 cri
= sheet_colrow_get_info (sheet
, index
, is_cols
);
2371 d
= cri
->outline_level
;
2375 /* Nodes only collapse when selected directly, selecting at a lower
2376 * level is a standard toggle. */
2378 if ((is_cols
? sheet
->outline_symbols_right
: sheet
->outline_symbols_below
)) {
2380 ColRowInfo
const *prev
=
2381 sheet_colrow_get (sheet
, index
-1, is_cols
);
2383 if (prev
!= NULL
&& prev
->outline_level
> d
) {
2384 visible
= (depth
== d
&& cri
->is_collapsed
);
2386 first
= colrow_find_outline_bound (sheet
, is_cols
,
2390 } else if (index
+1 < colrow_max (is_cols
, sheet
)) {
2391 ColRowInfo
const *next
=
2392 sheet_colrow_get (sheet
, index
+1, is_cols
);
2394 if (next
!= NULL
&& next
->outline_level
> d
) {
2395 visible
= (depth
== d
&& cri
->is_collapsed
);
2397 last
= colrow_find_outline_bound (sheet
, is_cols
,
2403 /* If nothing done yet do a simple collapse */
2404 if (first
< 0 && cri
->outline_level
> 0) {
2407 first
= colrow_find_outline_bound (sheet
, is_cols
, index
, depth
, FALSE
);
2408 last
= colrow_find_outline_bound (sheet
, is_cols
, index
, depth
, TRUE
);
2411 if (first
== last
&& depth
> cri
->outline_level
)
2415 if (first
< 0 || last
< 0)
2418 me
= g_object_new (CMD_COLROW_HIDE_TYPE
, NULL
);
2420 me
->is_cols
= is_cols
;
2421 me
->hide
= me
->show
= NULL
;
2423 me
->show
= colrow_get_outline_toggle (sv_sheet (sv
), is_cols
,
2426 me
->hide
= colrow_get_outline_toggle (sv_sheet (sv
), is_cols
,
2427 FALSE
, first
, last
);
2429 me
->cmd
.sheet
= sv_sheet (sv
);
2430 me
->cmd
.size
= 1 + g_slist_length (me
->show
) + g_slist_length (me
->hide
);
2431 me
->cmd
.cmd_descriptor
= g_strdup (is_cols
2432 ? (visible
? _("Expand columns") : _("Collapse columns"))
2433 : (visible
? _("Expand rows") : _("Collapse rows")));
2435 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
2439 cmd_global_outline_change (WorkbookControl
*wbc
, gboolean is_cols
, int depth
)
2442 ColRowVisList
*hide
, *show
;
2443 SheetView
*sv
= wb_control_cur_sheet_view (wbc
);
2445 colrow_get_global_outline (sv_sheet (sv
), is_cols
, depth
, &show
, &hide
);
2447 if (show
== NULL
&& hide
== NULL
)
2450 me
= g_object_new (CMD_COLROW_HIDE_TYPE
, NULL
);
2451 me
->is_cols
= is_cols
;
2454 me
->cmd
.sheet
= sv_sheet (sv
);
2455 me
->cmd
.size
= 1 + g_slist_length (me
->show
) + g_slist_length (me
->hide
);
2456 me
->cmd
.cmd_descriptor
= g_strdup_printf (is_cols
2457 ? _("Show column outline %d") : _("Show row outline %d"), depth
);
2459 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
2462 /******************************************************************/
2464 #define CMD_GROUP_TYPE (cmd_group_get_type ())
2465 #define CMD_GROUP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_GROUP_TYPE, CmdGroup))
2476 cmd_group_repeat (GnmCommand
const *cmd
, WorkbookControl
*wbc
)
2478 CmdGroup
const *orig
= (CmdGroup
const *) cmd
;
2479 cmd_selection_group (wbc
, orig
->is_cols
, orig
->group
);
2481 MAKE_GNM_COMMAND (CmdGroup
, cmd_group
, cmd_group_repeat
)
2484 cmd_group_undo (GnmCommand
*cmd
,
2485 G_GNUC_UNUSED WorkbookControl
*wbc
)
2487 CmdGroup
const *me
= CMD_GROUP (cmd
);
2488 sheet_colrow_group_ungroup (me
->cmd
.sheet
,
2489 &me
->range
, me
->is_cols
, !me
->group
);
2494 cmd_group_redo (GnmCommand
*cmd
,
2495 G_GNUC_UNUSED WorkbookControl
*wbc
)
2497 CmdGroup
const *me
= CMD_GROUP (cmd
);
2498 sheet_colrow_group_ungroup (me
->cmd
.sheet
,
2499 &me
->range
, me
->is_cols
, me
->group
);
2504 cmd_group_finalize (GObject
*cmd
)
2506 gnm_command_finalize (cmd
);
2510 cmd_selection_group (WorkbookControl
*wbc
,
2511 gboolean is_cols
, gboolean group
)
2517 g_return_val_if_fail (wbc
!= NULL
, TRUE
);
2519 sv
= wb_control_cur_sheet_view (wbc
);
2520 r
= *selection_first_range (sv
, NULL
, NULL
);
2522 /* Check if this really is possible and display an error if it's not */
2523 if (sheet_colrow_can_group (sv
->sheet
, &r
, is_cols
) != group
) {
2525 go_cmd_context_error_system (GO_CMD_CONTEXT (wbc
), is_cols
2526 ? _("Those columns are already grouped")
2527 : _("Those rows are already grouped"));
2531 /* see if the user selected the col/row with the marker too */
2533 if (r
.start
.col
!= r
.end
.col
) {
2534 if (sv
->sheet
->outline_symbols_right
)
2540 if (r
.start
.row
!= r
.end
.row
) {
2541 if (sv
->sheet
->outline_symbols_below
)
2548 if (sheet_colrow_can_group (sv
->sheet
, &r
, is_cols
) != group
) {
2549 go_cmd_context_error_system (GO_CMD_CONTEXT (wbc
), is_cols
2550 ? _("Those columns are not grouped, you can't ungroup them")
2551 : _("Those rows are not grouped, you can't ungroup them"));
2556 me
= g_object_new (CMD_GROUP_TYPE
, NULL
);
2557 me
->is_cols
= is_cols
;
2561 me
->cmd
.sheet
= sv
->sheet
;
2563 me
->cmd
.cmd_descriptor
= is_cols
2564 ? g_strdup_printf (group
? _("Group columns %s") : _("Ungroup columns %s"),
2565 cols_name (me
->range
.start
.col
, me
->range
.end
.col
))
2566 : g_strdup_printf (group
? _("Group rows %d:%d") : _("Ungroup rows %d:%d"),
2567 me
->range
.start
.row
+ 1, me
->range
.end
.row
+ 1);
2569 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
2572 /******************************************************************/
2574 #define CMD_PASTE_CUT_TYPE (cmd_paste_cut_get_type ())
2575 #define CMD_PASTE_CUT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_PASTE_CUT_TYPE, CmdPasteCut))
2580 GnmExprRelocateInfo info
;
2581 GSList
*paste_contents
;
2583 gboolean move_selection
;
2584 ColRowStateList
*saved_sizes
;
2586 /* handle redo-ing an undo with contents from a deleted sheet */
2587 GnmCellRegion
*deleted_sheet_contents
;
2590 MAKE_GNM_COMMAND (CmdPasteCut
, cmd_paste_cut
, NULL
)
2594 GnmCellRegion
*contents
;
2598 * cmd_paste_cut_update:
2600 * Utility routine to update things when we are transfering between sheets and
2604 cmd_paste_cut_update (GnmExprRelocateInfo
const *info
,
2605 G_GNUC_UNUSED WorkbookControl
*wbc
)
2607 Sheet
*o
= info
->origin_sheet
;
2608 Sheet
*t
= info
->target_sheet
;
2610 /* Dirty and update both sheets */
2611 sheet_mark_dirty (t
);
2614 if (IS_SHEET (o
) && o
!= t
) {
2615 sheet_mark_dirty (o
);
2621 cmd_paste_cut_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
2623 CmdPasteCut
*me
= CMD_PASTE_CUT (cmd
);
2624 GnmExprRelocateInfo reverse
;
2626 g_return_val_if_fail (me
!= NULL
, TRUE
);
2627 g_return_val_if_fail (me
->paste_contents
!= NULL
, TRUE
);
2628 g_return_val_if_fail (me
->deleted_sheet_contents
== NULL
, TRUE
);
2630 reverse
.reloc_type
= GNM_EXPR_RELOCATE_MOVE_RANGE
;
2631 reverse
.target_sheet
= me
->info
.origin_sheet
;
2632 reverse
.origin_sheet
= me
->info
.target_sheet
;
2633 reverse
.origin
= me
->info
.origin
;
2634 range_translate (&reverse
.origin
,
2635 me
->info
.origin_sheet
, /* FIXME: What sheet? */
2636 me
->info
.col_offset
,
2637 me
->info
.row_offset
);
2638 reverse
.col_offset
= -me
->info
.col_offset
;
2639 reverse
.row_offset
= -me
->info
.row_offset
;
2641 /* Move things back being careful NOT to invalidate the src region */
2642 if (IS_SHEET (me
->info
.origin_sheet
))
2643 sheet_move_range (&reverse
, NULL
, GO_CMD_CONTEXT (wbc
));
2645 me
->deleted_sheet_contents
= clipboard_copy_range (
2646 reverse
.origin_sheet
, &reverse
.origin
);
2648 /* Restore the original row heights */
2649 colrow_set_states (me
->info
.target_sheet
, FALSE
,
2650 reverse
.origin
.start
.row
, me
->saved_sizes
);
2651 colrow_state_list_destroy (me
->saved_sizes
);
2652 me
->saved_sizes
= NULL
;
2654 if (me
->reloc_undo
) {
2655 go_undo_undo (me
->reloc_undo
);
2656 g_object_unref (me
->reloc_undo
);
2657 me
->reloc_undo
= NULL
;
2660 while (me
->paste_contents
) {
2661 PasteContent
*pc
= me
->paste_contents
->data
;
2662 me
->paste_contents
= g_slist_remove (me
->paste_contents
, pc
);
2664 clipboard_paste_region (pc
->contents
, &pc
->pt
, GO_CMD_CONTEXT (wbc
));
2665 cellregion_unref (pc
->contents
);
2669 /* Force update of the status area */
2670 sheet_flag_status_update_range (me
->info
.target_sheet
, NULL
);
2672 cmd_paste_cut_update (&me
->info
, wbc
);
2674 /* Select the original region */
2675 if (me
->move_selection
&& IS_SHEET (me
->info
.origin_sheet
))
2676 select_range (me
->info
.origin_sheet
,
2684 cmd_paste_cut_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
2686 CmdPasteCut
*me
= CMD_PASTE_CUT (cmd
);
2689 g_return_val_if_fail (me
!= NULL
, TRUE
);
2690 g_return_val_if_fail (me
->paste_contents
== NULL
, TRUE
);
2692 tmp
= me
->info
.origin
;
2693 range_translate (&tmp
, me
->info
.origin_sheet
, /* FIXME: What sheet? */
2694 me
->info
.col_offset
, me
->info
.row_offset
);
2695 range_normalize (&tmp
);
2697 g_return_val_if_fail (range_is_sane (&tmp
), TRUE
);
2699 if (me
->info
.origin_sheet
!= me
->info
.target_sheet
||
2700 !range_overlap (&me
->info
.origin
, &tmp
)) {
2701 PasteContent
*pc
= g_new (PasteContent
, 1);
2702 paste_target_init (&pc
->pt
, me
->info
.target_sheet
, &tmp
, PASTE_ALL_SHEET
);
2703 pc
->contents
= clipboard_copy_range (me
->info
.target_sheet
, &tmp
);
2704 me
->paste_contents
= g_slist_prepend (me
->paste_contents
, pc
);
2706 /* need to store any portions of the paste target
2707 * that do not overlap with the source.
2709 GSList
*ptr
, *frag
= range_split_ranges (&me
->info
.origin
, &tmp
);
2710 for (ptr
= frag
; ptr
!= NULL
; ptr
= ptr
->next
) {
2711 GnmRange
*r
= ptr
->data
;
2713 if (!range_overlap (&me
->info
.origin
, r
)) {
2714 PasteContent
*pc
= g_new (PasteContent
, 1);
2715 paste_target_init (&pc
->pt
, me
->info
.target_sheet
, r
, PASTE_ALL_SHEET
);
2716 pc
->contents
= clipboard_copy_range (me
->info
.target_sheet
, r
);
2717 me
->paste_contents
= g_slist_prepend (me
->paste_contents
, pc
);
2721 g_slist_free (frag
);
2724 /* rare corner case. If the origin sheet has been deleted */
2725 if (!IS_SHEET (me
->info
.origin_sheet
)) {
2727 paste_target_init (&pt
, me
->info
.target_sheet
, &tmp
, PASTE_ALL_SHEET
);
2728 sheet_clear_region (pt
.sheet
,
2729 tmp
.start
.col
, tmp
.start
.row
, tmp
.end
.col
, tmp
.end
.row
,
2730 CLEAR_VALUES
| CLEAR_MERGES
| CLEAR_NOCHECKARRAY
| CLEAR_RECALC_DEPS
,
2731 GO_CMD_CONTEXT (wbc
));
2732 clipboard_paste_region (me
->deleted_sheet_contents
,
2733 &pt
, GO_CMD_CONTEXT (wbc
));
2734 cellregion_unref (me
->deleted_sheet_contents
);
2735 me
->deleted_sheet_contents
= NULL
;
2737 sheet_move_range (&me
->info
, &me
->reloc_undo
, GO_CMD_CONTEXT (wbc
));
2739 cmd_paste_cut_update (&me
->info
, wbc
);
2741 /* Backup row heights and adjust row heights to fit */
2742 me
->saved_sizes
= colrow_get_states (me
->info
.target_sheet
, FALSE
, tmp
.start
.row
, tmp
.end
.row
);
2743 rows_height_update (me
->info
.target_sheet
, &tmp
, FALSE
);
2745 /* Make sure the destination is selected */
2746 if (me
->move_selection
)
2747 select_range (me
->info
.target_sheet
, &tmp
, wbc
);
2753 cmd_paste_cut_finalize (GObject
*cmd
)
2755 CmdPasteCut
*me
= CMD_PASTE_CUT (cmd
);
2757 if (me
->saved_sizes
)
2758 me
->saved_sizes
= colrow_state_list_destroy (me
->saved_sizes
);
2759 while (me
->paste_contents
) {
2760 PasteContent
*pc
= me
->paste_contents
->data
;
2761 me
->paste_contents
= g_slist_remove (me
->paste_contents
, pc
);
2762 cellregion_unref (pc
->contents
);
2765 if (me
->reloc_undo
) {
2766 g_object_unref (me
->reloc_undo
);
2767 me
->reloc_undo
= NULL
;
2769 if (me
->deleted_sheet_contents
) {
2770 cellregion_unref (me
->deleted_sheet_contents
);
2771 me
->deleted_sheet_contents
= NULL
;
2774 gnm_command_finalize (cmd
);
2778 cmd_paste_cut (WorkbookControl
*wbc
, GnmExprRelocateInfo
const *info
,
2779 gboolean move_selection
, char *descriptor
)
2785 g_return_val_if_fail (info
!= NULL
, TRUE
);
2787 /* This is vacuous */
2788 if (info
->origin_sheet
== info
->target_sheet
&&
2789 info
->col_offset
== 0 && info
->row_offset
== 0)
2792 /* FIXME: Do we want to show the destination range as well ? */
2793 where
= undo_range_name (info
->origin_sheet
, &info
->origin
);
2794 if (descriptor
== NULL
)
2795 descriptor
= g_strdup_printf (_("Moving %s"), where
);
2798 g_return_val_if_fail (info
!= NULL
, TRUE
);
2801 if (range_translate (&r
, info
->target_sheet
,
2802 info
->col_offset
, info
->row_offset
)) {
2804 go_cmd_context_error_invalid (GO_CMD_CONTEXT (wbc
), descriptor
,
2805 _("is beyond sheet boundaries"));
2806 g_free (descriptor
);
2810 /* Check array subdivision & merged regions */
2811 if (sheet_range_splits_region (info
->target_sheet
, &r
,
2812 (info
->origin_sheet
== info
->target_sheet
)
2813 ? &info
->origin
: NULL
, GO_CMD_CONTEXT (wbc
), descriptor
)) {
2814 g_free (descriptor
);
2818 me
= g_object_new (CMD_PASTE_CUT_TYPE
, NULL
);
2821 me
->paste_contents
= NULL
;
2822 me
->deleted_sheet_contents
= NULL
;
2823 me
->reloc_undo
= NULL
;
2824 me
->move_selection
= move_selection
;
2825 me
->saved_sizes
= NULL
;
2827 me
->cmd
.sheet
= NULL
; /* we have potentially two different. */
2828 me
->cmd
.size
= 1; /* FIXME? */
2829 me
->cmd
.cmd_descriptor
= descriptor
;
2831 /* NOTE : if the destination workbook is different from the source
2832 * workbook should we have undo elements in both menus ?? It seems
2833 * poor form to hit undo in 1 window and effect another...
2835 * Maybe queue it as two different commands, as a clear in one book
2836 * and a paste in the other. This is not symmetric though. What
2837 * happens to the cells in the original sheet that now reference the
2838 * cells in the other? When do they reset to the original?
2840 * Probably when the clear in the original is undone.
2843 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
2846 /******************************************************************/
2849 warn_if_date_trouble (WorkbookControl
*wbc
, GnmCellRegion
*cr
)
2851 Workbook
*wb
= wb_control_get_workbook (wbc
);
2852 const GODateConventions
*wb_date_conv
= workbook_date_conv (wb
);
2854 if (cr
->date_conv
== NULL
)
2856 if (go_date_conv_equal (cr
->date_conv
, wb_date_conv
))
2859 /* We would like to show a warning, but it seems we cannot via a context. */
2862 err
= g_error_new (go_error_invalid(), 0,
2863 _("Copying between files with different date conventions.\n"
2864 "It is possible that some dates could be copied\n"
2866 go_cmd_context_error (GO_CMD_CONTEXT (wbc
), err
);
2872 #define CMD_PASTE_COPY_TYPE (cmd_paste_copy_get_type ())
2873 #define CMD_PASTE_COPY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_PASTE_COPY_TYPE, CmdPasteCopy))
2878 GnmCellRegion
*contents
;
2879 GSList
*pasted_objects
,*orig_contents_objects
;
2881 gboolean has_been_through_cycle
;
2882 gboolean only_objects
;
2883 gboolean single_merge_to_single_merge
;
2887 cmd_paste_copy_repeat (GnmCommand
const *cmd
, WorkbookControl
*wbc
)
2889 CmdPasteCopy
const *orig
= (CmdPasteCopy
const *) cmd
;
2890 GnmPasteTarget new_dst
;
2891 SheetView
*sv
= wb_control_cur_sheet_view (wbc
);
2892 GnmRange
const *r
= selection_first_range (sv
,
2893 GO_CMD_CONTEXT (wbc
), _("Paste Copy"));
2894 GnmCellRegion
*newcr
;
2899 paste_target_init (&new_dst
, sv_sheet (sv
), r
, orig
->dst
.paste_flags
);
2900 newcr
= clipboard_copy_range (orig
->dst
.sheet
, &orig
->dst
.range
);
2901 cmd_paste_copy (wbc
, &new_dst
, newcr
);
2902 cellregion_unref (newcr
);
2904 MAKE_GNM_COMMAND (CmdPasteCopy
, cmd_paste_copy
, cmd_paste_copy_repeat
)
2907 by_addr (gconstpointer a
, gconstpointer b
)
2909 if (GPOINTER_TO_UINT (a
) < GPOINTER_TO_UINT (b
))
2911 if (GPOINTER_TO_UINT (a
) > GPOINTER_TO_UINT (b
))
2918 * @sheet: #Sheet to query
2919 * @old: (element-type SheetObject): list of objects to disregard
2921 * Returns: (transfer full) (element-type SheetObject): A list of new objects
2922 * in sheet since @old was collected.
2925 get_new_objects (Sheet
*sheet
, GSList
*old
)
2928 g_slist_sort (g_slist_copy_deep (sheet
->sheet_objects
,
2929 (GCopyFunc
)g_object_ref
,
2932 GSList
*p
= objs
, *last
= NULL
;
2936 while (p
&& (c
= by_addr (p
->data
, old
->data
)) < 0) {
2944 GSList
*next
= p
->next
;
2958 cmd_paste_copy_select_obj (SheetObject
*so
, SheetControlGUI
*scg
)
2960 scg_object_select (scg
, so
);
2964 cmd_paste_copy_impl (GnmCommand
*cmd
, WorkbookControl
*wbc
,
2967 CmdPasteCopy
*me
= CMD_PASTE_COPY (cmd
);
2968 GnmCellRegion
*contents
;
2969 GSList
*old_objects
;
2971 g_return_val_if_fail (me
!= NULL
, TRUE
);
2972 g_return_val_if_fail (me
->contents
!= NULL
, TRUE
);
2974 g_slist_foreach (me
->pasted_objects
,
2975 (GFunc
)sheet_object_clear_sheet
,
2977 g_slist_free_full (me
->pasted_objects
, (GDestroyNotify
)g_object_unref
);
2978 me
->pasted_objects
= NULL
;
2979 old_objects
= get_new_objects (me
->dst
.sheet
, NULL
);
2981 contents
= clipboard_copy_range (me
->dst
.sheet
, &me
->dst
.range
);
2982 if (me
->has_been_through_cycle
)
2983 me
->dst
.paste_flags
=
2985 PASTE_COLUMN_WIDTHS
| PASTE_ROW_HEIGHTS
|
2986 (me
->dst
.paste_flags
& PASTE_ALL_SHEET
);
2988 if (clipboard_paste_region (me
->contents
, &me
->dst
,
2989 GO_CMD_CONTEXT (wbc
))) {
2990 /* There was a problem, avoid leaking */
2991 cellregion_unref (contents
);
2992 g_slist_free_full (old_objects
, g_object_unref
);
2996 me
->pasted_objects
= get_new_objects (me
->dst
.sheet
, old_objects
);
2997 g_slist_free_full (old_objects
, g_object_unref
);
2999 if (!is_undo
&& !me
->has_been_through_cycle
) {
3000 colrow_autofit (me
->dst
.sheet
, &me
->dst
.range
, FALSE
, FALSE
,
3003 colrow_autofit (me
->dst
.sheet
, &me
->dst
.range
, TRUE
, TRUE
,
3009 // We cannot use the random set of objects at the target
3010 // location. http://bugzilla.gnome.org/show_bug.cgi?id=308300
3011 g_slist_free_full (contents
->objects
, g_object_unref
);
3012 contents
->objects
= g_slist_copy_deep
3013 (me
->orig_contents_objects
,
3014 (GCopyFunc
)sheet_object_dup
, NULL
);
3017 for (l
= contents
->objects
; l
; l
= l
->next
) {
3018 SheetObject
*so
= l
->data
;
3019 if (sheet_object_get_sheet (so
)) {
3020 g_object_unref (so
);
3023 // Object got deleted by paste, so keep it for
3024 // undo. See bugzilla 732653
3028 g_slist_remove_all (contents
->objects
, NULL
);
3031 cellregion_unref (me
->contents
);
3032 me
->contents
= contents
;
3033 me
->has_been_through_cycle
= TRUE
;
3035 /* Select the newly pasted contents (this queues a redraw) */
3036 if (me
->only_objects
&& GNM_IS_WBC_GTK (wbc
)) {
3037 SheetControlGUI
*scg
=
3038 wbcg_get_nth_scg (WBC_GTK (wbc
),
3039 cmd
->sheet
->index_in_wb
);
3040 scg_object_unselect (scg
, NULL
);
3041 g_slist_foreach (me
->pasted_objects
,
3042 (GFunc
) cmd_paste_copy_select_obj
, scg
);
3044 select_range (me
->dst
.sheet
, &me
->dst
.range
, wbc
);
3050 cmd_paste_copy_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
3052 return cmd_paste_copy_impl (cmd
, wbc
, TRUE
);
3056 cmd_paste_copy_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
3058 return cmd_paste_copy_impl (cmd
, wbc
, FALSE
);
3062 cmd_paste_copy_finalize (GObject
*cmd
)
3064 CmdPasteCopy
*me
= CMD_PASTE_COPY (cmd
);
3067 cellregion_unref (me
->contents
);
3068 me
->contents
= NULL
;
3070 g_slist_free_full (me
->pasted_objects
, (GDestroyNotify
)g_object_unref
);
3071 g_slist_free_full (me
->orig_contents_objects
, (GDestroyNotify
)g_object_unref
);
3072 gnm_command_finalize (cmd
);
3076 * cmd_paste_copy will ref cr as needed.
3079 cmd_paste_copy (WorkbookControl
*wbc
,
3080 GnmPasteTarget
const *pt
, GnmCellRegion
*cr
)
3083 int n_r
= 1, n_c
= 1;
3085 GnmRange
const *merge_src
;
3087 g_return_val_if_fail (pt
!= NULL
, TRUE
);
3088 g_return_val_if_fail (IS_SHEET (pt
->sheet
), TRUE
);
3089 g_return_val_if_fail (cr
!= NULL
, TRUE
);
3091 cellregion_ref (cr
);
3093 me
= g_object_new (CMD_PASTE_COPY_TYPE
, NULL
);
3095 me
->cmd
.sheet
= pt
->sheet
;
3096 me
->cmd
.size
= 1; /* FIXME? */
3098 range_name
= undo_range_name (pt
->sheet
, &pt
->range
);
3099 me
->cmd
.cmd_descriptor
= g_strdup_printf (_("Pasting into %s"),
3101 g_free (range_name
);
3105 me
->has_been_through_cycle
= FALSE
;
3106 me
->only_objects
= (cr
->cols
< 1 || cr
->rows
< 1);
3107 me
->pasted_objects
= NULL
;
3108 me
->orig_contents_objects
=
3109 g_slist_copy_deep (cr
->objects
,
3110 (GCopyFunc
)sheet_object_dup
, NULL
);
3111 me
->single_merge_to_single_merge
= FALSE
;
3113 /* If the input is only objects ignore all this range stuff */
3114 if (!me
->only_objects
) {
3115 /* see if we need to do any tiling */
3116 GnmRange
*r
= &me
->dst
.range
;
3117 if (g_slist_length (cr
->merged
) == 1 &&
3118 (NULL
!= (merge_src
= cr
->merged
->data
)) &&
3119 range_height (merge_src
) == cr
->rows
&&
3120 range_width (merge_src
) == cr
->cols
) {
3121 /* We are copying from a single merge */
3122 GnmRange
const *merge
= gnm_sheet_merge_is_corner (pt
->sheet
, &r
->start
);
3123 if (merge
!= NULL
&& range_equal (r
, merge
)) {
3124 /* To a single merge */
3125 me
->single_merge_to_single_merge
= TRUE
;
3127 me
->dst
.paste_flags
|= PASTE_DONT_MERGE
;
3132 if (pt
->paste_flags
& PASTE_TRANSPOSE
) {
3133 n_c
= range_width (r
) / cr
->rows
;
3134 if (n_c
< 1) n_c
= 1;
3135 r
->end
.col
= r
->start
.col
+ n_c
* cr
->rows
- 1;
3137 n_r
= range_height (r
) / cr
->cols
;
3138 if (n_r
< 1) n_r
= 1;
3139 r
->end
.row
= r
->start
.row
+ n_r
* cr
->cols
- 1;
3141 /* Before looking for tiling if we are not transposing,
3142 * allow pasting a full col or row from a single cell */
3143 n_c
= range_width (r
);
3144 if (n_c
== 1 && cr
->cols
== gnm_sheet_get_max_cols (me
->cmd
.sheet
)) {
3146 r
->end
.col
= gnm_sheet_get_last_col (me
->cmd
.sheet
);
3149 if (n_c
< 1) n_c
= 1;
3150 r
->end
.col
= r
->start
.col
+ n_c
* cr
->cols
- 1;
3153 n_r
= range_height (r
);
3154 if (n_r
== 1 && cr
->rows
== gnm_sheet_get_max_rows (me
->cmd
.sheet
)) {
3156 r
->end
.row
= gnm_sheet_get_last_row (me
->cmd
.sheet
);
3159 if (n_r
< 1) n_r
= 1;
3160 r
->end
.row
= r
->start
.row
+ n_r
* cr
->rows
- 1;
3164 if (cr
->cols
!= 1 || cr
->rows
!= 1) {
3165 /* Note: when the source is a single cell, a single target merge is special */
3166 /* see clipboard.c (clipboard_paste_region) */
3167 GnmRange
const *merge
= gnm_sheet_merge_is_corner (pt
->sheet
, &r
->start
);
3168 if (merge
!= NULL
&& range_equal (r
, merge
)) {
3169 /* destination is a single merge */
3170 /* enlarge it such that the source fits */
3171 if (pt
->paste_flags
& PASTE_TRANSPOSE
) {
3172 if ((r
->end
.col
- r
->start
.col
+ 1) < cr
->rows
)
3173 r
->end
.col
= r
->start
.col
+ cr
->rows
- 1;
3174 if ((r
->end
.row
- r
->start
.row
+ 1) < cr
->cols
)
3175 r
->end
.row
= r
->start
.row
+ cr
->cols
- 1;
3177 if ((r
->end
.col
- r
->start
.col
+ 1) < cr
->cols
)
3178 r
->end
.col
= r
->start
.col
+ cr
->cols
- 1;
3179 if ((r
->end
.row
- r
->start
.row
+ 1) < cr
->rows
)
3180 r
->end
.row
= r
->start
.row
+ cr
->rows
- 1;
3186 if (n_c
* (gnm_float
)n_r
> 10000.) {
3187 char *number
= g_strdup_printf ("%0.0" GNM_FORMAT_f
,
3188 (gnm_float
)n_c
* (gnm_float
)n_r
);
3189 gboolean result
= go_gtk_query_yes_no (wbcg_toplevel (WBC_GTK (wbc
)), FALSE
,
3190 _("Do you really want to paste "
3191 "%s copies?"), number
);
3194 g_object_unref (me
);
3200 /* Use translate to do a quiet sanity check */
3201 if (range_translate (&me
->dst
.range
, pt
->sheet
, 0, 0)) {
3202 go_cmd_context_error_invalid (GO_CMD_CONTEXT (wbc
),
3203 me
->cmd
.cmd_descriptor
,
3204 _("is beyond sheet boundaries"));
3205 g_object_unref (me
);
3209 /* no need to test if all we have are objects or are copying from */
3210 /*a single merge to a single merge*/
3211 if ((!me
->only_objects
) && (!me
->single_merge_to_single_merge
)&&
3212 sheet_range_splits_region (pt
->sheet
, &me
->dst
.range
,
3213 NULL
, GO_CMD_CONTEXT (wbc
), me
->cmd
.cmd_descriptor
)) {
3214 g_object_unref (me
);
3218 warn_if_date_trouble (wbc
, cr
);
3220 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
3223 /******************************************************************/
3225 #define CMD_AUTOFILL_TYPE (cmd_autofill_get_type ())
3226 #define CMD_AUTOFILL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_AUTOFILL_TYPE, CmdAutofill))
3231 GnmCellRegion
*contents
;
3234 int base_col
, base_row
, w
, h
, end_col
, end_row
;
3235 gboolean default_increment
;
3236 gboolean inverse_autofill
;
3237 ColRowIndexList
*columns
;
3238 ColRowStateGroup
*old_widths
;
3242 cmd_autofill_repeat (GnmCommand
const *cmd
, WorkbookControl
*wbc
)
3244 CmdAutofill
const *orig
= (CmdAutofill
const *) cmd
;
3245 SheetView
*sv
= wb_control_cur_sheet_view (wbc
);
3246 GnmRange
const *r
= selection_first_range (sv
,
3247 GO_CMD_CONTEXT (wbc
), _("Autofill"));
3252 cmd_autofill (wbc
, sv_sheet (sv
), orig
->default_increment
,
3253 r
->start
.col
, r
->start
.row
, range_width (r
), range_height (r
),
3254 r
->start
.col
+ (orig
->end_col
- orig
->base_col
),
3255 r
->start
.row
+ (orig
->end_row
- orig
->base_row
),
3256 orig
->inverse_autofill
);
3258 MAKE_GNM_COMMAND (CmdAutofill
, cmd_autofill
, cmd_autofill_repeat
)
3261 cmd_autofill_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
3263 CmdAutofill
*me
= CMD_AUTOFILL (cmd
);
3266 g_return_val_if_fail (wbc
!= NULL
, TRUE
);
3267 g_return_val_if_fail (me
!= NULL
, TRUE
);
3268 g_return_val_if_fail (me
->contents
!= NULL
, TRUE
);
3270 res
= clipboard_paste_region (me
->contents
, &me
->dst
, GO_CMD_CONTEXT (wbc
));
3271 cellregion_unref (me
->contents
);
3272 me
->contents
= NULL
;
3274 if (me
->old_widths
) {
3275 colrow_restore_state_group (me
->cmd
.sheet
, TRUE
,
3278 colrow_state_group_destroy (me
->old_widths
);
3279 me
->old_widths
= NULL
;
3280 colrow_index_list_destroy (me
->columns
);
3287 select_range (me
->dst
.sheet
, &me
->src
, wbc
);
3293 cmd_autofill_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
3295 CmdAutofill
*me
= CMD_AUTOFILL (cmd
);
3298 g_return_val_if_fail (me
!= NULL
, TRUE
);
3299 g_return_val_if_fail (me
->contents
== NULL
, TRUE
);
3301 me
->contents
= clipboard_copy_range (me
->dst
.sheet
, &me
->dst
.range
);
3303 g_return_val_if_fail (me
->contents
!= NULL
, TRUE
);
3305 /* FIXME : when we split autofill to support hints and better validation
3306 * move this in there.
3308 /* MW: May 2006: we support hints now. What's this about? */
3309 sheet_clear_region (me
->dst
.sheet
,
3310 me
->dst
.range
.start
.col
, me
->dst
.range
.start
.row
,
3311 me
->dst
.range
.end
.col
, me
->dst
.range
.end
.row
,
3312 CLEAR_VALUES
| CLEAR_MERGES
| CLEAR_NOCHECKARRAY
| CLEAR_RECALC_DEPS
,
3313 GO_CMD_CONTEXT (wbc
));
3315 if (me
->cmd
.size
== 1)
3316 me
->cmd
.size
+= cellregion_cmd_size (me
->contents
);
3317 if (me
->inverse_autofill
)
3318 gnm_autofill_fill (me
->dst
.sheet
, me
->default_increment
,
3319 me
->end_col
, me
->end_row
, me
->w
, me
->h
,
3320 me
->base_col
, me
->base_row
);
3322 gnm_autofill_fill (me
->dst
.sheet
, me
->default_increment
,
3323 me
->base_col
, me
->base_row
, me
->w
, me
->h
,
3324 me
->end_col
, me
->end_row
);
3326 colrow_autofit (me
->cmd
.sheet
, &me
->dst
.range
, TRUE
, TRUE
,
3328 &me
->columns
, &me
->old_widths
);
3330 sheet_region_queue_recalc (me
->dst
.sheet
, &me
->dst
.range
);
3331 sheet_range_calc_spans (me
->dst
.sheet
, &me
->dst
.range
, GNM_SPANCALC_RENDER
);
3332 sheet_flag_status_update_range (me
->dst
.sheet
, &me
->dst
.range
);
3334 r
= range_union (&me
->dst
.range
, &me
->src
);
3335 select_range (me
->dst
.sheet
, &r
, wbc
);
3341 cmd_autofill_finalize (GObject
*cmd
)
3343 CmdAutofill
*me
= CMD_AUTOFILL (cmd
);
3346 cellregion_unref (me
->contents
);
3347 me
->contents
= NULL
;
3349 colrow_index_list_destroy (me
->columns
);
3350 colrow_state_group_destroy (me
->old_widths
);
3351 gnm_command_finalize (cmd
);
3355 cmd_autofill (WorkbookControl
*wbc
, Sheet
*sheet
,
3356 gboolean default_increment
,
3357 int base_col
, int base_row
,
3358 int w
, int h
, int end_col
, int end_row
,
3359 gboolean inverse_autofill
)
3362 GnmRange target
, src
;
3364 g_return_val_if_fail (IS_SHEET (sheet
), TRUE
);
3366 /* This would be meaningless */
3367 if (base_col
+w
-1 == end_col
&& base_row
+h
-1 == end_row
)
3370 if (inverse_autofill
) {
3371 if (end_col
!= base_col
+ w
- 1) {
3372 range_init (&target
, base_col
, base_row
,
3373 end_col
- w
, end_row
);
3374 range_init (&src
, end_col
- w
+ 1, base_row
,
3377 range_init (&target
, base_col
, base_row
,
3378 end_col
, end_row
- h
);
3379 range_init (&src
, base_col
, end_row
- h
+ 1,
3383 if (end_col
!= base_col
+ w
- 1) {
3384 range_init (&target
, base_col
+ w
, base_row
,
3386 range_init (&src
, base_col
, base_row
,
3387 base_col
+ w
- 1, end_row
);
3389 range_init (&target
, base_col
, base_row
+ h
,
3391 range_init (&src
, base_col
, base_row
,
3392 end_col
, base_row
+ h
- 1);
3396 /* We don't support clearing regions, when a user uses the autofill
3397 * cursor to 'shrink' a selection
3399 if (target
.start
.col
> target
.end
.col
|| target
.start
.row
> target
.end
.row
)
3402 /* Check arrays or merged regions in src or target regions */
3403 if (sheet_range_splits_region (sheet
, &target
, NULL
, GO_CMD_CONTEXT (wbc
), _("Autofill")) ||
3404 sheet_range_splits_region (sheet
, &src
, NULL
, GO_CMD_CONTEXT (wbc
), _("Autofill")))
3407 me
= g_object_new (CMD_AUTOFILL_TYPE
, NULL
);
3409 me
->contents
= NULL
;
3410 me
->dst
.sheet
= sheet
;
3411 me
->dst
.paste_flags
= PASTE_CONTENTS
| PASTE_FORMATS
;
3412 me
->dst
.range
= target
;
3415 me
->base_col
= base_col
;
3416 me
->base_row
= base_row
,
3419 me
->end_col
= end_col
;
3420 me
->end_row
= end_row
;
3421 me
->default_increment
= default_increment
;
3422 me
->inverse_autofill
= inverse_autofill
;
3424 me
->cmd
.sheet
= sheet
;
3425 me
->cmd
.size
= 1; /* Changed in initial redo. */
3426 me
->cmd
.cmd_descriptor
= g_strdup_printf (_("Autofilling %s"),
3427 range_as_string (&me
->dst
.range
));
3429 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
3432 /******************************************************************/
3434 #define CMD_COPYREL_TYPE (cmd_copyrel_get_type ())
3435 #define CMD_COPYREL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_COPYREL_TYPE, CmdCopyRel))
3441 GnmPasteTarget dst
, src
;
3447 cmd_copyrel_repeat (GnmCommand
const *cmd
, WorkbookControl
*wbc
)
3449 CmdCopyRel
const *orig
= (CmdCopyRel
const *) cmd
;
3450 cmd_copyrel (wbc
, orig
->dx
, orig
->dy
, orig
->name
);
3452 MAKE_GNM_COMMAND (CmdCopyRel
, cmd_copyrel
, cmd_copyrel_repeat
)
3455 cmd_copyrel_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
3457 CmdCopyRel
*me
= CMD_COPYREL (cmd
);
3459 g_return_val_if_fail (wbc
!= NULL
, TRUE
);
3460 g_return_val_if_fail (me
!= NULL
, TRUE
);
3461 g_return_val_if_fail (me
->undo
!= NULL
, TRUE
);
3463 go_undo_undo (me
->undo
);
3465 /* Select the newly pasted contents (this queues a redraw) */
3466 select_range (me
->dst
.sheet
, &me
->dst
.range
, wbc
);
3472 cmd_copyrel_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
3474 CmdCopyRel
*me
= CMD_COPYREL (cmd
);
3475 GnmCellRegion
*contents
;
3478 g_return_val_if_fail (me
!= NULL
, TRUE
);
3480 sheet_clear_region (me
->dst
.sheet
,
3481 me
->dst
.range
.start
.col
, me
->dst
.range
.start
.row
,
3482 me
->dst
.range
.end
.col
, me
->dst
.range
.end
.row
,
3483 CLEAR_VALUES
| CLEAR_MERGES
| CLEAR_NOCHECKARRAY
| CLEAR_RECALC_DEPS
,
3484 GO_CMD_CONTEXT (wbc
));
3486 contents
= clipboard_copy_range (me
->src
.sheet
, &me
->src
.range
);
3487 res
= clipboard_paste_region (contents
, &me
->dst
, GO_CMD_CONTEXT (wbc
));
3488 cellregion_unref (contents
);
3492 sheet_region_queue_recalc (me
->dst
.sheet
, &me
->dst
.range
);
3493 sheet_range_calc_spans (me
->dst
.sheet
, &me
->dst
.range
, GNM_SPANCALC_RENDER
);
3494 sheet_flag_status_update_range (me
->dst
.sheet
, &me
->dst
.range
);
3496 /* Select the newly pasted contents (this queues a redraw) */
3497 select_range (me
->dst
.sheet
, &me
->dst
.range
, wbc
);
3503 cmd_copyrel_finalize (GObject
*cmd
)
3505 CmdCopyRel
*me
= CMD_COPYREL (cmd
);
3508 g_object_unref (me
->undo
);
3510 gnm_command_finalize (cmd
);
3514 cmd_copyrel (WorkbookControl
*wbc
,
3519 GnmRange target
, src
;
3520 SheetView
*sv
= wb_control_cur_sheet_view (wbc
);
3521 Sheet
*sheet
= sv
->sheet
;
3522 GnmRange
const *selr
=
3523 selection_first_range (sv
, GO_CMD_CONTEXT (wbc
), name
);
3525 g_return_val_if_fail (dx
== 0 || dy
== 0, TRUE
);
3531 range_normalize (&target
);
3532 src
.start
= src
.end
= target
.start
;
3535 src
.end
.col
= target
.end
.col
;
3536 if (target
.start
.row
!= target
.end
.row
)
3539 src
.start
.row
= src
.end
.row
= (target
.start
.row
+ dy
);
3543 src
.end
.row
= target
.end
.row
;
3544 if (target
.start
.col
!= target
.end
.col
)
3547 src
.start
.col
= src
.end
.col
= (target
.start
.col
+ dx
);
3550 if (src
.start
.col
< 0 || src
.start
.col
>= gnm_sheet_get_max_cols (sheet
) ||
3551 src
.start
.row
< 0 || src
.start
.row
>= gnm_sheet_get_max_rows (sheet
))
3554 /* Check arrays or merged regions in src or target regions */
3555 if (sheet_range_splits_region (sheet
, &target
, NULL
, GO_CMD_CONTEXT (wbc
), name
) ||
3556 sheet_range_splits_region (sheet
, &src
, NULL
, GO_CMD_CONTEXT (wbc
), name
))
3559 me
= g_object_new (CMD_COPYREL_TYPE
, NULL
);
3561 me
->dst
.sheet
= sheet
;
3562 me
->dst
.paste_flags
= PASTE_CONTENTS
| PASTE_FORMATS
;
3563 me
->dst
.range
= target
;
3564 me
->src
.sheet
= sheet
;
3565 me
->src
.paste_flags
= PASTE_CONTENTS
| PASTE_FORMATS
;
3566 me
->src
.range
= src
;
3570 me
->undo
= clipboard_copy_range_undo (me
->dst
.sheet
, &me
->dst
.range
);
3572 me
->cmd
.sheet
= sheet
;
3574 me
->cmd
.cmd_descriptor
= g_strdup (name
);
3576 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
3579 /******************************************************************/
3582 #define CMD_AUTOFORMAT_TYPE (cmd_autoformat_get_type ())
3583 #define CMD_AUTOFORMAT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_AUTOFORMAT_TYPE, CmdAutoFormat))
3587 GnmStyleList
*styles
;
3588 } CmdAutoFormatOldStyle
;
3593 GSList
*selection
; /* Selections on the sheet */
3594 GSList
*old_styles
; /* Older styles, one style_list per selection range*/
3596 GnmFT
*ft
; /* Template that has been applied */
3600 cmd_autoformat_repeat (GnmCommand
const *cmd
, WorkbookControl
*wbc
)
3602 CmdAutoFormat
const *orig
= (CmdAutoFormat
const *) cmd
;
3603 cmd_selection_autoformat (wbc
, gnm_ft_clone (orig
->ft
));
3605 MAKE_GNM_COMMAND (CmdAutoFormat
, cmd_autoformat
, cmd_autoformat_repeat
)
3608 cmd_autoformat_undo (GnmCommand
*cmd
,
3609 G_GNUC_UNUSED WorkbookControl
*wbc
)
3611 CmdAutoFormat
*me
= CMD_AUTOFORMAT (cmd
);
3613 g_return_val_if_fail (me
!= NULL
, TRUE
);
3615 if (me
->old_styles
) {
3616 GSList
*l1
= me
->old_styles
;
3617 GSList
*l2
= me
->selection
;
3619 for (; l1
; l1
= l1
->next
, l2
= l2
->next
) {
3621 CmdAutoFormatOldStyle
*os
= l1
->data
;
3622 GnmSpanCalcFlags flags
= sheet_style_set_list (me
->cmd
.sheet
,
3623 &os
->pos
, os
->styles
, NULL
, NULL
);
3625 g_return_val_if_fail (l2
&& l2
->data
, TRUE
);
3628 sheet_range_calc_spans (me
->cmd
.sheet
, r
, flags
);
3629 if (flags
!= GNM_SPANCALC_SIMPLE
)
3630 rows_height_update (me
->cmd
.sheet
, r
, TRUE
);
3638 cmd_autoformat_redo (GnmCommand
*cmd
,
3639 G_GNUC_UNUSED WorkbookControl
*wbc
)
3641 CmdAutoFormat
*me
= CMD_AUTOFORMAT (cmd
);
3643 g_return_val_if_fail (me
!= NULL
, TRUE
);
3645 gnm_ft_apply_to_sheet_regions (me
->ft
,
3646 me
->cmd
.sheet
, me
->selection
);
3652 cmd_autoformat_finalize (GObject
*cmd
)
3654 CmdAutoFormat
*me
= CMD_AUTOFORMAT (cmd
);
3656 if (me
->old_styles
!= NULL
) {
3659 for (l
= me
->old_styles
; l
!= NULL
; l
= g_slist_remove (l
, l
->data
)) {
3660 CmdAutoFormatOldStyle
*os
= l
->data
;
3663 style_list_free (os
->styles
);
3668 me
->old_styles
= NULL
;
3671 range_fragment_free (me
->selection
);
3672 me
->selection
= NULL
;
3674 gnm_ft_free (me
->ft
);
3676 gnm_command_finalize (cmd
);
3680 * cmd_selection_autoformat:
3681 * @wbc: the context.
3682 * @ft: The format template that was applied
3684 * Return value: TRUE if there was a problem
3687 cmd_selection_autoformat (WorkbookControl
*wbc
, GnmFT
*ft
)
3692 SheetView
*sv
= wb_control_cur_sheet_view (wbc
);
3694 me
= g_object_new (CMD_AUTOFORMAT_TYPE
, NULL
);
3696 me
->selection
= selection_get_ranges (sv
, FALSE
); /* Regions may overlap */
3698 me
->cmd
.sheet
= sv_sheet (sv
);
3699 me
->cmd
.size
= 1; /* FIXME? */
3701 if (!gnm_ft_check_valid (ft
, me
->selection
, GO_CMD_CONTEXT (wbc
))) {
3702 g_object_unref (me
);
3706 me
->old_styles
= NULL
;
3707 for (l
= me
->selection
; l
; l
= l
->next
) {
3708 CmdFormatOldStyle
*os
;
3709 GnmRange range
= *((GnmRange
const *) l
->data
);
3711 /* Store the containing range to handle borders */
3712 if (range
.start
.col
> 0) range
.start
.col
--;
3713 if (range
.start
.row
> 0) range
.start
.row
--;
3714 if (range
.end
.col
< gnm_sheet_get_last_col (sv
->sheet
)) range
.end
.col
++;
3715 if (range
.end
.row
< gnm_sheet_get_last_row (sv
->sheet
)) range
.end
.row
++;
3717 os
= g_new (CmdFormatOldStyle
, 1);
3719 os
->styles
= sheet_style_get_range (me
->cmd
.sheet
, &range
);
3720 os
->pos
= range
.start
;
3722 me
->old_styles
= g_slist_append (me
->old_styles
, os
);
3725 names
= undo_range_list_name (me
->cmd
.sheet
, me
->selection
);
3726 me
->cmd
.cmd_descriptor
= g_strdup_printf (_("Autoformatting %s"),
3730 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
3733 /******************************************************************/
3735 #define CMD_UNMERGE_CELLS_TYPE (cmd_unmerge_cells_get_type ())
3736 #define CMD_UNMERGE_CELLS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_UNMERGE_CELLS_TYPE, CmdUnmergeCells))
3742 GArray
*unmerged_regions
;
3747 cmd_unmerge_cells_repeat (G_GNUC_UNUSED GnmCommand
const *cmd
, WorkbookControl
*wbc
)
3749 SheetView
*sv
= wb_control_cur_sheet_view (wbc
);
3750 GSList
*range_list
= selection_get_ranges (sv
, FALSE
);
3751 cmd_unmerge_cells (wbc
, sv_sheet (sv
), range_list
);
3752 range_fragment_free (range_list
);
3754 MAKE_GNM_COMMAND (CmdUnmergeCells
, cmd_unmerge_cells
, cmd_unmerge_cells_repeat
)
3757 cmd_unmerge_cells_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
3759 CmdUnmergeCells
*me
= CMD_UNMERGE_CELLS (cmd
);
3762 g_return_val_if_fail (me
!= NULL
, TRUE
);
3763 g_return_val_if_fail (me
->unmerged_regions
!= NULL
, TRUE
);
3765 for (i
= 0 ; i
< me
->unmerged_regions
->len
; ++i
) {
3766 GnmRange
const *tmp
= &(g_array_index (me
->unmerged_regions
, GnmRange
, i
));
3767 sheet_redraw_range (me
->cmd
.sheet
, tmp
);
3768 gnm_sheet_merge_add (me
->cmd
.sheet
, tmp
, TRUE
, GO_CMD_CONTEXT (wbc
));
3769 sheet_range_calc_spans (me
->cmd
.sheet
, tmp
, GNM_SPANCALC_RE_RENDER
);
3772 g_array_free (me
->unmerged_regions
, TRUE
);
3773 me
->unmerged_regions
= NULL
;
3779 cmd_unmerge_cells_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
3781 CmdUnmergeCells
*me
= CMD_UNMERGE_CELLS (cmd
);
3784 g_return_val_if_fail (me
!= NULL
, TRUE
);
3785 g_return_val_if_fail (me
->unmerged_regions
== NULL
, TRUE
);
3787 me
->unmerged_regions
= g_array_new (FALSE
, FALSE
, sizeof (GnmRange
));
3788 for (i
= 0 ; i
< me
->ranges
->len
; ++i
) {
3789 GSList
*ptr
, *merged
= gnm_sheet_merge_get_overlap (me
->cmd
.sheet
,
3790 &(g_array_index (me
->ranges
, GnmRange
, i
)));
3791 for (ptr
= merged
; ptr
!= NULL
; ptr
= ptr
->next
) {
3792 GnmRange
const *pr
= ptr
->data
;
3793 GnmRange
const tmp
= *pr
;
3794 g_array_append_val (me
->unmerged_regions
, tmp
);
3795 gnm_sheet_merge_remove (me
->cmd
.sheet
, &tmp
);
3796 sheet_range_calc_spans (me
->cmd
.sheet
, &tmp
,
3797 GNM_SPANCALC_RE_RENDER
);
3799 g_slist_free (merged
);
3806 cmd_unmerge_cells_finalize (GObject
*cmd
)
3808 CmdUnmergeCells
*me
= CMD_UNMERGE_CELLS (cmd
);
3810 if (me
->unmerged_regions
!= NULL
) {
3811 g_array_free (me
->unmerged_regions
, TRUE
);
3812 me
->unmerged_regions
= NULL
;
3814 if (me
->ranges
!= NULL
) {
3815 g_array_free (me
->ranges
, TRUE
);
3819 gnm_command_finalize (cmd
);
3823 * cmd_unmerge_cells:
3824 * @wbc: the context.
3826 * @selection: (element-type GnmRange): selection.
3828 * Return value: TRUE if there was a problem
3831 cmd_unmerge_cells (WorkbookControl
*wbc
, Sheet
*sheet
, GSList
const *selection
)
3833 CmdUnmergeCells
*me
;
3836 g_return_val_if_fail (IS_SHEET (sheet
), TRUE
);
3838 me
= g_object_new (CMD_UNMERGE_CELLS_TYPE
, NULL
);
3840 me
->cmd
.sheet
= sheet
;
3843 names
= undo_range_list_name (sheet
, selection
);
3844 me
->cmd
.cmd_descriptor
= g_strdup_printf (_("Unmerging %s"), names
);
3847 me
->unmerged_regions
= NULL
;
3848 me
->ranges
= g_array_new (FALSE
, FALSE
, sizeof (GnmRange
));
3849 for ( ; selection
!= NULL
; selection
= selection
->next
) {
3850 GSList
*merged
= gnm_sheet_merge_get_overlap (sheet
, selection
->data
);
3851 if (merged
!= NULL
) {
3852 g_array_append_val (me
->ranges
, *(GnmRange
*)selection
->data
);
3853 g_slist_free (merged
);
3857 if (me
->ranges
->len
<= 0) {
3858 g_object_unref (me
);
3862 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
3865 /******************************************************************/
3867 #define CMD_MERGE_CELLS_TYPE (cmd_merge_cells_get_type ())
3868 #define CMD_MERGE_CELLS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_MERGE_CELLS_TYPE, CmdMergeCells))
3873 GSList
*old_contents
;
3878 cmd_merge_cells_repeat (GnmCommand
const *cmd
, WorkbookControl
*wbc
);
3880 MAKE_GNM_COMMAND (CmdMergeCells
, cmd_merge_cells
, cmd_merge_cells_repeat
)
3883 cmd_merge_cells_repeat (GnmCommand
const *cmd
, WorkbookControl
*wbc
)
3885 SheetView
*sv
= wb_control_cur_sheet_view (wbc
);
3886 GSList
*range_list
= selection_get_ranges (sv
, FALSE
);
3887 cmd_merge_cells (wbc
, sv_sheet (sv
), range_list
,
3888 CMD_MERGE_CELLS (cmd
)->center
);
3889 range_fragment_free (range_list
);
3893 cmd_merge_cells_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
3895 CmdMergeCells
*me
= CMD_MERGE_CELLS (cmd
);
3898 g_return_val_if_fail (me
!= NULL
, TRUE
);
3900 for (i
= 0 ; i
< me
->ranges
->len
; ++i
) {
3901 GnmRange
const *r
= &(g_array_index (me
->ranges
, GnmRange
, i
));
3902 gnm_sheet_merge_remove (me
->cmd
.sheet
, r
);
3905 /* Avoid pasting comments that are at 0,0. Redo copies the target
3906 * region (including all comments) . If there was a comment in the top
3907 * left we would end up duplicating it. */
3908 flags
= PASTE_CONTENTS
| PASTE_FORMATS
| PASTE_COMMENTS
|
3909 PASTE_IGNORE_COMMENTS_AT_ORIGIN
;
3911 flags
|= PASTE_FORMATS
;
3912 for (i
= 0 ; i
< me
->ranges
->len
; ++i
) {
3913 GnmRange
const *r
= &(g_array_index (me
->ranges
, GnmRange
, i
));
3917 g_return_val_if_fail (me
->old_contents
!= NULL
, TRUE
);
3919 c
= me
->old_contents
->data
;
3920 clipboard_paste_region (c
,
3921 paste_target_init (&pt
, me
->cmd
.sheet
, r
, flags
),
3922 GO_CMD_CONTEXT (wbc
));
3923 cellregion_unref (c
);
3924 me
->old_contents
= g_slist_remove (me
->old_contents
, c
);
3926 g_return_val_if_fail (me
->old_contents
== NULL
, TRUE
);
3932 cmd_merge_cells_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
3934 CmdMergeCells
*me
= CMD_MERGE_CELLS (cmd
);
3935 GnmStyle
*align_center
= NULL
;
3939 g_return_val_if_fail (me
!= NULL
, TRUE
);
3942 align_center
= gnm_style_new ();
3943 gnm_style_set_align_h (align_center
, GNM_HALIGN_CENTER
);
3945 sheet
= me
->cmd
.sheet
;
3946 for (i
= 0 ; i
< me
->ranges
->len
; ++i
) {
3947 GnmRange
const *r
= &(g_array_index (me
->ranges
, GnmRange
, i
));
3948 GSList
*ptr
, *merged
= gnm_sheet_merge_get_overlap (sheet
, r
);
3950 /* save contents before removing contained merged regions */
3951 me
->old_contents
= g_slist_prepend (me
->old_contents
,
3952 clipboard_copy_range (sheet
, r
));
3953 for (ptr
= merged
; ptr
!= NULL
; ptr
= ptr
->next
)
3954 gnm_sheet_merge_remove (sheet
, ptr
->data
);
3955 g_slist_free (merged
);
3957 gnm_sheet_merge_add (sheet
, r
, TRUE
, GO_CMD_CONTEXT (wbc
));
3959 sheet_apply_style (me
->cmd
.sheet
, r
, align_center
);
3963 gnm_style_unref (align_center
);
3964 me
->old_contents
= g_slist_reverse (me
->old_contents
);
3969 cmd_merge_cells_finalize (GObject
*cmd
)
3971 CmdMergeCells
*me
= CMD_MERGE_CELLS (cmd
);
3973 if (me
->old_contents
!= NULL
) {
3975 for (l
= me
->old_contents
; l
!= NULL
; l
= g_slist_remove (l
, l
->data
))
3976 cellregion_unref (l
->data
);
3977 me
->old_contents
= NULL
;
3980 if (me
->ranges
!= NULL
) {
3981 g_array_free (me
->ranges
, TRUE
);
3985 gnm_command_finalize (cmd
);
3990 * @wbc: the context.
3992 * @selection: (element-type GnmRange): selection.
3995 * Return value: %TRUE if there was a problem
3998 cmd_merge_cells (WorkbookControl
*wbc
, Sheet
*sheet
, GSList
const *selection
,
4004 g_return_val_if_fail (IS_SHEET (sheet
), TRUE
);
4006 me
= g_object_new (CMD_MERGE_CELLS_TYPE
, NULL
);
4008 me
->cmd
.sheet
= sheet
;
4011 names
= undo_range_list_name (sheet
, selection
);
4012 me
->cmd
.cmd_descriptor
=
4013 g_strdup_printf ((center
? _("Merge and Center %s") :_("Merging %s")), names
);
4016 me
->center
= center
;
4017 me
->ranges
= g_array_new (FALSE
, FALSE
, sizeof (GnmRange
));
4018 for ( ; selection
!= NULL
; selection
= selection
->next
) {
4019 GnmRange
const *exist
;
4020 GnmRange
const *r
= selection
->data
;
4021 if (range_is_singleton (selection
->data
))
4023 if (NULL
!= (exist
= gnm_sheet_merge_is_corner (sheet
, &r
->start
)) &&
4024 range_equal (r
, exist
))
4026 g_array_append_val (me
->ranges
, *(GnmRange
*)selection
->data
);
4029 if (me
->ranges
->len
<= 0) {
4030 g_object_unref (me
);
4034 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
4037 /******************************************************************/
4039 #define CMD_SEARCH_REPLACE_TYPE (cmd_search_replace_get_type())
4040 #define CMD_SEARCH_REPLACE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_SEARCH_REPLACE_TYPE, CmdSearchReplace))
4044 GnmSearchReplace
*sr
;
4047 * Undo/redo use this list of SearchReplaceItems to do their
4048 * work. Note, that it is possible for a cell to occur
4049 * multiple times in the list.
4054 MAKE_GNM_COMMAND (CmdSearchReplace
, cmd_search_replace
, NULL
)
4056 typedef enum { SRI_text
, SRI_comment
} SearchReplaceItemType
;
4060 SearchReplaceItemType old_type
, new_type
;
4065 } SearchReplaceItem
;
4069 cmd_search_replace_update_after_action (CmdSearchReplace
*me
,
4070 WorkbookControl
*wbc
)
4073 Sheet
*last_sheet
= NULL
;
4075 for (tmp
= me
->cells
; tmp
; tmp
= tmp
->next
) {
4076 SearchReplaceItem
*sri
= tmp
->data
;
4077 if (sri
->pos
.sheet
!= last_sheet
) {
4078 last_sheet
= sri
->pos
.sheet
;
4079 update_after_action (last_sheet
, wbc
);
4086 cmd_search_replace_undo (GnmCommand
*cmd
,
4087 WorkbookControl
*wbc
)
4089 CmdSearchReplace
*me
= CMD_SEARCH_REPLACE (cmd
);
4092 /* Undo does replacements backwards. */
4093 for (tmp
= g_list_last (me
->cells
); tmp
; tmp
= tmp
->prev
) {
4094 SearchReplaceItem
*sri
= tmp
->data
;
4095 switch (sri
->old_type
) {
4098 GnmCell
*cell
= sheet_cell_get (sri
->pos
.sheet
,
4101 sheet_cell_set_text (cell
, sri
->old
.text
, NULL
);
4106 GnmComment
*comment
=
4107 sheet_get_comment (sri
->pos
.sheet
,
4110 cell_comment_text_set (comment
, sri
->old
.comment
);
4112 g_warning ("Undo/redo broken.");
4118 cmd_search_replace_update_after_action (me
, wbc
);
4124 cmd_search_replace_redo (GnmCommand
*cmd
,
4125 WorkbookControl
*wbc
)
4127 CmdSearchReplace
*me
= CMD_SEARCH_REPLACE (cmd
);
4130 /* Redo does replacements forward. */
4131 for (tmp
= me
->cells
; tmp
; tmp
= tmp
->next
) {
4132 SearchReplaceItem
*sri
= tmp
->data
;
4133 switch (sri
->new_type
) {
4136 GnmCell
*cell
= sheet_cell_get (sri
->pos
.sheet
,
4139 sheet_cell_set_text (cell
, sri
->new.text
, NULL
);
4144 GnmComment
*comment
=
4145 sheet_get_comment (sri
->pos
.sheet
,
4148 cell_comment_text_set (comment
, sri
->new.comment
);
4150 g_warning ("Undo/redo broken.");
4156 cmd_search_replace_update_after_action (me
, wbc
);
4162 cmd_search_replace_do_cell (CmdSearchReplace
*me
, GnmEvalPos
*ep
,
4165 GnmSearchReplace
*sr
= me
->sr
;
4167 GnmSearchReplaceCellResult cell_res
;
4168 GnmSearchReplaceCommentResult comment_res
;
4170 if (gnm_search_replace_cell (sr
, ep
, TRUE
, &cell_res
)) {
4171 GnmExprTop
const *texpr
;
4176 parse_pos_init_evalpos (&pp
, ep
);
4177 parse_text_value_or_expr (&pp
, cell_res
.new_text
, &val
, &texpr
);
4180 * FIXME: this is a hack, but parse_text_value_or_expr
4181 * does not have a better way of signaling an error.
4184 gnm_expr_char_start_p (cell_res
.new_text
) &&
4185 !go_format_is_text (gnm_cell_get_format (cell_res
.cell
)));
4186 value_release (val
);
4187 if (texpr
) gnm_expr_top_unref (texpr
);
4191 gnm_search_replace_query_fail (sr
, &cell_res
);
4192 g_free (cell_res
.old_text
);
4193 g_free (cell_res
.new_text
);
4196 switch (sr
->error_behaviour
) {
4197 case GNM_SRE_ERROR
: {
4198 GnmExprTop
const *ee
=
4200 (gnm_expr_new_funcall1
4201 (gnm_func_lookup ("ERROR", NULL
),
4202 gnm_expr_new_constant
4203 (value_new_string_nocopy (cell_res
.new_text
))));
4204 GnmConventionsOut out
;
4206 out
.accum
= g_string_new ("=");
4208 out
.convs
= pp
.sheet
->convs
;
4209 gnm_expr_top_as_gstring (ee
, &out
);
4210 gnm_expr_top_unref (ee
);
4211 cell_res
.new_text
= g_string_free (out
.accum
, FALSE
);
4215 case GNM_SRE_STRING
: {
4216 GString
*s
= g_string_new ("'");
4217 g_string_append (s
, cell_res
.new_text
);
4218 g_free (cell_res
.new_text
);
4219 cell_res
.new_text
= g_string_free (s
, FALSE
);
4224 g_assert_not_reached ();
4232 if (!err
&& !test_run
) {
4233 int res
= gnm_search_replace_query_cell
4235 gboolean doit
= (res
== GTK_RESPONSE_YES
);
4237 if (res
== GTK_RESPONSE_CANCEL
) {
4238 g_free (cell_res
.old_text
);
4239 g_free (cell_res
.new_text
);
4244 SearchReplaceItem
*sri
= g_new (SearchReplaceItem
, 1);
4246 sheet_cell_set_text (cell_res
.cell
, cell_res
.new_text
, NULL
);
4249 sri
->old_type
= sri
->new_type
= SRI_text
;
4250 sri
->old
.text
= cell_res
.old_text
;
4251 sri
->new.text
= cell_res
.new_text
;
4252 me
->cells
= g_list_prepend (me
->cells
, sri
);
4254 cell_res
.old_text
= cell_res
.new_text
= NULL
;
4258 g_free (cell_res
.new_text
);
4259 g_free (cell_res
.old_text
);
4263 gnm_search_replace_comment (sr
, ep
, TRUE
, &comment_res
)) {
4264 int res
= gnm_search_replace_query_comment
4265 (sr
, ep
, &comment_res
);
4266 gboolean doit
= (res
== GTK_RESPONSE_YES
);
4269 SearchReplaceItem
*sri
= g_new (SearchReplaceItem
, 1);
4271 sri
->old_type
= sri
->new_type
= SRI_comment
;
4272 sri
->old
.comment
= g_strdup (comment_res
.old_text
);
4273 sri
->new.comment
= comment_res
.new_text
;
4274 me
->cells
= g_list_prepend (me
->cells
, sri
);
4276 cell_comment_text_set (comment_res
.comment
, comment_res
.new_text
);
4278 g_free (comment_res
.new_text
);
4279 if (res
== GTK_RESPONSE_CANCEL
)
4289 cmd_search_replace_do (CmdSearchReplace
*me
, gboolean test_run
,
4290 WorkbookControl
*wbc
)
4292 GnmSearchReplace
*sr
= me
->sr
;
4294 gboolean result
= FALSE
;
4298 switch (sr
->error_behaviour
) {
4302 case GNM_SRE_STRING
:
4303 /* An error is not a problem. */
4311 cells
= gnm_search_collect_cells (sr
);
4313 for (i
= 0; i
< cells
->len
; i
++) {
4314 GnmEvalPos
*ep
= g_ptr_array_index (cells
, i
);
4316 if (cmd_search_replace_do_cell (me
, ep
, test_run
)) {
4322 gnm_search_collect_cells_free (cells
);
4325 /* Cells were added in the wrong order. Correct. */
4326 me
->cells
= g_list_reverse (me
->cells
);
4328 cmd_search_replace_update_after_action (me
, wbc
);
4336 cmd_search_replace_finalize (GObject
*cmd
)
4338 CmdSearchReplace
*me
= CMD_SEARCH_REPLACE (cmd
);
4341 for (tmp
= me
->cells
; tmp
; tmp
= tmp
->next
) {
4342 SearchReplaceItem
*sri
= tmp
->data
;
4343 switch (sri
->old_type
) {
4345 g_free (sri
->old
.text
);
4348 g_free (sri
->old
.comment
);
4351 switch (sri
->new_type
) {
4353 g_free (sri
->new.text
);
4356 g_free (sri
->new.comment
);
4361 g_list_free (me
->cells
);
4362 g_object_unref (me
->sr
);
4364 gnm_command_finalize (cmd
);
4368 cmd_search_replace (WorkbookControl
*wbc
, GnmSearchReplace
*sr
)
4370 CmdSearchReplace
*me
;
4372 g_return_val_if_fail (sr
!= NULL
, TRUE
);
4374 me
= g_object_new (CMD_SEARCH_REPLACE_TYPE
, NULL
);
4377 me
->sr
= g_object_ref (sr
);
4379 me
->cmd
.sheet
= NULL
;
4380 me
->cmd
.size
= 1; /* Corrected below. */
4381 me
->cmd
.cmd_descriptor
= g_strdup (_("Search and Replace"));
4383 if (cmd_search_replace_do (me
, TRUE
, wbc
)) {
4384 /* There was an error and nothing was done. */
4385 g_object_unref (me
);
4389 cmd_search_replace_do (me
, FALSE
, wbc
);
4390 me
->cmd
.size
+= g_list_length (me
->cells
);
4392 command_register_undo (wbc
, G_OBJECT (me
));
4396 /******************************************************************/
4398 #define CMD_COLROW_STD_SIZE_TYPE (cmd_colrow_std_size_get_type ())
4399 #define CMD_COLROW_STD_SIZE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_COLROW_STD_SIZE_TYPE, CmdColRowStdSize))
4410 MAKE_GNM_COMMAND (CmdColRowStdSize
, cmd_colrow_std_size
, NULL
)
4413 cmd_colrow_std_size_undo (GnmCommand
*cmd
,
4414 G_GNUC_UNUSED WorkbookControl
*wbc
)
4416 CmdColRowStdSize
*me
= CMD_COLROW_STD_SIZE (cmd
);
4418 g_return_val_if_fail (me
!= NULL
, TRUE
);
4419 g_return_val_if_fail (me
->old_default
!= 0, TRUE
);
4422 sheet_col_set_default_size_pts (me
->sheet
, me
->old_default
);
4424 sheet_row_set_default_size_pts (me
->sheet
, me
->old_default
);
4426 me
->old_default
= 0;
4432 cmd_colrow_std_size_redo (GnmCommand
*cmd
,
4433 G_GNUC_UNUSED WorkbookControl
*wbc
)
4435 CmdColRowStdSize
*me
= CMD_COLROW_STD_SIZE (cmd
);
4437 g_return_val_if_fail (me
!= NULL
, TRUE
);
4438 g_return_val_if_fail (me
->old_default
== 0, TRUE
);
4441 me
->old_default
= sheet_col_get_default_size_pts (me
->sheet
);
4442 sheet_col_set_default_size_pts (me
->sheet
, me
->new_default
);
4444 me
->old_default
= sheet_row_get_default_size_pts (me
->sheet
);
4445 sheet_row_set_default_size_pts (me
->sheet
, me
->new_default
);
4451 cmd_colrow_std_size_finalize (GObject
*cmd
)
4453 gnm_command_finalize (cmd
);
4457 cmd_colrow_std_size (WorkbookControl
*wbc
, Sheet
*sheet
,
4458 gboolean is_cols
, double new_default
)
4460 CmdColRowStdSize
*me
;
4462 g_return_val_if_fail (IS_SHEET (sheet
), TRUE
);
4464 me
= g_object_new (CMD_COLROW_STD_SIZE_TYPE
, NULL
);
4467 me
->is_cols
= is_cols
;
4468 me
->new_default
= new_default
;
4469 me
->old_default
= 0;
4471 me
->cmd
.sheet
= sheet
;
4472 me
->cmd
.size
= 1; /* Changed in initial redo. */
4473 me
->cmd
.cmd_descriptor
= is_cols
4474 ? g_strdup_printf (_("Setting default width of columns to %.2fpts"), new_default
)
4475 : g_strdup_printf (_("Setting default height of rows to %.2fpts"), new_default
);
4477 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
4480 /******************************************************************/
4482 #define CMD_ZOOM_TYPE (cmd_zoom_get_type ())
4483 #define CMD_ZOOM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_ZOOM_TYPE, CmdZoom))
4490 double *old_factors
;
4493 MAKE_GNM_COMMAND (CmdZoom
, cmd_zoom
, NULL
)
4496 cmd_zoom_undo (GnmCommand
*cmd
,
4497 G_GNUC_UNUSED WorkbookControl
*wbc
)
4499 CmdZoom
*me
= CMD_ZOOM (cmd
);
4503 g_return_val_if_fail (me
!= NULL
, TRUE
);
4504 g_return_val_if_fail (me
->sheets
!= NULL
, TRUE
);
4505 g_return_val_if_fail (me
->old_factors
!= NULL
, TRUE
);
4507 for (i
= 0, l
= me
->sheets
; l
!= NULL
; l
= l
->next
, i
++) {
4508 Sheet
*sheet
= l
->data
;
4509 g_object_set (sheet
, "zoom-factor", me
->old_factors
[i
], NULL
);
4516 cmd_zoom_redo (GnmCommand
*cmd
,
4517 G_GNUC_UNUSED WorkbookControl
*wbc
)
4519 CmdZoom
*me
= CMD_ZOOM (cmd
);
4522 g_return_val_if_fail (me
!= NULL
, TRUE
);
4523 g_return_val_if_fail (me
->sheets
!= NULL
, TRUE
);
4525 for (l
= me
->sheets
; l
!= NULL
; l
= l
->next
) {
4526 Sheet
*sheet
= l
->data
;
4527 g_object_set (sheet
, "zoom-factor", me
->new_factor
, NULL
);
4534 cmd_zoom_finalize (GObject
*cmd
)
4536 CmdZoom
*me
= CMD_ZOOM (cmd
);
4538 g_slist_free (me
->sheets
);
4539 g_free (me
->old_factors
);
4541 gnm_command_finalize (cmd
);
4546 * @wbc: #WorkbookControl
4547 * @sheets: (element-type Sheet) (transfer container):
4552 cmd_zoom (WorkbookControl
*wbc
, GSList
*sheets
, double factor
)
4559 g_return_val_if_fail (wbc
!= NULL
, TRUE
);
4560 g_return_val_if_fail (sheets
!= NULL
, TRUE
);
4562 me
= g_object_new (CMD_ZOOM_TYPE
, NULL
);
4564 me
->sheets
= sheets
;
4565 me
->old_factors
= g_new0 (double, g_slist_length (sheets
));
4566 me
->new_factor
= factor
;
4568 /* Make a list of all sheets to zoom and save zoom factor for each */
4569 namelist
= g_string_new (NULL
);
4570 for (i
= 0, l
= me
->sheets
; l
!= NULL
; l
= l
->next
, i
++) {
4571 Sheet
*sheet
= l
->data
;
4573 g_string_append (namelist
, sheet
->name_unquoted
);
4574 me
->old_factors
[i
] = sheet
->last_zoom_factor_used
;
4577 g_string_append (namelist
, ", ");
4580 /* Make sure the string doesn't get overly wide */
4581 gnm_cmd_trunc_descriptor (namelist
, NULL
);
4583 me
->cmd
.sheet
= NULL
;
4585 me
->cmd
.cmd_descriptor
=
4586 g_strdup_printf (_("Zoom %s to %.0f%%"), namelist
->str
, factor
* 100);
4588 g_string_free (namelist
, TRUE
);
4590 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
4593 /******************************************************************/
4595 #define CMD_OBJECTS_DELETE_TYPE (cmd_objects_delete_get_type ())
4596 #define CMD_OBJECTS_DELETE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_OBJECTS_DELETE_TYPE, CmdObjectsDelete))
4604 MAKE_GNM_COMMAND (CmdObjectsDelete
, cmd_objects_delete
, NULL
)
4607 cmd_objects_delete_redo (GnmCommand
*cmd
,
4608 G_GNUC_UNUSED WorkbookControl
*wbc
)
4610 CmdObjectsDelete
*me
= CMD_OBJECTS_DELETE (cmd
);
4611 g_slist_foreach (me
->objects
, (GFunc
) sheet_object_clear_sheet
, NULL
);
4616 cmd_objects_restore_location (SheetObject
*so
, gint location
)
4618 gint loc
= sheet_object_get_stacking (so
);
4619 if (loc
!= location
)
4620 sheet_object_adjust_stacking(so
, location
- loc
);
4624 cmd_objects_delete_undo (GnmCommand
*cmd
,
4625 G_GNUC_UNUSED WorkbookControl
*wbc
)
4627 CmdObjectsDelete
*me
= CMD_OBJECTS_DELETE (cmd
);
4631 g_slist_foreach (me
->objects
,
4632 (GFunc
) sheet_object_set_sheet
, me
->cmd
.sheet
);
4634 for (l
= me
->objects
, i
= 0; l
; l
= l
->next
, i
++)
4635 cmd_objects_restore_location (GNM_SO (l
->data
),
4636 g_array_index(me
->location
,
4642 cmd_objects_delete_finalize (GObject
*cmd
)
4644 CmdObjectsDelete
*me
= CMD_OBJECTS_DELETE (cmd
);
4645 g_slist_free_full (me
->objects
, g_object_unref
);
4647 g_array_free (me
->location
, TRUE
);
4648 me
->location
= NULL
;
4650 gnm_command_finalize (cmd
);
4654 cmd_objects_store_location (SheetObject
*so
, GArray
*location
)
4656 gint loc
= sheet_object_get_stacking (so
);
4657 g_array_append_val (location
, loc
);
4661 * cmd_objects_delete:
4662 * @wbc: #WorkbookControl
4663 * @objects: (element-type SheetObject) (transfer container): the objects to
4667 * Absorbs the list, adding references to the contents.
4670 cmd_objects_delete (WorkbookControl
*wbc
, GSList
*objects
,
4673 CmdObjectsDelete
*me
;
4675 g_return_val_if_fail (GNM_IS_WBC (wbc
), TRUE
);
4676 g_return_val_if_fail (objects
!= NULL
, TRUE
);
4678 me
= g_object_new (CMD_OBJECTS_DELETE_TYPE
, NULL
);
4680 me
->objects
= objects
;
4681 g_slist_foreach (me
->objects
, (GFunc
) g_object_ref
, NULL
);
4683 me
->location
= g_array_new (FALSE
, FALSE
, sizeof (gint
));
4684 g_slist_foreach (me
->objects
, (GFunc
) cmd_objects_store_location
,
4687 me
->cmd
.sheet
= sheet_object_get_sheet (objects
->data
);
4689 me
->cmd
.cmd_descriptor
= g_strdup (name
? name
: _("Delete Object"));
4691 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
4694 /******************************************************************/
4698 * @wbc: #WorkbookControl
4699 * @objects: (element-type SheetObject) (transfer container): the objects to move.
4700 * @anchors: (element-type SheetObjectAnchor) (transfer full): the anchors for the objects.
4706 cmd_objects_move (WorkbookControl
*wbc
, GSList
*objects
, GSList
*anchors
,
4707 gboolean objects_created
, char const *name
)
4709 GOUndo
*undo
= NULL
;
4710 GOUndo
*redo
= NULL
;
4711 gboolean result
= TRUE
;
4713 g_return_val_if_fail (GNM_IS_WBC (wbc
), TRUE
);
4715 undo
= sheet_object_move_undo (objects
, objects_created
);
4716 redo
= sheet_object_move_do (objects
, anchors
, objects_created
);
4718 result
= cmd_generic (wbc
, name
, undo
, redo
);
4720 g_slist_free (objects
);
4721 g_slist_free_full (anchors
, g_free
);
4726 /******************************************************************/
4728 #define CMD_REORGANIZE_SHEETS_TYPE (cmd_reorganize_sheets_get_type ())
4729 #define CMD_REORGANIZE_SHEETS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_REORGANIZE_SHEETS_TYPE, CmdReorganizeSheets))
4734 WorkbookSheetState
*old
;
4735 WorkbookSheetState
*new;
4739 } CmdReorganizeSheets
;
4741 MAKE_GNM_COMMAND (CmdReorganizeSheets
, cmd_reorganize_sheets
, NULL
)
4744 cmd_reorganize_sheets_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
4746 CmdReorganizeSheets
*me
= CMD_REORGANIZE_SHEETS (cmd
);
4747 workbook_sheet_state_restore (me
->wb
, me
->old
);
4748 if (me
->undo_sheet
) {
4749 WORKBOOK_VIEW_FOREACH_CONTROL (wb_control_view (wbc
), control
,
4750 wb_control_sheet_focus (control
, me
->undo_sheet
););
4756 cmd_reorganize_sheets_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
4758 CmdReorganizeSheets
*me
= CMD_REORGANIZE_SHEETS (cmd
);
4763 workbook_sheet_state_restore (me
->wb
, me
->new);
4764 if (me
->redo_sheet
) {
4765 WORKBOOK_VIEW_FOREACH_CONTROL (wb_control_view (wbc
), control
,
4766 wb_control_sheet_focus (control
, me
->redo_sheet
););
4774 cmd_reorganize_sheets_finalize (GObject
*cmd
)
4776 CmdReorganizeSheets
*me
= CMD_REORGANIZE_SHEETS (cmd
);
4779 workbook_sheet_state_free (me
->old
);
4781 workbook_sheet_state_free (me
->new);
4783 gnm_command_finalize (cmd
);
4787 cmd_reorganize_sheets (WorkbookControl
*wbc
,
4788 WorkbookSheetState
*old_state
,
4791 CmdReorganizeSheets
*me
;
4792 Workbook
*wb
= wb_control_get_workbook (wbc
);
4794 me
= g_object_new (CMD_REORGANIZE_SHEETS_TYPE
, NULL
);
4796 me
->old
= old_state
;
4797 me
->new = workbook_sheet_state_new (me
->wb
);
4799 me
->undo_sheet
= undo_sheet
;
4800 me
->redo_sheet
= wb_control_cur_sheet (wbc
);
4802 me
->cmd
.sheet
= NULL
;
4803 me
->cmd
.size
= workbook_sheet_state_size (me
->old
) +
4804 workbook_sheet_state_size (me
->new);
4805 me
->cmd
.cmd_descriptor
=
4806 workbook_sheet_state_diff (me
->old
, me
->new);
4808 if (me
->cmd
.cmd_descriptor
)
4809 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
4812 g_object_unref (me
);
4816 /******************************************************************/
4819 cmd_rename_sheet (WorkbookControl
*wbc
,
4821 char const *new_name
)
4823 WorkbookSheetState
*old_state
;
4826 g_return_val_if_fail (new_name
!= NULL
, TRUE
);
4827 g_return_val_if_fail (sheet
!= NULL
, TRUE
);
4829 if (*new_name
== 0) {
4830 go_cmd_context_error_invalid (GO_CMD_CONTEXT (wbc
), _("Name"), _("Sheet names must be non-empty."));
4834 collision
= workbook_sheet_by_name (sheet
->workbook
, new_name
);
4835 if (collision
&& collision
!= sheet
) {
4836 GError
*err
= g_error_new (go_error_invalid(), 0,
4837 _("A workbook cannot have two sheets with the same name."));
4838 go_cmd_context_error (GO_CMD_CONTEXT (wbc
), err
);
4843 old_state
= workbook_sheet_state_new (sheet
->workbook
);
4844 g_object_set (sheet
, "name", new_name
, NULL
);
4845 return cmd_reorganize_sheets (wbc
, old_state
, sheet
);
4848 /******************************************************************/
4850 #define CMD_RESIZE_SHEETS_TYPE (cmd_resize_sheets_get_type ())
4851 #define CMD_RESIZE_SHEETS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_RESIZE_SHEETS_TYPE, CmdResizeSheets))
4860 MAKE_GNM_COMMAND (CmdResizeSheets
, cmd_resize_sheets
, NULL
)
4863 cmd_resize_sheets_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
4865 CmdResizeSheets
*me
= CMD_RESIZE_SHEETS (cmd
);
4866 GOCmdContext
*cc
= GO_CMD_CONTEXT (wbc
);
4868 go_undo_undo_with_data (me
->undo
, cc
);
4869 g_object_unref (me
->undo
);
4876 cmd_resize_sheets_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
4878 CmdResizeSheets
*me
= CMD_RESIZE_SHEETS (cmd
);
4879 GOCmdContext
*cc
= GO_CMD_CONTEXT (wbc
);
4882 for (l
= me
->sheets
; l
; l
= l
->next
) {
4883 Sheet
*sheet
= l
->data
;
4885 GOUndo
*u
= gnm_sheet_resize (sheet
, me
->cols
, me
->rows
,
4887 me
->undo
= go_undo_combine (me
->undo
, u
);
4891 go_undo_undo_with_data (me
->undo
, cc
);
4900 cmd_resize_sheets_finalize (GObject
*cmd
)
4902 CmdResizeSheets
*me
= CMD_RESIZE_SHEETS (cmd
);
4904 g_slist_free (me
->sheets
);
4906 g_object_unref (me
->undo
);
4910 gnm_command_finalize (cmd
);
4914 * cmd_resize_sheets:
4915 * @wbc: #WorkbookControl
4916 * @sheets: (element-type Sheet) (transfer container): the sheets to resize.
4917 * @cols: new columns number.
4918 * @rows: new rows number.
4922 cmd_resize_sheets (WorkbookControl
*wbc
,
4926 CmdResizeSheets
*me
;
4928 me
= g_object_new (CMD_RESIZE_SHEETS_TYPE
, NULL
);
4929 me
->sheets
= sheets
;
4932 me
->cmd
.sheet
= sheets
? sheets
->data
: NULL
;
4934 me
->cmd
.cmd_descriptor
= g_strdup (_("Resizing sheet"));
4937 gnm_sheet_valid_size (cols
, rows
))
4938 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
4941 g_object_unref (me
);
4945 /******************************************************************/
4947 #define CMD_SET_COMMENT_TYPE (cmd_set_comment_get_type ())
4948 #define CMD_SET_COMMENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_SET_COMMENT_TYPE, CmdSetComment))
4959 PangoAttrList
*old_attributes
;
4960 PangoAttrList
*new_attributes
;
4963 MAKE_GNM_COMMAND (CmdSetComment
, cmd_set_comment
, NULL
)
4966 cmd_set_comment_apply (Sheet
*sheet
, GnmCellPos
*pos
,
4967 char const *text
, PangoAttrList
*attributes
,
4970 GnmComment
*comment
;
4971 Workbook
*wb
= sheet
->workbook
;
4973 comment
= sheet_get_comment (sheet
, pos
);
4976 g_object_set (G_OBJECT (comment
), "text", text
,
4978 "markup", attributes
, NULL
);
4982 mr
= gnm_sheet_merge_contains_pos (sheet
, pos
);
4985 sheet_objects_clear (sheet
, mr
, GNM_CELL_COMMENT_TYPE
, NULL
);
4988 r
.start
= r
.end
= *pos
;
4989 sheet_objects_clear (sheet
, &r
, GNM_CELL_COMMENT_TYPE
, NULL
);
4992 } else if (text
&& (strlen (text
) > 0)) {
4993 cell_set_comment (sheet
, pos
, author
, text
, attributes
);
4995 sheet_mark_dirty (sheet
);
4997 WORKBOOK_FOREACH_CONTROL (wb
, view
, ctl
,
4998 wb_control_menu_state_update (ctl
, MS_COMMENT_LINKS
););
5004 cmd_set_comment_undo (GnmCommand
*cmd
,
5005 G_GNUC_UNUSED WorkbookControl
*wbc
)
5007 CmdSetComment
*me
= CMD_SET_COMMENT (cmd
);
5009 return cmd_set_comment_apply (me
->sheet
, &me
->pos
,
5010 me
->old_text
, me
->old_attributes
,
5015 cmd_set_comment_redo (GnmCommand
*cmd
,
5016 G_GNUC_UNUSED WorkbookControl
*wbc
)
5018 CmdSetComment
*me
= CMD_SET_COMMENT (cmd
);
5020 return cmd_set_comment_apply (me
->sheet
, &me
->pos
,
5021 me
->new_text
, me
->new_attributes
,
5026 cmd_set_comment_finalize (GObject
*cmd
)
5028 CmdSetComment
*me
= CMD_SET_COMMENT (cmd
);
5030 g_free (me
->new_text
);
5031 me
->new_text
= NULL
;
5033 g_free (me
->old_text
);
5034 me
->old_text
= NULL
;
5036 g_free (me
->new_author
);
5037 me
->new_author
= NULL
;
5039 g_free (me
->old_author
);
5040 me
->old_author
= NULL
;
5042 if (me
->old_attributes
!= NULL
) {
5043 pango_attr_list_unref (me
->old_attributes
);
5044 me
->old_attributes
= NULL
;
5047 if (me
->new_attributes
!= NULL
) {
5048 pango_attr_list_unref (me
->new_attributes
);
5049 me
->new_attributes
= NULL
;
5052 gnm_command_finalize (cmd
);
5056 cmd_set_comment (WorkbookControl
*wbc
,
5057 Sheet
*sheet
, GnmCellPos
const *pos
,
5058 char const *new_text
,
5059 PangoAttrList
*attr
,
5060 char const *new_author
)
5063 GnmComment
*comment
;
5066 g_return_val_if_fail (IS_SHEET (sheet
), TRUE
);
5067 g_return_val_if_fail (new_text
!= NULL
, TRUE
);
5069 me
= g_object_new (CMD_SET_COMMENT_TYPE
, NULL
);
5071 me
->cmd
.sheet
= sheet
;
5073 if (strlen (new_text
) < 1)
5074 me
->new_text
= NULL
;
5076 me
->new_text
= g_strdup (new_text
);
5077 if (strlen (new_author
) < 1)
5078 me
->new_author
= NULL
;
5080 me
->new_author
= g_strdup (new_author
);
5082 pango_attr_list_ref (attr
);
5083 me
->new_attributes
= attr
;
5084 where
= undo_cell_pos_name (sheet
, pos
);
5085 me
->cmd
.cmd_descriptor
=
5086 g_strdup_printf (me
->new_text
== NULL
?
5087 _("Clearing comment of %s") :
5088 _("Setting comment of %s"),
5091 me
->old_text
= NULL
;
5092 me
->old_author
= NULL
;
5093 me
->old_attributes
= NULL
;
5096 comment
= sheet_get_comment (sheet
, pos
);
5098 g_object_get (G_OBJECT (comment
),
5099 "text", &(me
->old_text
),
5100 "author", &(me
->old_author
),
5101 "markup", &(me
->old_attributes
), NULL
);
5102 if (me
->old_attributes
!= NULL
)
5103 pango_attr_list_ref (me
->old_attributes
);
5104 me
->old_text
= g_strdup (me
->old_text
);
5105 me
->old_author
= g_strdup (me
->old_author
);
5108 /* Register the command object */
5109 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
5112 /******************************************************************/
5114 #define CMD_ANALYSIS_TOOL_TYPE (cmd_analysis_tool_get_type ())
5115 #define CMD_ANALYSIS_TOOL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_ANALYSIS_TOOL_TYPE, CmdAnalysis_Tool))
5120 data_analysis_output_t
*dao
;
5122 gboolean specs_owned
;
5123 analysis_tool_engine engine
;
5124 data_analysis_output_type_t type
;
5126 ColRowStateList
*col_info
;
5127 ColRowStateList
*row_info
;
5129 GnmCellRegion
*old_contents
;
5130 GSList
*newSheetObjects
;
5133 MAKE_GNM_COMMAND (CmdAnalysis_Tool
, cmd_analysis_tool
, NULL
)
5136 cmd_analysis_tool_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
5138 CmdAnalysis_Tool
*me
= CMD_ANALYSIS_TOOL (cmd
);
5141 g_return_val_if_fail (me
!= NULL
, TRUE
);
5143 /* The old view might not exist anymore */
5147 case NewSheetOutput
:
5148 if (!command_undo_sheet_delete (me
->dao
->sheet
))
5150 me
->dao
->sheet
= NULL
;
5152 case NewWorkbookOutput
:
5153 g_warning ("How did we get here?");
5158 sheet_clear_region (me
->dao
->sheet
,
5159 me
->old_range
.start
.col
, me
->old_range
.start
.row
,
5160 me
->old_range
.end
.col
, me
->old_range
.end
.row
,
5161 CLEAR_COMMENTS
| CLEAR_FORMATS
| CLEAR_NOCHECKARRAY
|
5162 CLEAR_RECALC_DEPS
| CLEAR_VALUES
| CLEAR_MERGES
,
5163 GO_CMD_CONTEXT (wbc
));
5164 clipboard_paste_region (me
->old_contents
,
5165 paste_target_init (&pt
, me
->dao
->sheet
, &me
->old_range
, PASTE_ALL_SHEET
),
5166 GO_CMD_CONTEXT (wbc
));
5167 cellregion_unref (me
->old_contents
);
5168 me
->old_contents
= NULL
;
5170 dao_set_colrow_state_list (me
->dao
, TRUE
, me
->col_info
);
5171 me
->col_info
= colrow_state_list_destroy (me
->col_info
);
5174 dao_set_colrow_state_list (me
->dao
, FALSE
, me
->row_info
);
5175 me
->row_info
= colrow_state_list_destroy (me
->row_info
);
5177 if (me
->newSheetObjects
== NULL
)
5178 me
->newSheetObjects
= dao_surrender_so (me
->dao
);
5179 g_slist_foreach (me
->newSheetObjects
, (GFunc
)sheet_object_clear_sheet
, NULL
);
5180 sheet_update (me
->dao
->sheet
);
5187 cmd_analysis_tool_draw_old_so (SheetObject
*so
, data_analysis_output_t
*dao
)
5190 dao_set_sheet_object (dao
, 0, 1, so
);
5194 cmd_analysis_tool_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
5196 gpointer continuity
= NULL
;
5197 CmdAnalysis_Tool
*me
= CMD_ANALYSIS_TOOL (cmd
);
5198 GOCmdContext
*cc
= GO_CMD_CONTEXT (wbc
);
5200 g_return_val_if_fail (me
!= NULL
, TRUE
);
5202 /* The old view might not exist anymore */
5206 me
->col_info
= colrow_state_list_destroy (me
->col_info
);
5207 me
->col_info
= dao_get_colrow_state_list (me
->dao
, TRUE
);
5209 me
->row_info
= colrow_state_list_destroy (me
->row_info
);
5210 me
->row_info
= dao_get_colrow_state_list (me
->dao
, FALSE
);
5212 if (me
->engine (cc
, me
->dao
, me
->specs
, TOOL_ENGINE_PREPARE_OUTPUT_RANGE
, NULL
)
5213 || me
->engine (cc
, me
->dao
, me
->specs
, TOOL_ENGINE_UPDATE_DESCRIPTOR
,
5214 &me
->cmd
.cmd_descriptor
)
5215 || cmd_dao_is_locked_effective (me
->dao
, wbc
, me
->cmd
.cmd_descriptor
)
5216 || me
->engine (cc
, me
->dao
, me
->specs
, TOOL_ENGINE_LAST_VALIDITY_CHECK
, &continuity
))
5220 case NewSheetOutput
:
5221 me
->old_contents
= NULL
;
5223 case NewWorkbookOutput
:
5224 /* No undo in this case (see below) */
5225 me
->old_contents
= NULL
;
5229 range_init (&me
->old_range
, me
->dao
->start_col
, me
->dao
->start_row
,
5230 me
->dao
->start_col
+ me
->dao
->cols
- 1,
5231 me
->dao
->start_row
+ me
->dao
->rows
- 1);
5232 me
->old_contents
= clipboard_copy_range (me
->dao
->sheet
, &me
->old_range
);
5236 if (me
->newSheetObjects
!= NULL
)
5237 dao_set_omit_so (me
->dao
, TRUE
);
5239 if (me
->engine (cc
, me
->dao
, me
->specs
, TOOL_ENGINE_FORMAT_OUTPUT_RANGE
, NULL
))
5242 if (me
->engine (cc
, me
->dao
, me
->specs
, TOOL_ENGINE_PERFORM_CALC
, &continuity
)) {
5243 if (me
->type
== RangeOutput
) {
5244 g_warning ("This is too late for failure! The target region has "
5245 "already been formatted!");
5249 if (me
->newSheetObjects
!= NULL
)
5251 GSList
*l
= g_slist_reverse
5252 (g_slist_copy (me
->newSheetObjects
));
5254 dao_set_omit_so (me
->dao
, FALSE
);
5256 (GFunc
) cmd_analysis_tool_draw_old_so
,
5262 g_warning ("There shouldn't be any data left in here!");
5265 dao_autofit_columns (me
->dao
);
5266 sheet_mark_dirty (me
->dao
->sheet
);
5267 sheet_update (me
->dao
->sheet
);
5269 /* The concept of an undo if we create a new worksheet is extremely strange,
5270 * since we have separate undo/redo queues per worksheet.
5271 * Users can simply delete the worksheet if they so desire.
5274 return (me
->type
== NewWorkbookOutput
);
5278 cmd_analysis_tool_finalize (GObject
*cmd
)
5280 CmdAnalysis_Tool
*me
= CMD_ANALYSIS_TOOL (cmd
);
5283 me
->col_info
= colrow_state_list_destroy (me
->col_info
);
5285 me
->row_info
= colrow_state_list_destroy (me
->row_info
);
5287 me
->engine (NULL
, me
->dao
, me
->specs
, TOOL_ENGINE_CLEAN_UP
, NULL
);
5289 if (me
->specs_owned
) {
5293 if (me
->old_contents
)
5294 cellregion_unref (me
->old_contents
);
5296 g_slist_free_full (me
->newSheetObjects
, g_object_unref
);
5298 gnm_command_finalize (cmd
);
5302 * cmd_analysis_tool: (skip)
5303 * Note: this takes ownership of specs and dao if and if only the command
5307 cmd_analysis_tool (WorkbookControl
*wbc
, G_GNUC_UNUSED Sheet
*sheet
,
5308 data_analysis_output_t
*dao
, gpointer specs
,
5309 analysis_tool_engine engine
, gboolean always_take_ownership
)
5311 CmdAnalysis_Tool
*me
;
5313 GOCmdContext
*cc
= GO_CMD_CONTEXT (wbc
);
5315 g_return_val_if_fail (dao
!= NULL
, TRUE
);
5316 g_return_val_if_fail (specs
!= NULL
, TRUE
);
5317 g_return_val_if_fail (engine
!= NULL
, TRUE
);
5319 me
= g_object_new (CMD_ANALYSIS_TOOL_TYPE
, NULL
);
5323 /* Store the specs for the object */
5325 me
->specs_owned
= always_take_ownership
;
5327 me
->engine
= engine
;
5328 me
->cmd
.cmd_descriptor
= NULL
;
5329 if (me
->engine (cc
, me
->dao
, me
->specs
, TOOL_ENGINE_UPDATE_DAO
, NULL
)) {
5330 g_object_unref (me
);
5333 me
->engine (cc
, me
->dao
, me
->specs
, TOOL_ENGINE_UPDATE_DESCRIPTOR
,
5334 &me
->cmd
.cmd_descriptor
);
5335 me
->cmd
.sheet
= NULL
;
5336 me
->type
= dao
->type
;
5337 me
->row_info
= NULL
;
5338 me
->col_info
= NULL
;
5340 /* We divide by 2 since many cells will be empty*/
5341 me
->cmd
.size
= 1 + dao
->rows
* dao
->cols
/ 2;
5343 /* Register the command object */
5344 trouble
= gnm_command_push_undo (wbc
, G_OBJECT (me
));
5347 me
->specs_owned
= TRUE
;
5352 /******************************************************************/
5354 #define CMD_MERGE_DATA_TYPE (cmd_merge_data_get_type ())
5355 #define CMD_MERGE_DATA(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_MERGE_DATA_TYPE, CmdMergeData))
5359 GnmValue
*merge_zone
;
5360 GSList
*merge_fields
;
5367 MAKE_GNM_COMMAND (CmdMergeData
, cmd_merge_data
, NULL
)
5370 cmd_merge_data_delete_sheets (gpointer data
, gpointer success
)
5372 Sheet
*sheet
= data
;
5374 if (!command_undo_sheet_delete (sheet
))
5375 *(gboolean
*)success
= FALSE
;
5379 cmd_merge_data_undo (GnmCommand
*cmd
,
5380 G_GNUC_UNUSED WorkbookControl
*wbc
)
5382 CmdMergeData
*me
= CMD_MERGE_DATA (cmd
);
5383 gboolean success
= TRUE
;
5385 g_slist_foreach (me
->sheet_list
, cmd_merge_data_delete_sheets
, &success
);
5386 g_slist_free (me
->sheet_list
);
5387 me
->sheet_list
= NULL
;
5393 cmd_merge_data_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
5395 CmdMergeData
*me
= CMD_MERGE_DATA (cmd
);
5397 GnmCellRegion
*merge_contents
;
5398 GnmRangeRef
*cell
= &me
->merge_zone
->v_range
.cell
;
5400 GSList
*this_field
= me
->merge_fields
;
5401 GSList
*this_data
= me
->merge_data
;
5402 Sheet
*source_sheet
= cell
->a
.sheet
;
5403 GSList
*target_sheet
;
5404 GnmRange target_range
;
5405 ColRowStateList
*state_col
;
5406 ColRowStateList
*state_row
;
5408 range_init (&target_range
, cell
->a
.col
, cell
->a
.row
,
5409 cell
->b
.col
, cell
->b
.row
);
5410 merge_contents
= clipboard_copy_range (source_sheet
, &target_range
);
5411 state_col
= colrow_get_states (source_sheet
, TRUE
, target_range
.start
.col
,
5412 target_range
.end
.col
);
5413 state_row
= colrow_get_states (source_sheet
, FALSE
, target_range
.start
.row
,
5414 target_range
.end
.row
);
5416 for (i
= 0; i
< me
->n
; i
++) {
5419 new_sheet
= workbook_sheet_add (me
->sheet
->workbook
, -1,
5420 gnm_sheet_get_max_cols (me
->sheet
),
5421 gnm_sheet_get_max_rows (me
->sheet
));
5422 me
->sheet_list
= g_slist_prepend (me
->sheet_list
, new_sheet
);
5424 colrow_set_states (new_sheet
, TRUE
, target_range
.start
.col
, state_col
);
5425 colrow_set_states (new_sheet
, FALSE
, target_range
.start
.row
, state_row
);
5426 sheet_objects_dup (source_sheet
, new_sheet
, &target_range
);
5427 clipboard_paste_region (merge_contents
,
5428 paste_target_init (&pt
, new_sheet
, &target_range
, PASTE_ALL_SHEET
),
5429 GO_CMD_CONTEXT (wbc
));
5431 cellregion_unref (merge_contents
);
5432 me
->sheet_list
= g_slist_reverse (me
->sheet_list
);
5433 colrow_state_list_destroy (state_col
);
5434 colrow_state_list_destroy (state_row
);
5436 while (this_field
) {
5437 int col_source
, row_source
;
5438 int col_target
, row_target
;
5440 g_return_val_if_fail (this_data
!= NULL
, TRUE
);
5441 cell
= &((GnmValue
*)this_field
->data
)->v_range
.cell
;
5442 col_target
= cell
->a
.col
;
5443 row_target
= cell
->a
.row
;
5445 cell
= &((GnmValue
*)this_data
->data
)->v_range
.cell
;
5446 col_source
= cell
->a
.col
;
5447 row_source
= cell
->a
.row
;
5448 source_sheet
= cell
->a
.sheet
;
5450 target_sheet
= me
->sheet_list
;
5451 while (target_sheet
) {
5452 GnmCell
*source_cell
= sheet_cell_get (source_sheet
,
5453 col_source
, row_source
);
5454 if (source_cell
== NULL
) {
5455 GnmCell
*target_cell
= sheet_cell_get ((Sheet
*)target_sheet
->data
,
5456 col_target
, row_target
);
5457 if (target_cell
!= NULL
)
5458 gnm_cell_set_value (target_cell
,
5459 value_new_empty ());
5461 GnmCell
*target_cell
= sheet_cell_fetch ((Sheet
*)target_sheet
->data
,
5462 col_target
, row_target
);
5463 gnm_cell_set_value (target_cell
,
5464 value_dup (source_cell
->value
));
5466 target_sheet
= target_sheet
->next
;
5470 this_field
= this_field
->next
;
5471 this_data
= this_data
->next
;
5478 cmd_merge_data_finalize (GObject
*cmd
)
5480 CmdMergeData
*me
= CMD_MERGE_DATA (cmd
);
5482 value_release (me
->merge_zone
);
5483 me
->merge_zone
= NULL
;
5484 range_list_destroy (me
->merge_data
);
5485 me
->merge_data
= NULL
;
5486 range_list_destroy (me
->merge_fields
);
5487 me
->merge_fields
= NULL
;
5488 g_slist_free (me
->sheet_list
);
5489 me
->sheet_list
= NULL
;
5492 gnm_command_finalize (cmd
);
5497 * @wbc: #WorkbookControl
5499 * @merge_zone: (transfer full): #GnmValue
5500 * @merge_fields: (element-type GnmRange) (transfer full):
5501 * @merge_data: (element-type GnmRange) (transfer full):
5505 cmd_merge_data (WorkbookControl
*wbc
, Sheet
*sheet
,
5506 GnmValue
*merge_zone
, GSList
*merge_fields
, GSList
*merge_data
)
5511 g_return_val_if_fail (IS_SHEET (sheet
), TRUE
);
5512 g_return_val_if_fail (merge_zone
!= NULL
, TRUE
);
5513 g_return_val_if_fail (merge_fields
!= NULL
, TRUE
);
5514 g_return_val_if_fail (merge_data
!= NULL
, TRUE
);
5516 me
= g_object_new (CMD_MERGE_DATA_TYPE
, NULL
);
5518 me
->cmd
.sheet
= sheet
;
5520 me
->cmd
.size
= 1 + g_slist_length (merge_fields
);
5521 me
->cmd
.cmd_descriptor
=
5522 g_strdup_printf (_("Merging data into %s"), value_peek_string (merge_zone
));
5524 me
->merge_zone
= merge_zone
;
5525 me
->merge_fields
= merge_fields
;
5526 me
->merge_data
= merge_data
;
5527 me
->sheet_list
= NULL
;
5529 cell
= &((GnmValue
*)merge_data
->data
)->v_range
.cell
;
5530 me
->n
= cell
->b
.row
- cell
->a
.row
+ 1;
5532 /* Register the command object */
5533 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
5536 /******************************************************************/
5538 #define CMD_CHANGE_META_DATA_TYPE (cmd_change_summary_get_type ())
5539 #define CMD_CHANGE_META_DATA(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_CHANGE_META_DATA_TYPE, CmdChangeMetaData))
5543 GSList
*changed_props
;
5544 GSList
*removed_names
;
5545 } CmdChangeMetaData
;
5547 MAKE_GNM_COMMAND (CmdChangeMetaData
, cmd_change_summary
, NULL
)
5550 cmd_change_summary_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
5552 CmdChangeMetaData
*me
= CMD_CHANGE_META_DATA (cmd
);
5553 GsfDocMetaData
*meta
= go_doc_get_meta_data (wb_control_get_doc (wbc
));
5554 GSList
*ptr
, *old_vals
= NULL
, *dropped
= NULL
;
5558 for (ptr
= me
->removed_names
; ptr
!= NULL
; ptr
= ptr
->next
) {
5559 if (NULL
!= (prop
= gsf_doc_meta_data_steal (meta
, ptr
->data
)))
5560 old_vals
= g_slist_prepend (old_vals
, prop
);
5563 g_slist_free (me
->removed_names
);
5565 for (ptr
= me
->changed_props
; ptr
!= NULL
; ptr
= ptr
->next
) {
5566 name
= gsf_doc_prop_get_name (ptr
->data
);
5567 if (NULL
!= (prop
= gsf_doc_meta_data_steal (meta
, name
)))
5568 old_vals
= g_slist_prepend (old_vals
, prop
);
5570 dropped
= g_slist_prepend (old_vals
, g_strdup (name
));
5571 gsf_doc_meta_data_store (meta
, ptr
->data
);
5573 g_slist_free (me
->changed_props
);
5575 me
->removed_names
= dropped
;
5576 me
->changed_props
= old_vals
;
5577 go_doc_update_meta_data (wb_control_get_doc (wbc
));
5583 cmd_change_summary_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
5585 return cmd_change_summary_undo (cmd
, wbc
);
5589 cmd_change_summary_finalize (GObject
*cmd
)
5591 CmdChangeMetaData
*me
= CMD_CHANGE_META_DATA (cmd
);
5593 g_slist_free_full (me
->changed_props
, (GDestroyNotify
)gsf_doc_prop_free
);
5594 me
->changed_props
= NULL
;
5595 g_slist_free_full (me
->removed_names
, g_free
);
5596 me
->removed_names
= NULL
;
5598 gnm_command_finalize (cmd
);
5602 * cmd_change_meta_data:
5603 * @wbc: #WorkbookControl
5604 * @changes: (element-type GsfDocMetaData) (transfer full): the changed metadata.
5605 * @removed: (element-type GsfDocMetaData) (transfer full): the removed metadata.
5609 cmd_change_meta_data (WorkbookControl
*wbc
, GSList
*changes
, GSList
*removed
)
5611 CmdChangeMetaData
*me
= g_object_new (CMD_CHANGE_META_DATA_TYPE
, NULL
);
5613 me
->changed_props
= changes
;
5614 me
->removed_names
= removed
;
5615 me
->cmd
.sheet
= NULL
;
5617 me
->cmd
.size
= g_slist_length (changes
) + g_slist_length (removed
);
5618 me
->cmd
.cmd_descriptor
= g_strdup_printf (
5619 _("Changing workbook properties"));
5620 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
5623 /******************************************************************/
5625 #define CMD_OBJECT_RAISE_TYPE (cmd_object_raise_get_type ())
5626 #define CMD_OBJECT_RAISE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_OBJECT_RAISE_TYPE, CmdObjectRaise))
5631 CmdObjectRaiseSelector dir
;
5632 gint changed_positions
;
5635 MAKE_GNM_COMMAND (CmdObjectRaise
, cmd_object_raise
, NULL
)
5638 cmd_object_raise_redo (GnmCommand
*cmd
,
5639 G_GNUC_UNUSED WorkbookControl
*wbc
)
5641 CmdObjectRaise
*me
= CMD_OBJECT_RAISE (cmd
);
5643 case cmd_object_pull_to_front
:
5644 me
->changed_positions
= sheet_object_adjust_stacking (me
->so
, G_MAXINT
/2);
5646 case cmd_object_pull_forward
:
5647 me
->changed_positions
= sheet_object_adjust_stacking (me
->so
, 1);
5649 case cmd_object_push_backward
:
5650 me
->changed_positions
= sheet_object_adjust_stacking (me
->so
, -1);
5652 case cmd_object_push_to_back
:
5653 me
->changed_positions
= sheet_object_adjust_stacking (me
->so
, G_MININT
/2);
5660 cmd_object_raise_undo (GnmCommand
*cmd
,
5661 G_GNUC_UNUSED WorkbookControl
*wbc
)
5663 CmdObjectRaise
*me
= CMD_OBJECT_RAISE (cmd
);
5664 if (me
->changed_positions
!= 0)
5665 sheet_object_adjust_stacking (me
->so
, - me
->changed_positions
);
5670 cmd_object_raise_finalize (GObject
*cmd
)
5672 CmdObjectRaise
*me
= CMD_OBJECT_RAISE (cmd
);
5673 g_object_unref (me
->so
);
5674 gnm_command_finalize (cmd
);
5678 cmd_object_raise (WorkbookControl
*wbc
, SheetObject
*so
, CmdObjectRaiseSelector dir
)
5682 g_return_val_if_fail (GNM_IS_SO (so
), TRUE
);
5684 me
= g_object_new (CMD_OBJECT_RAISE_TYPE
, NULL
);
5689 me
->cmd
.sheet
= sheet_object_get_sheet (so
);
5692 case cmd_object_pull_to_front
:
5693 me
->cmd
.cmd_descriptor
= g_strdup (_("Pull Object to the Front"));
5695 case cmd_object_pull_forward
:
5696 me
->cmd
.cmd_descriptor
= g_strdup (_("Pull Object Forward"));
5698 case cmd_object_push_backward
:
5699 me
->cmd
.cmd_descriptor
= g_strdup (_("Push Object Backward"));
5701 case cmd_object_push_to_back
:
5702 me
->cmd
.cmd_descriptor
= g_strdup (_("Push Object to the Back"));
5706 me
->changed_positions
= 0;
5708 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
5711 /******************************************************************/
5713 #define CMD_PRINT_SETUP_TYPE (cmd_print_setup_get_type ())
5714 #define CMD_PRINT_SETUP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_PRINT_SETUP_TYPE, CmdPrintSetup))
5720 GnmPrintInformation
*new_pi
;
5723 MAKE_GNM_COMMAND (CmdPrintSetup
, cmd_print_setup
, NULL
)
5726 update_sheet_graph_cb (Sheet
*sheet
)
5728 g_return_if_fail (IS_SHEET (sheet
) && sheet
->sheet_type
== GNM_SHEET_OBJECT
);
5730 sheet_object_graph_ensure_size (GNM_SO (sheet
->sheet_objects
->data
));
5734 cmd_print_setup_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
5736 CmdPrintSetup
*me
= CMD_PRINT_SETUP (cmd
);
5741 g_return_val_if_fail (me
->old_pi
!= NULL
, TRUE
);
5743 if (me
->cmd
.sheet
) {
5744 GnmPrintInformation
*pi
= me
->old_pi
->data
;
5745 gnm_print_info_free (me
->cmd
.sheet
->print_info
);
5746 me
->cmd
.sheet
->print_info
= gnm_print_info_dup (pi
);
5747 if (me
->cmd
.sheet
->sheet_type
== GNM_SHEET_OBJECT
)
5748 update_sheet_graph_cb (me
->cmd
.sheet
);
5750 book
= wb_control_get_workbook(wbc
);
5751 n
= workbook_sheet_count (book
);
5753 g_return_val_if_fail (g_slist_length (infos
) == n
, TRUE
);
5755 for (i
= 0 ; i
< n
; i
++) {
5756 GnmPrintInformation
*pi
= infos
->data
;
5757 Sheet
*sheet
= workbook_sheet_by_index (book
, i
);
5759 g_return_val_if_fail (infos
!= NULL
, TRUE
);
5761 gnm_print_info_free (sheet
->print_info
);
5762 sheet
->print_info
= gnm_print_info_dup (pi
);
5763 if (sheet
->sheet_type
== GNM_SHEET_OBJECT
)
5764 update_sheet_graph_cb (sheet
);
5765 infos
= infos
->next
;
5772 cmd_print_setup_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
5774 CmdPrintSetup
*me
= CMD_PRINT_SETUP (cmd
);
5777 gboolean save_pis
= (me
->old_pi
== NULL
);
5779 if (me
->cmd
.sheet
) {
5781 me
->old_pi
= g_slist_append (me
->old_pi
, me
->cmd
.sheet
->print_info
);
5783 gnm_print_info_free (me
->cmd
.sheet
->print_info
);
5784 me
->cmd
.sheet
->print_info
= gnm_print_info_dup (me
->new_pi
);
5785 if (me
->cmd
.sheet
->sheet_type
== GNM_SHEET_OBJECT
)
5786 update_sheet_graph_cb (me
->cmd
.sheet
);
5788 book
= wb_control_get_workbook(wbc
);
5789 n
= workbook_sheet_count (book
);
5790 for (i
= 0 ; i
< n
; i
++) {
5791 Sheet
*sheet
= workbook_sheet_by_index (book
, i
);
5792 sheet_mark_dirty (sheet
);
5794 me
->old_pi
= g_slist_prepend (me
->old_pi
, sheet
->print_info
);
5796 gnm_print_info_free (sheet
->print_info
);
5797 sheet
->print_info
= gnm_print_info_dup (me
->new_pi
);
5798 if (sheet
->sheet_type
== GNM_SHEET_OBJECT
)
5799 update_sheet_graph_cb (sheet
);
5802 me
->old_pi
= g_slist_reverse (me
->old_pi
);
5808 cmd_print_setup_finalize (GObject
*cmd
)
5810 CmdPrintSetup
*me
= CMD_PRINT_SETUP (cmd
);
5811 GSList
*list
= me
->old_pi
;
5814 gnm_print_info_free (me
->new_pi
);
5815 for (; list
; list
= list
->next
)
5816 gnm_print_info_free ((GnmPrintInformation
*) list
->data
);
5817 g_slist_free (me
->old_pi
);
5818 gnm_command_finalize (cmd
);
5822 cmd_print_setup (WorkbookControl
*wbc
, Sheet
*sheet
, GnmPrintInformation
const *pi
)
5826 me
= g_object_new (CMD_PRINT_SETUP_TYPE
, NULL
);
5828 me
->cmd
.sheet
= sheet
;
5831 me
->cmd
.cmd_descriptor
=
5832 g_strdup_printf (_("Page Setup For %s"), sheet
->name_unquoted
);
5834 me
->cmd
.cmd_descriptor
= g_strdup (_("Page Setup For All Sheets"));
5836 me
->new_pi
= gnm_print_info_dup (pi
);
5838 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
5841 /******************************************************************/
5843 #define CMD_DEFINE_NAME_TYPE (cmd_define_name_get_type ())
5844 #define CMD_DEFINE_NAME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_DEFINE_NAME_TYPE, CmdDefineName))
5851 GnmExprTop
const *texpr
;
5853 gboolean placeholder
;
5856 MAKE_GNM_COMMAND (CmdDefineName
, cmd_define_name
, NULL
)
5859 cmd_define_name_undo (GnmCommand
*cmd
,
5860 WorkbookControl
*wbc
)
5862 CmdDefineName
*me
= CMD_DEFINE_NAME (cmd
);
5863 GnmNamedExpr
*nexpr
= expr_name_lookup (&(me
->pp
), me
->name
);
5864 GnmExprTop
const *texpr
= nexpr
->texpr
;
5866 gnm_expr_top_ref (texpr
);
5868 expr_name_remove (nexpr
);
5869 else if (me
->placeholder
)
5870 expr_name_downgrade_to_placeholder (nexpr
);
5872 expr_name_set_expr (nexpr
, me
->texpr
); /* restore old def */
5876 WORKBOOK_FOREACH_VIEW (wb_control_get_workbook (wbc
), each_wbv
, {
5877 wb_view_menus_update (each_wbv
);
5883 cmd_define_name_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
5885 CmdDefineName
*me
= CMD_DEFINE_NAME (cmd
);
5886 GnmNamedExpr
*nexpr
= expr_name_lookup (&(me
->pp
), me
->name
);
5888 me
->new_name
= (nexpr
== NULL
);
5889 me
->placeholder
= (nexpr
!= NULL
)
5890 && expr_name_is_placeholder (nexpr
);
5892 if (me
->new_name
|| me
->placeholder
) {
5894 nexpr
= expr_name_add (&me
->pp
, me
->name
, me
->texpr
, &err
, TRUE
, NULL
);
5895 if (nexpr
== NULL
) {
5896 go_cmd_context_error_invalid (GO_CMD_CONTEXT (wbc
), _("Name"), err
);
5901 } else { /* changing the definition */
5902 GnmExprTop
const *tmp
= nexpr
->texpr
;
5903 gnm_expr_top_ref (tmp
);
5904 expr_name_set_expr (nexpr
, me
->texpr
);
5905 me
->texpr
= tmp
; /* store the old definition */
5907 WORKBOOK_FOREACH_VIEW (wb_control_get_workbook (wbc
), each_wbv
, {
5908 wb_view_menus_update (each_wbv
);
5915 cmd_define_name_finalize (GObject
*cmd
)
5917 CmdDefineName
*me
= CMD_DEFINE_NAME (cmd
);
5919 g_free (me
->name
); me
->name
= NULL
;
5922 gnm_expr_top_unref (me
->texpr
);
5926 gnm_command_finalize (cmd
);
5934 * @texpr: absorbs a ref to the texpr.
5935 * @descriptor: optional descriptor.
5937 * If the @name has never been defined in context @pp create a new name
5938 * If its a placeholder assign @texpr to it and make it real
5939 * If it already exists as a real name just assign @expr.
5941 * Returns TRUE on error
5944 cmd_define_name (WorkbookControl
*wbc
, char const *name
,
5945 GnmParsePos
const *pp
, GnmExprTop
const *texpr
,
5946 char const *descriptor
)
5949 GnmNamedExpr
*nexpr
;
5952 g_return_val_if_fail (name
!= NULL
, TRUE
);
5953 g_return_val_if_fail (pp
!= NULL
, TRUE
);
5954 g_return_val_if_fail (texpr
!= NULL
, TRUE
);
5956 if (name
[0] == '\0') {
5957 go_cmd_context_error_invalid
5958 (GO_CMD_CONTEXT (wbc
), _("Defined Name"),
5959 _("An empty string is not allowed as defined name."));
5960 gnm_expr_top_unref (texpr
);
5964 sheet
= wb_control_cur_sheet (wbc
);
5965 if (!expr_name_validate (name
)) {
5966 gchar
*err
= g_strdup_printf
5967 (_("'%s' is not allowed as defined name."), name
);
5968 go_cmd_context_error_invalid (GO_CMD_CONTEXT (wbc
),
5969 _("Defined Name"), err
);
5971 gnm_expr_top_unref (texpr
);
5975 if (expr_name_check_for_loop (name
, texpr
)) {
5976 go_cmd_context_error_invalid (GO_CMD_CONTEXT (wbc
), name
,
5977 _("has a circular reference"));
5978 gnm_expr_top_unref (texpr
);
5981 nexpr
= expr_name_lookup (pp
, name
);
5982 if (nexpr
!= NULL
&& !expr_name_is_placeholder (nexpr
) &&
5983 gnm_expr_top_equal (texpr
, nexpr
->texpr
)) {
5984 gnm_expr_top_unref (texpr
);
5985 return FALSE
; /* expr is not changing, do nothing */
5988 me
= g_object_new (CMD_DEFINE_NAME_TYPE
, NULL
);
5989 me
->name
= g_strdup (name
);
5993 me
->cmd
.sheet
= sheet
;
5996 if (descriptor
== NULL
) {
6000 /* Underscores need to be doubled. */
6001 res
= g_string_new (NULL
);
6002 for (tmp
= name
; *tmp
; tmp
++) {
6004 g_string_append_c (res
, '_');
6005 g_string_append_c (res
, *tmp
);
6008 nexpr
= expr_name_lookup (pp
, name
);
6009 if (nexpr
== NULL
|| expr_name_is_placeholder (nexpr
))
6010 me
->cmd
.cmd_descriptor
=
6011 g_strdup_printf (_("Define Name %s"), res
->str
);
6013 me
->cmd
.cmd_descriptor
=
6014 g_strdup_printf (_("Update Name %s"), res
->str
);
6015 g_string_free (res
, TRUE
);
6017 me
->cmd
.cmd_descriptor
= g_strdup (descriptor
);
6019 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
6022 /******************************************************************/
6024 #define CMD_REMOVE_NAME_TYPE (cmd_remove_name_get_type ())
6025 #define CMD_REMOVE_NAME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_REMOVE_NAME_TYPE, CmdRemoveName))
6031 GnmNamedExpr
*nexpr
;
6032 const GnmExprTop
*texpr
;
6035 MAKE_GNM_COMMAND (CmdRemoveName
, cmd_remove_name
, NULL
)
6038 cmd_remove_name_undo (GnmCommand
*cmd
,
6039 G_GNUC_UNUSED WorkbookControl
*wbc
)
6041 CmdRemoveName
*me
= CMD_REMOVE_NAME (cmd
);
6042 GnmNamedExpr
*nexpr
=
6043 expr_name_add (&me
->nexpr
->pos
, expr_name_name (me
->nexpr
),
6044 me
->texpr
, NULL
, TRUE
, NULL
);
6047 expr_name_ref (nexpr
);
6048 expr_name_unref (me
->nexpr
);
6052 g_warning ("Redefining name failed.");
6058 cmd_remove_name_redo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
6060 CmdRemoveName
*me
= CMD_REMOVE_NAME (cmd
);
6062 me
->texpr
= me
->nexpr
->texpr
;
6063 gnm_expr_top_ref (me
->texpr
);
6064 expr_name_downgrade_to_placeholder (me
->nexpr
);
6070 cmd_remove_name_finalize (GObject
*cmd
)
6072 CmdRemoveName
*me
= CMD_REMOVE_NAME (cmd
);
6074 expr_name_unref (me
->nexpr
);
6077 gnm_expr_top_unref (me
->texpr
);
6081 gnm_command_finalize (cmd
);
6087 * @nexpr: name to remove.
6089 * Returns TRUE on error
6092 cmd_remove_name (WorkbookControl
*wbc
, GnmNamedExpr
*nexpr
)
6096 g_return_val_if_fail (wbc
!= NULL
, TRUE
);
6097 g_return_val_if_fail (nexpr
!= NULL
, TRUE
);
6098 g_return_val_if_fail (!expr_name_is_placeholder (nexpr
), TRUE
);
6100 expr_name_ref (nexpr
);
6102 me
= g_object_new (CMD_REMOVE_NAME_TYPE
, NULL
);
6105 me
->cmd
.sheet
= wb_control_cur_sheet (wbc
);
6107 me
->cmd
.cmd_descriptor
= g_strdup_printf (_("Remove Name %s"),
6108 expr_name_name (nexpr
));
6110 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
6113 /******************************************************************/
6115 #define CMD_RESCOPE_NAME_TYPE (cmd_rescope_name_get_type ())
6116 #define CMD_RESCOPE_NAME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_RESCOPE_NAME_TYPE, CmdRescopeName))
6120 GnmNamedExpr
*nexpr
;
6124 MAKE_GNM_COMMAND (CmdRescopeName
, cmd_rescope_name
, NULL
)
6127 cmd_rescope_name_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
6129 CmdRescopeName
*me
= CMD_RESCOPE_NAME (cmd
);
6130 Sheet
*old_scope
= me
->nexpr
->pos
.sheet
;
6132 GnmParsePos pp
= me
->nexpr
->pos
;
6134 pp
.sheet
= me
->scope
;
6135 err
= expr_name_set_pos (me
->nexpr
, &pp
);
6138 go_cmd_context_error_invalid (GO_CMD_CONTEXT (wbc
), _("Change Scope of Name"), err
);
6143 me
->scope
= old_scope
;
6148 cmd_rescope_name_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
6150 return cmd_rescope_name_redo (cmd
, wbc
);
6155 cmd_rescope_name_finalize (GObject
*cmd
)
6157 CmdRescopeName
*me
= CMD_RESCOPE_NAME (cmd
);
6159 expr_name_unref (me
->nexpr
);
6160 gnm_command_finalize (cmd
);
6166 * @nexpr: name to rescope.
6168 * Returns TRUE on error
6171 cmd_rescope_name (WorkbookControl
*wbc
, GnmNamedExpr
*nexpr
, Sheet
*scope
)
6175 g_return_val_if_fail (wbc
!= NULL
, TRUE
);
6176 g_return_val_if_fail (nexpr
!= NULL
, TRUE
);
6177 g_return_val_if_fail (!expr_name_is_placeholder (nexpr
), TRUE
);
6179 expr_name_ref (nexpr
);
6181 me
= g_object_new (CMD_RESCOPE_NAME_TYPE
, NULL
);
6184 me
->cmd
.sheet
= wb_control_cur_sheet (wbc
);
6186 me
->cmd
.cmd_descriptor
= g_strdup_printf (_("Change Scope of Name %s"),
6187 expr_name_name (nexpr
));
6189 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
6191 /******************************************************************/
6193 #define CMD_SCENARIO_ADD_TYPE (cmd_scenario_add_get_type ())
6194 #define CMD_SCENARIO_ADD(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_SCENARIO_ADD_TYPE, CmdScenarioAdd))
6198 GnmScenario
*scenario
;
6201 MAKE_GNM_COMMAND (CmdScenarioAdd
, cmd_scenario_add
, NULL
)
6204 cmd_scenario_add_redo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
6206 CmdScenarioAdd
*me
= CMD_SCENARIO_ADD (cmd
);
6207 GnmScenario
*sc
= g_object_ref (me
->scenario
);
6208 gnm_sheet_scenario_add (sc
->sheet
, sc
);
6213 cmd_scenario_add_undo (GnmCommand
*cmd
,
6214 G_GNUC_UNUSED WorkbookControl
*wbc
)
6216 CmdScenarioAdd
*me
= CMD_SCENARIO_ADD (cmd
);
6217 GnmScenario
*sc
= me
->scenario
;
6218 gnm_sheet_scenario_remove (sc
->sheet
, sc
);
6223 cmd_scenario_add_finalize (GObject
*cmd
)
6225 CmdScenarioAdd
*me
= CMD_SCENARIO_ADD (cmd
);
6227 g_object_unref (me
->scenario
);
6228 gnm_command_finalize (cmd
);
6232 cmd_scenario_add (WorkbookControl
*wbc
, GnmScenario
*s
, Sheet
*sheet
)
6236 g_return_val_if_fail (GNM_IS_WBC (wbc
), TRUE
);
6237 g_return_val_if_fail (IS_SHEET (sheet
), TRUE
);
6239 me
= g_object_new (CMD_SCENARIO_ADD_TYPE
, NULL
);
6241 me
->scenario
= s
; /* Take ownership */
6242 me
->cmd
.sheet
= sheet
;
6244 me
->cmd
.cmd_descriptor
= g_strdup (_("Add scenario"));
6246 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
6249 /******************************************************************/
6251 #define CMD_SCENARIO_MNGR_TYPE (cmd_scenario_mngr_get_type ())
6252 #define CMD_SCENARIO_MNGR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_SCENARIO_MNGR_TYPE, CmdScenarioMngr))
6260 MAKE_GNM_COMMAND (CmdScenarioMngr
, cmd_scenario_mngr
, NULL
)
6263 cmd_scenario_mngr_redo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
6265 CmdScenarioMngr
*me
= CMD_SCENARIO_MNGR (cmd
);
6267 me
->undo
= gnm_scenario_apply (me
->sc
);
6272 cmd_scenario_mngr_undo (GnmCommand
*cmd
,
6273 G_GNUC_UNUSED WorkbookControl
*wbc
)
6275 CmdScenarioMngr
*me
= CMD_SCENARIO_MNGR (cmd
);
6276 go_undo_undo_with_data (me
->undo
, GO_CMD_CONTEXT (wbc
));
6277 g_object_unref (me
->undo
);
6283 cmd_scenario_mngr_finalize (GObject
*cmd
)
6285 CmdScenarioMngr
*me
= CMD_SCENARIO_MNGR (cmd
);
6287 g_object_unref (me
->sc
);
6289 g_object_unref (me
->undo
);
6291 gnm_command_finalize (cmd
);
6295 cmd_scenario_mngr (WorkbookControl
*wbc
, GnmScenario
*sc
, GOUndo
*undo
)
6297 CmdScenarioMngr
*me
;
6299 g_return_val_if_fail (GNM_IS_WBC (wbc
), TRUE
);
6300 g_return_val_if_fail (GNM_IS_SCENARIO (sc
), TRUE
);
6302 me
= g_object_new (CMD_SCENARIO_MNGR_TYPE
, NULL
);
6304 me
->sc
= g_object_ref (sc
);
6305 me
->undo
= g_object_ref (undo
);
6306 me
->cmd
.sheet
= sc
->sheet
;
6308 me
->cmd
.cmd_descriptor
= g_strdup (_("Scenario Show"));
6310 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
6313 /******************************************************************/
6315 #define CMD_DATA_SHUFFLE_TYPE (cmd_data_shuffle_get_type ())
6316 #define CMD_DATA_SHUFFLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_DATA_SHUFFLE_TYPE, CmdDataShuffle))
6320 data_shuffling_t
*ds
;
6323 MAKE_GNM_COMMAND (CmdDataShuffle
, cmd_data_shuffle
, NULL
)
6326 cmd_data_shuffle_redo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
6328 CmdDataShuffle
*me
= CMD_DATA_SHUFFLE (cmd
);
6330 data_shuffling_redo (me
->ds
);
6335 cmd_data_shuffle_undo (GnmCommand
*cmd
,
6336 G_GNUC_UNUSED WorkbookControl
*wbc
)
6338 CmdDataShuffle
*me
= CMD_DATA_SHUFFLE (cmd
);
6340 data_shuffling_redo (me
->ds
);
6345 cmd_data_shuffle_finalize (GObject
*cmd
)
6347 CmdDataShuffle
*me
= CMD_DATA_SHUFFLE (cmd
);
6349 data_shuffling_free (me
->ds
);
6350 gnm_command_finalize (cmd
);
6354 cmd_data_shuffle (WorkbookControl
*wbc
, data_shuffling_t
*sc
, Sheet
*sheet
)
6358 g_return_val_if_fail (GNM_IS_WBC (wbc
), TRUE
);
6359 g_return_val_if_fail (IS_SHEET (sheet
), TRUE
);
6361 me
= g_object_new (CMD_DATA_SHUFFLE_TYPE
, NULL
);
6364 me
->cmd
.sheet
= sheet
;
6366 me
->cmd
.cmd_descriptor
= g_strdup (_("Shuffle Data"));
6368 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
6371 /******************************************************************/
6373 #define CMD_TEXT_TO_COLUMNS_TYPE (cmd_text_to_columns_get_type ())
6374 #define CMD_TEXT_TO_COLUMNS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_TEXT_TO_COLUMNS_TYPE, CmdTextToColumns))
6379 GnmCellRegion
*contents
;
6383 ColRowStateList
*saved_sizes
;
6386 MAKE_GNM_COMMAND (CmdTextToColumns
, cmd_text_to_columns
, NULL
)
6389 cmd_text_to_columns_impl (GnmCommand
*cmd
, WorkbookControl
*wbc
,
6392 CmdTextToColumns
*me
= CMD_TEXT_TO_COLUMNS (cmd
);
6393 GnmCellRegion
*contents
;
6395 g_return_val_if_fail (me
!= NULL
, TRUE
);
6396 g_return_val_if_fail (me
->contents
!= NULL
, TRUE
);
6398 contents
= clipboard_copy_range (me
->dst
.sheet
, &me
->dst
.range
);
6399 if (clipboard_paste_region (me
->contents
, &me
->dst
, GO_CMD_CONTEXT (wbc
))) {
6400 /* There was a problem, avoid leaking */
6401 cellregion_unref (contents
);
6405 cellregion_unref (me
->contents
);
6408 colrow_set_states (me
->dst
.sheet
, FALSE
,
6409 me
->dst
.range
.start
.row
, me
->saved_sizes
);
6410 colrow_state_list_destroy (me
->saved_sizes
);
6411 me
->saved_sizes
= NULL
;
6413 me
->saved_sizes
= colrow_get_states (me
->dst
.sheet
,
6414 FALSE
, me
->dst
.range
.start
.row
, me
->dst
.range
.end
.row
);
6415 rows_height_update (me
->dst
.sheet
, &me
->dst
.range
, FALSE
);
6418 me
->contents
= contents
;
6420 /* Select the newly pasted contents (this queues a redraw) */
6421 select_range (me
->dst
.sheet
, &me
->dst
.range
, wbc
);
6427 cmd_text_to_columns_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
6429 return cmd_text_to_columns_impl (cmd
, wbc
, TRUE
);
6433 cmd_text_to_columns_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
6435 return cmd_text_to_columns_impl (cmd
, wbc
, FALSE
);
6439 cmd_text_to_columns_finalize (GObject
*cmd
)
6441 CmdTextToColumns
*me
= CMD_TEXT_TO_COLUMNS (cmd
);
6443 if (me
->saved_sizes
)
6444 me
->saved_sizes
= colrow_state_list_destroy (me
->saved_sizes
);
6446 cellregion_unref (me
->contents
);
6447 me
->contents
= NULL
;
6449 gnm_command_finalize (cmd
);
6453 cmd_text_to_columns (WorkbookControl
*wbc
,
6454 GnmRange
const *src
, Sheet
*src_sheet
,
6455 GnmRange
const *target
, Sheet
*target_sheet
,
6456 GnmCellRegion
*contents
)
6458 CmdTextToColumns
*me
;
6459 char *src_range_name
, *target_range_name
;
6461 g_return_val_if_fail (contents
!= NULL
, TRUE
);
6463 src_range_name
= undo_range_name (src_sheet
, src
);
6464 target_range_name
= undo_range_name (target_sheet
, target
);
6466 me
= g_object_new (CMD_TEXT_TO_COLUMNS_TYPE
, NULL
);
6468 me
->cmd
.sheet
= (src_sheet
== target_sheet
? src_sheet
: NULL
);
6469 me
->cmd
.size
= 1; /* FIXME? */
6470 me
->cmd
.cmd_descriptor
= g_strdup_printf (_("Text (%s) to Columns (%s)"),
6473 me
->dst
.range
= *target
;
6474 me
->dst
.sheet
= target_sheet
;
6475 me
->dst
.paste_flags
= PASTE_CONTENTS
| PASTE_FORMATS
;
6477 me
->src_sheet
= src_sheet
;
6478 me
->contents
= contents
;
6479 me
->saved_sizes
= NULL
;
6481 g_free (src_range_name
);
6482 g_free (target_range_name
);
6484 /* Check array subdivision & merged regions */
6485 if (sheet_range_splits_region (target_sheet
, &me
->dst
.range
,
6486 NULL
, GO_CMD_CONTEXT (wbc
), me
->cmd
.cmd_descriptor
)) {
6487 g_object_unref (me
);
6491 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
6494 /******************************************************************/
6496 #define CMD_GENERIC_TYPE (cmd_generic_get_type ())
6497 #define CMD_GENERIC(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_GENERIC_TYPE, CmdGeneric))
6501 GOUndo
*undo
, *redo
;
6504 MAKE_GNM_COMMAND (CmdGeneric
, cmd_generic
, NULL
)
6507 cmd_generic_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
6509 CmdGeneric
*me
= CMD_GENERIC (cmd
);
6510 go_undo_undo_with_data (me
->undo
, GO_CMD_CONTEXT (wbc
));
6515 cmd_generic_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
6517 CmdGeneric
*me
= CMD_GENERIC (cmd
);
6518 go_undo_undo_with_data (me
->redo
, GO_CMD_CONTEXT (wbc
));
6523 cmd_generic_finalize (GObject
*cmd
)
6525 CmdGeneric
*me
= CMD_GENERIC (cmd
);
6527 g_object_unref (me
->undo
);
6528 g_object_unref (me
->redo
);
6530 gnm_command_finalize (cmd
);
6534 cmd_generic_with_size (WorkbookControl
*wbc
, const char *txt
,
6536 GOUndo
*undo
, GOUndo
*redo
)
6540 g_return_val_if_fail (GO_IS_UNDO (undo
), TRUE
);
6541 g_return_val_if_fail (GO_IS_UNDO (redo
), TRUE
);
6543 me
= g_object_new (CMD_GENERIC_TYPE
, NULL
);
6545 me
->cmd
.sheet
= wb_control_cur_sheet (wbc
);
6546 me
->cmd
.size
= size
;
6547 me
->cmd
.cmd_descriptor
= g_strdup (txt
);
6552 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
6556 cmd_generic (WorkbookControl
*wbc
, const char *txt
, GOUndo
*undo
, GOUndo
*redo
)
6558 return cmd_generic_with_size (wbc
, txt
, 1, undo
, redo
);
6561 /******************************************************************/
6563 #define CMD_GOAL_SEEK_TYPE (cmd_goal_seek_get_type ())
6564 #define CMD_GOAL_SEEK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_GOAL_SEEK_TYPE, CmdGoalSeek))
6574 MAKE_GNM_COMMAND (CmdGoalSeek
, cmd_goal_seek
, NULL
)
6577 cmd_goal_seek_impl (GnmCell
*cell
, GnmValue
*value
)
6579 sheet_cell_set_value (cell
, value_dup(value
));
6585 cmd_goal_seek_undo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
6587 CmdGoalSeek
*me
= CMD_GOAL_SEEK (cmd
);
6589 return cmd_goal_seek_impl (me
->cell
, me
->ov
);
6593 cmd_goal_seek_redo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
6595 CmdGoalSeek
*me
= CMD_GOAL_SEEK (cmd
);
6597 return cmd_goal_seek_impl (me
->cell
, me
->nv
);
6601 cmd_goal_seek_finalize (GObject
*cmd
)
6603 CmdGoalSeek
*me
= CMD_GOAL_SEEK (cmd
);
6605 value_release (me
->ov
);
6607 value_release (me
->nv
);
6610 gnm_command_finalize (cmd
);
6614 cmd_goal_seek (WorkbookControl
*wbc
, GnmCell
*cell
, GnmValue
*ov
, GnmValue
*nv
)
6619 g_return_val_if_fail (cell
!= NULL
, TRUE
);
6620 g_return_val_if_fail (ov
!= NULL
|| nv
!= NULL
, TRUE
);
6622 me
= g_object_new (CMD_GOAL_SEEK_TYPE
, NULL
);
6624 me
->cmd
.sheet
= cell
->base
.sheet
;
6626 range_init_cellpos (&range
, &cell
->pos
);
6627 me
->cmd
.cmd_descriptor
= g_strdup_printf
6628 (_("Goal Seek (%s)"), undo_range_name (cell
->base
.sheet
, &range
));
6635 me
->ov
= value_dup (cell
->value
);
6637 me
->nv
= value_dup (cell
->value
);
6639 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
6642 /******************************************************************/
6645 #define CMD_FREEZE_PANES_TYPE (cmd_freeze_panes_get_type ())
6646 #define CMD_FREEZE_PANES(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_FREEZE_PANES_TYPE, CmdFreezePanes))
6655 MAKE_GNM_COMMAND (CmdFreezePanes
, cmd_freeze_panes
, NULL
)
6658 cmd_freeze_panes_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
6660 CmdFreezePanes
*me
= CMD_FREEZE_PANES (cmd
);
6666 cmd_freeze_panes_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
6668 CmdFreezePanes
*me
= CMD_FREEZE_PANES (cmd
);
6674 cmd_freeze_panes_finalize (GObject
*cmd
)
6676 CmdFreezePanes
*me
= CMD_FREEZE_PANES (cmd
);
6678 gnm_command_finalize (cmd
);
6683 * @wbc: where to report errors
6684 * @sv: the view to freeze
6688 * Returns TRUE on error
6691 cmd_freeze_panes (WorkbookControl
*wbc
, SheetView
*sv
,
6692 GnmCellPos
const *frozen
, GnmCellPos
const *unfrozen
)
6696 g_return_val_if_fail (name
!= NULL
, TRUE
);
6697 g_return_val_if_fail (pp
!= NULL
, TRUE
);
6698 g_return_val_if_fail (expr
!= NULL
, TRUE
);
6700 me
= g_object_new (CMD_FREEZE_PANES_TYPE
, NULL
);
6703 me
->unfrozen
= expr
;
6704 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
6710 /******************************************************************/
6713 #define CMD_TABULATE_TYPE (cmd_tabulate_get_type ())
6714 #define CMD_TABULATE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_TABULATE_TYPE, CmdTabulate))
6719 GnmTabulateInfo
*data
;
6722 MAKE_GNM_COMMAND (CmdTabulate
, cmd_tabulate
, NULL
)
6725 cmd_tabulate_cmp_f (gconstpointer a
,
6728 guint
const a_val
= GPOINTER_TO_INT (a
);
6729 guint
const b_val
= GPOINTER_TO_INT (b
);
6739 cmd_tabulate_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
6741 CmdTabulate
*me
= CMD_TABULATE (cmd
);
6743 gboolean res
= TRUE
;
6745 me
->sheet_idx
= g_slist_sort (me
->sheet_idx
,
6746 cmd_tabulate_cmp_f
);
6748 for (l
= me
->sheet_idx
; l
!= NULL
; l
= l
->next
) {
6749 int i
= GPOINTER_TO_INT (l
->data
);
6751 workbook_sheet_by_index (wb_control_get_workbook (wbc
),
6753 res
= res
&& command_undo_sheet_delete (new_sheet
);
6759 cmd_tabulate_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
6761 CmdTabulate
*me
= CMD_TABULATE (cmd
);
6763 g_slist_free (me
->sheet_idx
);
6764 me
->sheet_idx
= do_tabulation (wbc
, me
->data
);
6766 return (me
->sheet_idx
== NULL
);
6770 cmd_tabulate_finalize (GObject
*cmd
)
6772 CmdTabulate
*me
= CMD_TABULATE (cmd
);
6774 g_free (me
->data
->cells
);
6775 g_free (me
->data
->minima
);
6776 g_free (me
->data
->maxima
);
6777 g_free (me
->data
->steps
);
6779 gnm_command_finalize (cmd
);
6783 cmd_tabulate (WorkbookControl
*wbc
, gpointer data
)
6787 g_return_val_if_fail (data
!= NULL
, TRUE
);
6789 me
= g_object_new (CMD_TABULATE_TYPE
, NULL
);
6791 me
->cmd
.sheet
= NULL
;
6793 me
->cmd
.cmd_descriptor
=
6794 g_strdup_printf (_("Tabulating Dependencies"));
6796 me
->sheet_idx
= NULL
;
6798 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
6801 /******************************************************************/
6803 #define CMD_SO_GRAPH_CONFIG_TYPE (cmd_so_graph_config_get_type ())
6804 #define CMD_SO_GRAPH_CONFIG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_SO_GRAPH_CONFIG_TYPE, CmdSOGraphConfig))
6809 GogGraph
*new_graph
;
6810 GogGraph
*old_graph
;
6813 MAKE_GNM_COMMAND (CmdSOGraphConfig
, cmd_so_graph_config
, NULL
)
6816 cmd_so_graph_config_redo (GnmCommand
*cmd
,
6817 G_GNUC_UNUSED WorkbookControl
*wbc
)
6819 CmdSOGraphConfig
*me
= CMD_SO_GRAPH_CONFIG (cmd
);
6820 sheet_object_graph_set_gog (me
->so
, me
->new_graph
);
6825 cmd_so_graph_config_undo (GnmCommand
*cmd
,
6826 G_GNUC_UNUSED WorkbookControl
*wbc
)
6828 CmdSOGraphConfig
*me
= CMD_SO_GRAPH_CONFIG (cmd
);
6829 sheet_object_graph_set_gog (me
->so
, me
->old_graph
);
6834 cmd_so_graph_config_finalize (GObject
*cmd
)
6836 CmdSOGraphConfig
*me
= CMD_SO_GRAPH_CONFIG (cmd
);
6838 g_object_unref (me
->so
);
6839 g_object_unref (me
->new_graph
);
6840 g_object_unref (me
->old_graph
);
6842 gnm_command_finalize (cmd
);
6846 cmd_so_graph_config (WorkbookControl
*wbc
, SheetObject
*so
,
6847 GObject
*n_graph
, GObject
*o_graph
)
6849 CmdSOGraphConfig
*me
;
6851 g_return_val_if_fail (GNM_IS_WBC (wbc
), TRUE
);
6852 g_return_val_if_fail (GNM_IS_SO_GRAPH (so
), TRUE
);
6853 g_return_val_if_fail (GOG_IS_GRAPH (n_graph
), TRUE
);
6854 g_return_val_if_fail (GOG_IS_GRAPH (o_graph
), TRUE
);
6856 me
= g_object_new (CMD_SO_GRAPH_CONFIG_TYPE
, NULL
);
6861 me
->new_graph
= GOG_GRAPH (n_graph
);
6862 g_object_ref (me
->new_graph
);
6863 me
->old_graph
= GOG_GRAPH (o_graph
);
6864 g_object_ref (me
->old_graph
);
6866 me
->cmd
.sheet
= sheet_object_get_sheet (so
);
6868 me
->cmd
.cmd_descriptor
= g_strdup (_("Reconfigure Graph"));
6870 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
6873 /******************************************************************/
6875 #define CMD_SO_COMPONENT_CONFIG_TYPE (cmd_so_component_config_get_type ())
6876 #define CMD_SO_COMPONENT_CONFIG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_SO_COMPONENT_CONFIG_TYPE, CmdSOComponentConfig))
6881 GOComponent
*new_obj
;
6882 GOComponent
*old_obj
;
6883 } CmdSOComponentConfig
;
6885 MAKE_GNM_COMMAND (CmdSOComponentConfig
, cmd_so_component_config
, NULL
)
6888 cmd_so_component_config_redo (GnmCommand
*cmd
,
6889 G_GNUC_UNUSED WorkbookControl
*wbc
)
6891 CmdSOComponentConfig
*me
= CMD_SO_COMPONENT_CONFIG (cmd
);
6892 sheet_object_component_set_component (me
->so
, me
->new_obj
);
6897 cmd_so_component_config_undo (GnmCommand
*cmd
,
6898 G_GNUC_UNUSED WorkbookControl
*wbc
)
6900 CmdSOComponentConfig
*me
= CMD_SO_COMPONENT_CONFIG (cmd
);
6901 sheet_object_component_set_component (me
->so
, me
->old_obj
);
6906 cmd_so_component_config_finalize (GObject
*cmd
)
6908 CmdSOComponentConfig
*me
= CMD_SO_COMPONENT_CONFIG (cmd
);
6910 g_object_unref (me
->so
);
6911 g_object_unref (me
->new_obj
);
6912 g_object_unref (me
->old_obj
);
6914 gnm_command_finalize (cmd
);
6918 cmd_so_component_config (WorkbookControl
*wbc
, SheetObject
*so
,
6919 GObject
*n_obj
, GObject
*o_obj
)
6921 CmdSOComponentConfig
*me
;
6923 g_return_val_if_fail (GNM_IS_WBC (wbc
), TRUE
);
6924 g_return_val_if_fail (GNM_IS_SO_COMPONENT (so
), TRUE
);
6925 g_return_val_if_fail (GO_IS_COMPONENT (n_obj
), TRUE
);
6926 g_return_val_if_fail (GO_IS_COMPONENT (o_obj
), TRUE
);
6928 me
= g_object_new (CMD_SO_COMPONENT_CONFIG_TYPE
, NULL
);
6933 me
->new_obj
= GO_COMPONENT (g_object_ref (n_obj
));
6934 me
->old_obj
= GO_COMPONENT (g_object_ref (o_obj
));
6936 me
->cmd
.sheet
= sheet_object_get_sheet (so
);
6938 me
->cmd
.cmd_descriptor
= g_strdup (_("Reconfigure Object"));
6940 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
6943 /******************************************************************/
6945 #define CMD_TOGGLE_RTL_TYPE (cmd_toggle_rtl_get_type ())
6946 #define CMD_TOGGLE_RTL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_TOGGLE_RTL_TYPE, CmdToggleRTL))
6948 typedef GnmCommand CmdToggleRTL
;
6950 MAKE_GNM_COMMAND (CmdToggleRTL
, cmd_toggle_rtl
, NULL
)
6953 cmd_toggle_rtl_redo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
6955 go_object_toggle (cmd
->sheet
, "text-is-rtl");
6960 cmd_toggle_rtl_undo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
6962 return cmd_toggle_rtl_redo (cmd
, wbc
);
6966 cmd_toggle_rtl_finalize (GObject
*cmd
)
6968 gnm_command_finalize (cmd
);
6972 cmd_toggle_rtl (WorkbookControl
*wbc
, Sheet
*sheet
)
6976 g_return_val_if_fail (GNM_IS_WBC (wbc
), TRUE
);
6977 g_return_val_if_fail (IS_SHEET (sheet
), TRUE
);
6979 me
= g_object_new (CMD_TOGGLE_RTL_TYPE
, NULL
);
6982 me
->cmd_descriptor
= g_strdup (sheet
->text_is_rtl
? _("Left to Right") : _("Right to Left"));
6984 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
6987 /******************************************************************/
6989 #define CMD_SO_SET_VALUE_TYPE (cmd_so_set_value_get_type ())
6990 #define CMD_SO_SET_VALUE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_SO_SET_VALUE_TYPE, CmdSOSetValue))
6999 MAKE_GNM_COMMAND (CmdSOSetValue
, cmd_so_set_value
, NULL
)
7002 cmd_so_set_value_redo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
7004 CmdSOSetValue
*me
= CMD_SO_SET_VALUE (cmd
);
7005 Sheet
*sheet
= me
->ref
.sheet
;
7006 GnmCell
*cell
= sheet_cell_fetch (sheet
, me
->ref
.col
, me
->ref
.row
);
7008 sheet_cell_set_value (cell
, value_dup (me
->val
));
7009 sheet_update (sheet
);
7015 cmd_so_set_value_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
7017 CmdSOSetValue
*me
= CMD_SO_SET_VALUE (cmd
);
7019 go_undo_undo_with_data (me
->undo
, GO_CMD_CONTEXT (wbc
));
7025 cmd_so_set_value_finalize (GObject
*cmd
)
7027 CmdSOSetValue
*me
= CMD_SO_SET_VALUE (cmd
);
7029 value_release (me
->val
);
7030 g_object_unref (me
->undo
);
7032 gnm_command_finalize (cmd
);
7036 cmd_so_set_value (WorkbookControl
*wbc
,
7038 const GnmCellRef
*pref
,
7045 g_return_val_if_fail (GNM_IS_WBC (wbc
), TRUE
);
7047 r
.start
.col
= r
.end
.col
= pref
->col
;
7048 r
.start
.row
= r
.end
.row
= pref
->row
;
7050 me
= g_object_new (CMD_SO_SET_VALUE_TYPE
, NULL
);
7051 me
->cmd
.sheet
= sheet
;
7053 me
->cmd
.cmd_descriptor
= g_strdup (text
);
7056 me
->undo
= clipboard_copy_range_undo (pref
->sheet
, &r
);
7058 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
7061 /******************************************************************/
7063 #define CMD_HYPERLINK_TYPE (cmd_hyperlink_get_type ())
7064 #define CMD_HYPERLINK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_HYPERLINK_TYPE, CmdHyperlink))
7069 GnmStyle
*new_style
;
7072 gboolean update_size
;
7076 cmd_hyperlink_repeat (GnmCommand
const *cmd
, WorkbookControl
*wbc
)
7078 CmdHyperlink
const *orig
= (CmdHyperlink
const *) cmd
;
7080 if (orig
->new_style
)
7081 gnm_style_ref (orig
->new_style
);
7083 cmd_selection_hyperlink (wbc
, orig
->new_style
, NULL
,
7084 g_strdup (orig
->opt_content
));
7086 MAKE_GNM_COMMAND (CmdHyperlink
, cmd_hyperlink
, cmd_hyperlink_repeat
)
7089 cmd_hyperlink_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
7091 CmdHyperlink
*me
= CMD_HYPERLINK (cmd
);
7092 Workbook
*wb
= wb_control_get_workbook (wbc
);
7095 go_undo_undo (me
->undo
);
7096 g_clear_object (&me
->undo
);
7099 select_selection (me
->cmd
.sheet
, me
->selection
, wbc
);
7101 WORKBOOK_FOREACH_CONTROL (wb
, view
, ctl
, {
7102 wb_control_menu_state_update (ctl
, MS_COMMENT_LINKS
);
7109 cb_hyperlink_set_text (GnmCellIter
const *iter
, gpointer user
)
7111 CmdHyperlink
*me
= user
;
7112 GnmCell
*cell
= iter
->cell
;
7115 cell
= sheet_cell_fetch (iter
->pp
.sheet
,
7119 /* We skip non-empty cells. */
7120 if (gnm_cell_is_empty (cell
) &&
7121 !gnm_cell_is_nonsingleton_array (cell
)) {
7122 sheet_cell_set_value (cell
, value_new_string (me
->opt_content
));
7123 if (me
->update_size
)
7131 cmd_hyperlink_redo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
7133 CmdHyperlink
*me
= CMD_HYPERLINK (cmd
);
7135 Workbook
*wb
= wb_control_get_workbook (wbc
);
7138 g_return_val_if_fail (me
!= NULL
, TRUE
);
7140 sheet
= me
->cmd
.sheet
;
7142 /* Check for locked cells */
7143 if (cmd_selection_is_locked_effective (sheet
, me
->selection
,
7144 wbc
, _("Changing Hyperlink")))
7147 me
->undo
= clipboard_copy_ranges_undo (sheet
, me
->selection
);
7149 for (l
= me
->selection
; l
; l
= l
->next
) {
7150 GnmRange
const *r
= l
->data
;
7152 if (me
->new_style
) {
7153 gnm_style_ref (me
->new_style
);
7154 sheet_apply_style (sheet
, r
, me
->new_style
);
7155 sheet_flag_style_update_range (sheet
, r
);
7158 if (me
->opt_content
) {
7159 sheet_foreach_cell_in_range (sheet
, CELL_ITER_ALL
, r
,
7160 cb_hyperlink_set_text
,
7164 me
->update_size
= FALSE
;
7166 sheet_redraw_all (sheet
, FALSE
);
7167 sheet_mark_dirty (sheet
);
7169 select_selection (sheet
, me
->selection
, wbc
);
7171 WORKBOOK_FOREACH_CONTROL (wb
, view
, ctl
,
7172 wb_control_menu_state_update (ctl
, MS_COMMENT_LINKS
););
7178 cmd_hyperlink_finalize (GObject
*cmd
)
7180 CmdHyperlink
*me
= CMD_HYPERLINK (cmd
);
7182 g_clear_object (&me
->undo
);
7185 gnm_style_unref (me
->new_style
);
7186 me
->new_style
= NULL
;
7188 range_fragment_free (me
->selection
);
7189 me
->selection
= NULL
;
7191 g_free (me
->opt_content
);
7193 gnm_command_finalize (cmd
);
7197 * cmd_selection_hyperlink:
7198 * @wbc: the workbook control.
7199 * @style: style to apply to the selection
7200 * @opt_translated_name: An optional name to use in place of 'Hyperlink Cells'
7201 * @opt_content: optional content for otherwise empty cells.
7203 * If borders is non NULL, then the GnmBorder references are passed,
7204 * the GnmStyle reference is also passed.
7206 * It absorbs the reference to the style.
7208 * Return value: TRUE if there was a problem
7211 cmd_selection_hyperlink (WorkbookControl
*wbc
,
7213 char const *opt_translated_name
,
7217 SheetView
*sv
= wb_control_cur_sheet_view (wbc
);
7219 me
= g_object_new (CMD_HYPERLINK_TYPE
, NULL
);
7221 me
->selection
= selection_get_ranges (sv
, FALSE
); /* TRUE ? */
7222 me
->new_style
= style
;
7224 me
->cmd
.sheet
= sv_sheet (sv
);
7225 me
->cmd
.size
= 1; /* Updated later. */
7226 me
->update_size
= TRUE
;
7228 me
->opt_content
= opt_content
;
7230 if (opt_translated_name
== NULL
) {
7231 char *names
= undo_range_list_name (me
->cmd
.sheet
, me
->selection
);
7233 me
->cmd
.cmd_descriptor
= g_strdup_printf (_("Changing hyperlink of %s"), names
);
7236 me
->cmd
.cmd_descriptor
= g_strdup (opt_translated_name
);
7239 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
7242 /******************************************************************/
7245 #define CMD_SO_SET_LINKS_TYPE (cmd_so_set_links_get_type ())
7246 #define CMD_SO_SET_LINKS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_SO_SET_LINKS_TYPE, CmdSOSetLink))
7251 GnmExprTop
const *output
;
7252 GnmExprTop
const *content
;
7256 MAKE_GNM_COMMAND (CmdSOSetLink
, cmd_so_set_links
, NULL
)
7259 cmd_so_set_links_redo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
7261 CmdSOSetLink
*me
= CMD_SO_SET_LINKS (cmd
);
7262 GnmExprTop
const *old_output
;
7263 GnmExprTop
const *old_content
;
7264 gboolean old_as_index
;
7266 old_content
= sheet_widget_list_base_get_content_link (me
->so
);
7267 old_output
= sheet_widget_list_base_get_result_link (me
->so
);
7268 old_as_index
= sheet_widget_list_base_result_type_is_index (me
->so
);
7270 sheet_widget_list_base_set_links
7271 (me
->so
, me
->output
, me
->content
);
7272 if (old_as_index
!= me
->as_index
) {
7273 sheet_widget_list_base_set_result_type (me
->so
, me
->as_index
);
7274 me
->as_index
= old_as_index
;
7277 gnm_expr_top_unref (me
->output
);
7279 gnm_expr_top_unref (me
->content
);
7280 me
->output
= old_output
;
7281 me
->content
= old_content
;
7287 cmd_so_set_links_undo (GnmCommand
*cmd
, WorkbookControl
*wbc
)
7289 return cmd_so_set_links_redo (cmd
, wbc
);
7293 cmd_so_set_links_finalize (GObject
*cmd
)
7295 CmdSOSetLink
*me
= CMD_SO_SET_LINKS (cmd
);
7298 gnm_expr_top_unref (me
->output
);
7300 gnm_expr_top_unref (me
->content
);
7301 gnm_command_finalize (cmd
);
7305 cmd_so_set_links (WorkbookControl
*wbc
,
7307 GnmExprTop
const *output
,
7308 GnmExprTop
const *content
,
7313 g_return_val_if_fail (GNM_IS_WBC (wbc
), TRUE
);
7315 me
= g_object_new (CMD_SO_SET_LINKS_TYPE
, NULL
);
7316 me
->cmd
.sheet
= sheet_object_get_sheet (so
);
7318 me
->cmd
.cmd_descriptor
= g_strdup (_("Configure List"));
7320 me
->output
= output
;
7321 me
->content
= content
;
7322 me
->as_index
= as_index
;
7324 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
7327 /******************************************************************/
7331 #define CMD_SO_SET_FRAME_LABEL_TYPE (cmd_so_set_frame_label_get_type ())
7332 #define CMD_SO_SET_FRAME_LABEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_SO_SET_FRAME_LABEL_TYPE, CmdSOSetFrameLabel))
7339 } CmdSOSetFrameLabel
;
7341 MAKE_GNM_COMMAND (CmdSOSetFrameLabel
, cmd_so_set_frame_label
, NULL
)
7344 cmd_so_set_frame_label_redo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
7346 CmdSOSetFrameLabel
*me
= CMD_SO_SET_FRAME_LABEL (cmd
);
7348 sheet_widget_frame_set_label (me
->so
, me
->new_label
);
7354 cmd_so_set_frame_label_undo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
7356 CmdSOSetFrameLabel
*me
= CMD_SO_SET_FRAME_LABEL (cmd
);
7358 sheet_widget_frame_set_label (me
->so
, me
->old_label
);
7364 cmd_so_set_frame_label_finalize (GObject
*cmd
)
7366 CmdSOSetFrameLabel
*me
= CMD_SO_SET_FRAME_LABEL (cmd
);
7368 g_free (me
->old_label
);
7369 me
->old_label
= NULL
;
7371 g_free (me
->new_label
);
7372 me
->new_label
= NULL
;
7374 gnm_command_finalize (cmd
);
7378 cmd_so_set_frame_label (WorkbookControl
*wbc
,
7380 char *old_label
, char *new_label
)
7382 CmdSOSetFrameLabel
*me
;
7384 g_return_val_if_fail (GNM_IS_WBC (wbc
), TRUE
);
7386 me
= g_object_new (CMD_SO_SET_FRAME_LABEL_TYPE
, NULL
);
7387 me
->cmd
.sheet
= sheet_object_get_sheet (so
);
7389 me
->cmd
.cmd_descriptor
= g_strdup (_("Set Frame Label"));
7391 me
->old_label
= old_label
;
7392 me
->new_label
= new_label
;
7394 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
7397 /******************************************************************/
7398 #define CMD_SO_SET_BUTTON_TYPE (cmd_so_set_button_get_type ())
7399 #define CMD_SO_SET_BUTTON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_SO_SET_BUTTON_TYPE, CmdSOSetButton))
7404 GnmExprTop
const *new_link
;
7405 GnmExprTop
const *old_link
;
7410 MAKE_GNM_COMMAND (CmdSOSetButton
, cmd_so_set_button
, NULL
)
7413 cmd_so_set_button_redo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
7415 CmdSOSetButton
*me
= CMD_SO_SET_BUTTON (cmd
);
7417 sheet_widget_button_set_link (me
->so
, me
->new_link
);
7418 sheet_widget_button_set_label (me
->so
, me
->new_label
);
7424 cmd_so_set_button_undo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
7426 CmdSOSetButton
*me
= CMD_SO_SET_BUTTON (cmd
);
7428 sheet_widget_button_set_link (me
->so
, me
->old_link
);
7429 sheet_widget_button_set_label (me
->so
, me
->old_label
);
7435 cmd_so_set_button_finalize (GObject
*cmd
)
7437 CmdSOSetButton
*me
= CMD_SO_SET_BUTTON (cmd
);
7440 gnm_expr_top_unref (me
->new_link
);
7442 gnm_expr_top_unref (me
->old_link
);
7443 g_free (me
->old_label
);
7444 g_free (me
->new_label
);
7445 gnm_command_finalize (cmd
);
7449 cmd_so_set_button (WorkbookControl
*wbc
,
7450 SheetObject
*so
, GnmExprTop
const *lnk
,
7451 char *old_label
, char *new_label
)
7455 g_return_val_if_fail (GNM_IS_WBC (wbc
), TRUE
);
7457 me
= g_object_new (CMD_SO_SET_BUTTON_TYPE
, NULL
);
7458 me
->cmd
.sheet
= sheet_object_get_sheet (so
);
7460 me
->cmd
.cmd_descriptor
= g_strdup (_("Configure Button"));
7463 me
->old_label
= old_label
;
7464 me
->new_label
= new_label
;
7466 me
->old_link
= sheet_widget_button_get_link (so
);
7468 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
7471 /******************************************************************/
7472 #define CMD_SO_SET_RADIO_BUTTON_TYPE (cmd_so_set_radio_button_get_type ())
7473 #define CMD_SO_SET_RADIO_BUTTON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_SO_SET_RADIO_BUTTON_TYPE, CmdSOSetRadioButton))
7478 GnmExprTop
const *new_link
;
7479 GnmExprTop
const *old_link
;
7482 GnmValue
*old_value
;
7483 GnmValue
*new_value
;
7484 } CmdSOSetRadioButton
;
7486 MAKE_GNM_COMMAND (CmdSOSetRadioButton
, cmd_so_set_radio_button
, NULL
)
7489 cmd_so_set_radio_button_redo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
7491 CmdSOSetRadioButton
*me
= CMD_SO_SET_RADIO_BUTTON (cmd
);
7493 sheet_widget_radio_button_set_link (me
->so
, me
->new_link
);
7494 sheet_widget_radio_button_set_label (me
->so
, me
->new_label
);
7495 sheet_widget_radio_button_set_value (me
->so
, me
->new_value
);
7501 cmd_so_set_radio_button_undo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
7503 CmdSOSetRadioButton
*me
= CMD_SO_SET_RADIO_BUTTON (cmd
);
7505 sheet_widget_radio_button_set_link (me
->so
, me
->old_link
);
7506 sheet_widget_radio_button_set_label (me
->so
, me
->old_label
);
7507 sheet_widget_radio_button_set_value (me
->so
, me
->old_value
);
7513 cmd_so_set_radio_button_finalize (GObject
*cmd
)
7515 CmdSOSetRadioButton
*me
= CMD_SO_SET_RADIO_BUTTON (cmd
);
7518 gnm_expr_top_unref (me
->new_link
);
7520 gnm_expr_top_unref (me
->old_link
);
7521 g_free (me
->old_label
);
7522 g_free (me
->new_label
);
7523 value_release (me
->old_value
);
7524 value_release (me
->new_value
);
7525 gnm_command_finalize (cmd
);
7529 cmd_so_set_radio_button (WorkbookControl
*wbc
,
7530 SheetObject
*so
, GnmExprTop
const *lnk
,
7531 char *old_label
, char *new_label
,
7532 GnmValue
*old_value
, GnmValue
*new_value
)
7534 CmdSOSetRadioButton
*me
;
7536 g_return_val_if_fail (GNM_IS_WBC (wbc
), TRUE
);
7538 me
= g_object_new (CMD_SO_SET_RADIO_BUTTON_TYPE
, NULL
);
7539 me
->cmd
.sheet
= sheet_object_get_sheet (so
);
7541 me
->cmd
.cmd_descriptor
= g_strdup (_("Configure Radio Button"));
7544 me
->old_label
= old_label
;
7545 me
->new_label
= new_label
;
7546 me
->old_value
= old_value
;
7547 me
->new_value
= new_value
;
7549 me
->old_link
= sheet_widget_radio_button_get_link (so
);
7551 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
7554 /******************************************************************/
7555 #define CMD_SO_SET_CHECKBOX_TYPE (cmd_so_set_checkbox_get_type ())
7556 #define CMD_SO_SET_CHECKBOX(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_SO_SET_CHECKBOX_TYPE, CmdSOSetCheckbox))
7561 GnmExprTop
const *new_link
;
7562 GnmExprTop
const *old_link
;
7567 MAKE_GNM_COMMAND (CmdSOSetCheckbox
, cmd_so_set_checkbox
, NULL
)
7570 cmd_so_set_checkbox_redo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
7572 CmdSOSetCheckbox
*me
= CMD_SO_SET_CHECKBOX (cmd
);
7574 sheet_widget_checkbox_set_link (me
->so
, me
->new_link
);
7575 sheet_widget_checkbox_set_label (me
->so
, me
->new_label
);
7581 cmd_so_set_checkbox_undo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
7583 CmdSOSetCheckbox
*me
= CMD_SO_SET_CHECKBOX (cmd
);
7585 sheet_widget_checkbox_set_link (me
->so
, me
->old_link
);
7586 sheet_widget_checkbox_set_label (me
->so
, me
->old_label
);
7592 cmd_so_set_checkbox_finalize (GObject
*cmd
)
7594 CmdSOSetCheckbox
*me
= CMD_SO_SET_CHECKBOX (cmd
);
7597 gnm_expr_top_unref (me
->new_link
);
7599 gnm_expr_top_unref (me
->old_link
);
7600 g_free (me
->old_label
);
7601 g_free (me
->new_label
);
7602 gnm_command_finalize (cmd
);
7606 cmd_so_set_checkbox (WorkbookControl
*wbc
,
7607 SheetObject
*so
, GnmExprTop
const *lnk
,
7608 char *old_label
, char *new_label
)
7610 CmdSOSetCheckbox
*me
;
7612 g_return_val_if_fail (GNM_IS_WBC (wbc
), TRUE
);
7614 me
= g_object_new (CMD_SO_SET_CHECKBOX_TYPE
, NULL
);
7615 me
->cmd
.sheet
= sheet_object_get_sheet (so
);
7617 me
->cmd
.cmd_descriptor
= g_strdup (_("Configure Checkbox"));
7620 me
->old_label
= old_label
;
7621 me
->new_label
= new_label
;
7623 me
->old_link
= sheet_widget_checkbox_get_link (so
);
7625 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
7628 /******************************************************************/
7630 #define CMD_SO_SET_ADJUSTMENT_TYPE (cmd_so_set_adjustment_get_type ())
7631 #define CMD_SO_SET_ADJUSTMENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CMD_SO_SET_ADJUSTMENT_TYPE, CmdSOSetAdjustment))
7636 GnmExprTop
const *new_link
;
7637 GnmExprTop
const *old_link
;
7642 gboolean old_horizontal
;
7643 } CmdSOSetAdjustment
;
7645 MAKE_GNM_COMMAND (CmdSOSetAdjustment
, cmd_so_set_adjustment
, NULL
)
7648 cmd_so_set_adjustment_adj (CmdSOSetAdjustment
*me
)
7650 GtkAdjustment
*adj
= sheet_widget_adjustment_get_adjustment (me
->so
);
7652 double old_lower
= gtk_adjustment_get_lower (adj
);
7653 double old_upper
= gtk_adjustment_get_upper (adj
);
7654 double old_step
= gtk_adjustment_get_step_increment (adj
);
7655 double old_page
= gtk_adjustment_get_page_increment (adj
);
7656 gboolean old_horizontal
;
7657 g_object_get (G_OBJECT (me
->so
), "horizontal", &old_horizontal
, NULL
);
7659 gtk_adjustment_configure (adj
,
7660 gtk_adjustment_get_value (adj
),
7665 gtk_adjustment_get_page_size (adj
));
7666 g_object_set (G_OBJECT (me
->so
), "horizontal", me
->old_horizontal
, NULL
);
7668 me
->old_lower
= old_lower
;
7669 me
->old_upper
= old_upper
;
7670 me
->old_step
= old_step
;
7671 me
->old_page
= old_page
;
7672 me
->old_horizontal
= old_horizontal
;
7676 cmd_so_set_adjustment_redo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
7678 CmdSOSetAdjustment
*me
= CMD_SO_SET_ADJUSTMENT (cmd
);
7680 sheet_widget_adjustment_set_link (me
->so
, me
->new_link
);
7681 cmd_so_set_adjustment_adj (me
);
7686 cmd_so_set_adjustment_undo (GnmCommand
*cmd
, G_GNUC_UNUSED WorkbookControl
*wbc
)
7688 CmdSOSetAdjustment
*me
= CMD_SO_SET_ADJUSTMENT (cmd
);
7690 sheet_widget_adjustment_set_link (me
->so
, me
->old_link
);
7691 cmd_so_set_adjustment_adj (me
);
7697 cmd_so_set_adjustment_finalize (GObject
*cmd
)
7699 CmdSOSetAdjustment
*me
= CMD_SO_SET_ADJUSTMENT (cmd
);
7702 gnm_expr_top_unref (me
->new_link
);
7704 gnm_expr_top_unref (me
->old_link
);
7705 gnm_command_finalize (cmd
);
7709 cmd_so_set_adjustment (WorkbookControl
*wbc
,
7710 SheetObject
*so
, GnmExprTop
const *lnk
,
7711 gboolean horizontal
,
7712 int lower
, int upper
,
7714 char const *undo_label
)
7716 CmdSOSetAdjustment
*me
;
7718 g_return_val_if_fail (GNM_IS_WBC (wbc
), TRUE
);
7720 me
= g_object_new (CMD_SO_SET_ADJUSTMENT_TYPE
, NULL
);
7721 me
->cmd
.sheet
= sheet_object_get_sheet (so
);
7723 me
->cmd
.cmd_descriptor
= g_strdup ((undo_label
== NULL
) ?
7724 _("Configure Adjustment") : _(undo_label
));
7727 me
->old_lower
= lower
;
7728 me
->old_upper
= upper
;
7729 me
->old_step
= step
;
7730 me
->old_page
= page
;
7731 me
->old_horizontal
= horizontal
;
7733 me
->old_link
= sheet_widget_adjustment_get_link (so
);
7735 return gnm_command_push_undo (wbc
, G_OBJECT (me
));
7738 /******************************************************************/
7741 cmd_autofilter_add_remove (WorkbookControl
*wbc
)
7743 SheetView
*sv
= wb_control_cur_sheet_view (wbc
);
7744 GnmFilter
*f
= gnm_sheet_view_editpos_in_filter (sv
);
7745 gboolean add
= (f
== NULL
);
7746 char *descr
= NULL
, *name
= NULL
;
7747 GOUndo
*undo
= NULL
;
7748 GOUndo
*redo
= NULL
;
7754 GnmRange
const *src
= selection_first_range (sv
,
7755 GO_CMD_CONTEXT (wbc
), _("Add Filter"));
7756 GnmFilter
*f_old
= NULL
;
7761 f_old
= gnm_sheet_filter_intersect_rows
7762 (sv
->sheet
, src
->start
.row
, src
->end
.row
);
7764 if (f_old
!= NULL
) {
7765 GnmRange
*r
= gnm_sheet_filter_can_be_extended
7766 (sv
->sheet
, f_old
, src
);
7769 name
= undo_range_name (sv
->sheet
, &(f_old
->r
));
7770 error
= g_strdup_printf
7771 (_("Auto Filter blocked by %s"),
7774 go_cmd_context_error_invalid
7775 (GO_CMD_CONTEXT (wbc
),
7776 _("AutoFilter"), error
);
7780 /* extending existing filter. */
7781 undo
= go_undo_binary_new
7782 (gnm_filter_ref (f_old
), sv
->sheet
,
7783 (GOUndoBinaryFunc
) gnm_filter_attach
,
7784 (GFreeFunc
) gnm_filter_unref
,
7786 redo
= go_undo_unary_new
7787 (gnm_filter_ref (f_old
),
7788 (GOUndoUnaryFunc
) gnm_filter_remove
,
7789 (GFreeFunc
) gnm_filter_unref
);
7790 gnm_filter_remove (f_old
);
7794 /* if only one row is selected
7795 * assume that the user wants to
7796 * filter the region below this row. */
7798 if (src
->start
.row
== src
->end
.row
)
7799 gnm_sheet_guess_region (sv
->sheet
, ®ion
);
7800 if (region
.start
.row
== region
.end
.row
) {
7801 go_cmd_context_error_invalid
7802 (GO_CMD_CONTEXT (wbc
),
7804 _("Requires more than 1 row"));
7808 f
= gnm_filter_new (sv
->sheet
, ®ion
);
7810 go_cmd_context_error_invalid
7811 (GO_CMD_CONTEXT (wbc
),
7813 _("Unable to create Autofilter"));
7815 gnm_filter_attach (f_old
, sv
->sheet
);
7819 gnm_filter_remove (f
);
7821 gnm_filter_attach (f_old
, sv
->sheet
);
7823 redo
= go_undo_combine (go_undo_binary_new
7824 (gnm_filter_ref (f
), sv
->sheet
,
7825 (GOUndoBinaryFunc
) gnm_filter_attach
,
7826 (GFreeFunc
) gnm_filter_unref
,
7828 undo
= go_undo_combine (undo
,
7831 (GOUndoUnaryFunc
) gnm_filter_remove
,
7832 (GFreeFunc
) gnm_filter_unref
));
7834 name
= undo_range_name (sv
->sheet
, &(f
->r
));
7835 descr
= g_strdup_printf
7836 ((f_old
== NULL
) ? _("Add Autofilter to %s")
7837 : _("Extend Autofilter to %s"),
7840 undo
= go_undo_binary_new
7841 (gnm_filter_ref (f
), sv
->sheet
,
7842 (GOUndoBinaryFunc
) gnm_filter_attach
,
7843 (GFreeFunc
) gnm_filter_unref
,
7845 redo
= go_undo_unary_new
7846 (gnm_filter_ref (f
),
7847 (GOUndoUnaryFunc
) gnm_filter_remove
,
7848 (GFreeFunc
) gnm_filter_unref
);
7849 name
= undo_range_name (sv
->sheet
, &(f
->r
));
7850 descr
= g_strdup_printf (_("Remove Autofilter from %s"),
7853 result
= cmd_generic (wbc
, descr
, undo
, redo
);
7861 /******************************************************************/
7863 gboolean
cmd_autofilter_set_condition (WorkbookControl
*wbc
,
7864 GnmFilter
*filter
, unsigned i
,
7865 GnmFilterCondition
*cond
)
7867 char *descr
= NULL
, *name
= NULL
;
7868 GOUndo
*undo
= NULL
;
7869 GOUndo
*redo
= NULL
;
7872 undo
= gnm_undo_filter_set_condition_new (filter
, i
,
7874 g_return_val_if_fail (undo
!= NULL
, TRUE
);
7875 redo
= gnm_undo_filter_set_condition_new (filter
, i
,
7877 g_return_val_if_fail (redo
!= NULL
, TRUE
);
7879 name
= undo_range_name (filter
->sheet
, &(filter
->r
));
7880 descr
= g_strdup_printf (_("Change filter condition for %s"),
7883 result
= cmd_generic (wbc
, descr
, undo
, redo
);
7891 /******************************************************************/
7894 cmd_page_breaks_set_breaks (Sheet
*sheet
,
7895 GnmPageBreaks
const *breaks
)
7897 print_info_set_breaks (sheet
->print_info
, gnm_page_breaks_dup (breaks
));
7899 SHEET_FOREACH_CONTROL (sheet
, sv
, sc
, wb_control_menu_state_update (sc_wbc (sc
), MS_PAGE_BREAKS
););
7903 cmd_page_breaks_clear (WorkbookControl
*wbc
, Sheet
*sheet
)
7905 GOUndo
*undo
= NULL
;
7906 GOUndo
*redo
= NULL
;
7908 g_return_val_if_fail (GNM_IS_WBC (wbc
), TRUE
);
7909 g_return_val_if_fail (sheet
!= NULL
, TRUE
);
7911 if (sheet
->print_info
->page_breaks
.v
!= NULL
) {
7912 redo
= go_undo_binary_new
7914 gnm_page_breaks_new (TRUE
),
7915 (GOUndoBinaryFunc
) cmd_page_breaks_set_breaks
,
7917 (GFreeFunc
) gnm_page_breaks_free
);
7918 undo
= go_undo_binary_new
7921 (sheet
->print_info
->page_breaks
.v
),
7922 (GOUndoBinaryFunc
) cmd_page_breaks_set_breaks
,
7924 (GFreeFunc
) gnm_page_breaks_free
);
7927 if (sheet
->print_info
->page_breaks
.h
!= NULL
) {
7928 redo
= go_undo_combine
7932 gnm_page_breaks_new (FALSE
),
7933 (GOUndoBinaryFunc
) cmd_page_breaks_set_breaks
,
7935 (GFreeFunc
) gnm_page_breaks_free
));
7937 undo
= go_undo_combine
7942 (sheet
->print_info
->page_breaks
.h
),
7943 (GOUndoBinaryFunc
) cmd_page_breaks_set_breaks
,
7945 (GFreeFunc
) gnm_page_breaks_free
));
7949 return cmd_generic (wbc
, _("Clear All Page Breaks"), undo
, redo
);
7955 cmd_page_break_toggle (WorkbookControl
*wbc
, Sheet
*sheet
, gboolean is_vert
)
7957 SheetView
const *sv
= wb_control_cur_sheet_view (wbc
);
7958 gint col
= sv
->edit_pos
.col
;
7959 gint row
= sv
->edit_pos
.row
;
7960 int rc
= is_vert
? col
: row
;
7961 GnmPageBreaks
*old
, *new, *target
;
7962 GnmPageBreakType type
;
7967 target
= is_vert
? sheet
->print_info
->page_breaks
.v
7968 : sheet
->print_info
->page_breaks
.h
;
7970 old
= (target
== NULL
) ? gnm_page_breaks_new (is_vert
)
7971 : gnm_page_breaks_dup (target
);
7972 new = gnm_page_breaks_dup (old
);
7974 if (gnm_page_breaks_get_break (new, rc
) != GNM_PAGE_BREAK_MANUAL
) {
7975 type
= GNM_PAGE_BREAK_MANUAL
;
7976 label
= is_vert
? _("Remove Column Page Break") : _("Remove Row Page Break");
7978 type
= GNM_PAGE_BREAK_NONE
;
7979 label
= is_vert
? _("Add Column Page Break") : _("Add Row Page Break");
7982 gnm_page_breaks_set_break (new, rc
, type
);
7984 redo
= go_undo_binary_new
7986 (GOUndoBinaryFunc
) cmd_page_breaks_set_breaks
,
7988 (GFreeFunc
) gnm_page_breaks_free
);
7989 undo
= go_undo_binary_new
7991 (GOUndoBinaryFunc
) cmd_page_breaks_set_breaks
,
7993 (GFreeFunc
) gnm_page_breaks_free
);
7995 return cmd_generic (wbc
, label
, undo
, redo
);
7998 /******************************************************************/