1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * workbook-control.c: The base class for the displaying a workbook.
6 * Copyright (C) 2000-2002 Jody Goldberg (jody@gnome.org)
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) version 3.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
24 #include <gnumeric-config.h>
27 #include "workbook-control-priv.h"
29 #include "application.h"
30 #include "workbook-view.h"
31 #include "workbook-priv.h"
33 #include "sheet-view.h"
34 #include "sheet-utils.h"
35 #include "selection.h"
39 #include "expr-name.h"
41 #include "command-context.h"
42 #include <goffice/goffice.h>
43 #include <gsf/gsf-impl-utils.h>
50 #define WBC_CLASS(o) GNM_WBC_CLASS (G_OBJECT_GET_CLASS (o))
51 #define WBC_VIRTUAL_FULL(func, handle, arglist, call) \
52 void wb_control_ ## func arglist \
54 WorkbookControlClass *wbc_class = WBC_CLASS (wbc); \
56 g_return_if_fail (wbc_class != NULL); \
58 if (wbc_class != NULL && wbc_class->handle != NULL) \
59 wbc_class->handle call; \
61 #define WBC_VIRTUAL(func, arglist, call) WBC_VIRTUAL_FULL(func, func, arglist, call)
64 * workbook_control_new_wrapper:
65 * @wbc: #WorkbookControl
68 * @extra: (allow-none):
70 * Returns: (transfer full): the newly allocated #WorkbookControl.
73 workbook_control_new_wrapper (WorkbookControl
*wbc
, WorkbookView
*wbv
, Workbook
*wb
,
76 WorkbookControlClass
*wbc_class
= WBC_CLASS (wbc
);
78 g_return_val_if_fail (wbc_class
!= NULL
, NULL
);
80 if (wbc_class
!= NULL
&& wbc_class
->control_new
!= NULL
)
81 return wbc_class
->control_new (wbc
, wbv
, wb
, extra
);
85 WBC_VIRTUAL (style_feedback
,
86 (WorkbookControl
*wbc
, GnmStyle
const *changes
), (wbc
, changes
))
87 WBC_VIRTUAL (edit_line_set
,
88 (WorkbookControl
*wbc
, char const *text
), (wbc
, text
))
89 WBC_VIRTUAL (selection_descr_set
,
90 (WorkbookControl
*wbc
, char const *text
), (wbc
, text
))
92 WBC_VIRTUAL_FULL (sheet_remove
, sheet
.remove
,
93 (WorkbookControl
*wbc
, Sheet
*sheet
), (wbc
, sheet
))
94 WBC_VIRTUAL_FULL (sheet_focus
, sheet
.focus
,
95 (WorkbookControl
*wbc
, Sheet
*sheet
), (wbc
, sheet
))
96 WBC_VIRTUAL_FULL (sheet_remove_all
, sheet
.remove_all
,
97 (WorkbookControl
*wbc
), (wbc
))
99 WBC_VIRTUAL_FULL (undo_redo_truncate
, undo_redo
.truncate
,
100 (WorkbookControl
*wbc
, int n
, gboolean is_undo
), (wbc
, n
, is_undo
))
101 WBC_VIRTUAL_FULL (undo_redo_pop
, undo_redo
.pop
,
102 (WorkbookControl
*wbc
, gboolean is_undo
), (wbc
, is_undo
))
103 WBC_VIRTUAL_FULL (undo_redo_push
, undo_redo
.push
,
104 (WorkbookControl
*wbc
, gboolean is_undo
, char const *text
, gpointer key
),
105 (wbc
, is_undo
, text
, key
))
106 WBC_VIRTUAL_FULL (undo_redo_labels
, undo_redo
.labels
,
107 (WorkbookControl
*wbc
, char const *undo
, char const *redo
),
110 WBC_VIRTUAL_FULL (menu_state_update
, menu_state
.update
,
111 (WorkbookControl
*wbc
, int flags
),
114 WBC_VIRTUAL (paste_from_selection
,
115 (WorkbookControl
*wbc
, GnmPasteTarget
const *pt
), (wbc
, pt
))
116 WBC_VIRTUAL (update_action_sensitivity
,
117 (WorkbookControl
*wbc
), (wbc
))
120 wb_control_sheet_add (WorkbookControl
*wbc
, SheetView
*sv
)
122 WorkbookControlClass
*wbc_class
;
124 g_return_if_fail (GNM_IS_WBC (wbc
));
126 wbc_class
= WBC_CLASS (wbc
);
127 if (wbc_class
!= NULL
&& wbc_class
->sheet
.add
!= NULL
) {
128 Sheet
*new_sheet
= sv_sheet (sv
);
130 wbc_class
->sheet
.add (wbc
, sv
);
132 /* If this is the current sheet init the display */
133 if (new_sheet
== wb_control_cur_sheet (wbc
)) {
134 WorkbookView
*wbv
= wb_control_view (wbc
);
135 wb_control_sheet_focus (wbc
, new_sheet
);
136 wb_view_selection_desc (wbv
, TRUE
, wbc
);
137 wb_view_edit_line_set (wbv
, wbc
);
138 wb_control_style_feedback (wbc
, NULL
);
139 wb_control_menu_state_update (wbc
, MS_ALL
);
140 wb_control_update_action_sensitivity (wbc
);
146 wb_control_claim_selection (WorkbookControl
*wbc
)
148 WorkbookControlClass
*wbc_class
;
150 g_return_val_if_fail (GNM_IS_WBC (wbc
), FALSE
);
152 wbc_class
= WBC_CLASS (wbc
);
153 if (wbc_class
!= NULL
&& wbc_class
->claim_selection
!= NULL
)
154 return wbc_class
->claim_selection (wbc
);
155 return TRUE
; /* no handler means we always get the selection */
159 * wb_control_validation_msg:
160 * 1 : ignore invalid and accept result
161 * 0 : discard invalid and finish editing
162 * -1 : continue editing
165 wb_control_validation_msg (WorkbookControl
*wbc
, ValidationStyle v
,
166 char const *title
, char const *msg
)
168 WorkbookControlClass
*wbc_class
;
170 g_return_val_if_fail (GNM_IS_WBC (wbc
), 1);
172 wbc_class
= WBC_CLASS (wbc
);
173 if (wbc_class
!= NULL
&& wbc_class
->validation_msg
!= NULL
)
174 return wbc_class
->validation_msg (wbc
, v
, title
, msg
);
175 return 1; /* no handler, always accept */
180 * @wbc: #WorkbookControl
182 * Returns: (transfer none): the workbook view.
185 wb_control_view (WorkbookControl
const *wbc
)
187 g_return_val_if_fail (GNM_IS_WBC (wbc
), NULL
);
192 * wb_control_get_doc:
193 * @wbc: #WorkbookControl
195 * Returns: (transfer none): the workbook set as a #GODoc.
198 wb_control_get_doc (WorkbookControl
const *wbc
)
200 return GO_DOC (wb_control_get_workbook (wbc
));
204 * wb_control_get_workbook:
205 * @wbc: #WorkbookControl
207 * Returns: (transfer none): the workbook.
210 wb_control_get_workbook (WorkbookControl
const *wbc
)
212 g_return_val_if_fail (GNM_IS_WBC (wbc
), NULL
);
213 return wbc
->wb_view
? wb_view_get_workbook (wbc
->wb_view
) : NULL
;
217 * wb_control_cur_sheet:
218 * @wbc: #WorkbookControl
220 * Returns: (transfer none): the current sheet.
223 wb_control_cur_sheet (WorkbookControl
const *wbc
)
225 g_return_val_if_fail (GNM_IS_WBC (wbc
), NULL
);
226 return wb_view_cur_sheet (wbc
->wb_view
);
230 * wb_control_cur_sheet_view:
231 * @wbc: #WorkbookControl
233 * Returns: (transfer none): the current sheet view.
236 wb_control_cur_sheet_view (WorkbookControl
const *wbc
)
238 g_return_val_if_fail (GNM_IS_WBC (wbc
), NULL
);
239 return wb_view_cur_sheet_view (wbc
->wb_view
);
243 wb_create_name (WorkbookControl
*wbc
, char const *text
, GnmParsePos
*pp
)
247 GnmExpr
const *target_range
;
249 r
= selection_first_range (wb_control_cur_sheet_view (wbc
),
250 GO_CMD_CONTEXT (wbc
), _("Define Name"));
252 a
.sheet
= b
.sheet
= wb_control_cur_sheet (wbc
);
253 a
.col
= r
->start
.col
;
254 a
.row
= r
->start
.row
;
257 a
.col_relative
= a
.row_relative
= b
.col_relative
= b
.row_relative
= FALSE
;
258 pp
->sheet
= NULL
; /* make it a global name */
259 if (gnm_cellref_equal (&a
, &b
))
260 target_range
= gnm_expr_new_cellref (&a
);
262 target_range
= gnm_expr_new_constant (
263 value_new_cellrange_unsafe (&a
, &b
));
264 cmd_define_name (wbc
, text
, pp
, gnm_expr_top_new (target_range
), NULL
);
269 * Select the given range and make the it visible.
272 wb_control_jump (WorkbookControl
*wbc
, Sheet
*sheet
, const GnmRangeRef
*r
)
280 if (!sheet_is_visible (sheet
)) {
281 go_cmd_context_error_invalid
282 (GO_CMD_CONTEXT (wbc
),
283 _("Cannot jump to an invisible sheet"),
284 sheet
->name_unquoted
);
288 sv
= sheet_get_view (sheet
, wb_control_view (wbc
));
292 sv_selection_set (sv
, &tmp
, r
->a
.col
, r
->a
.row
, r
->b
.col
, r
->b
.row
);
293 gnm_sheet_view_make_cell_visible (sv
, r
->b
.col
, r
->b
.row
, FALSE
);
294 gnm_sheet_view_make_cell_visible (sv
, r
->a
.col
, r
->a
.row
, FALSE
);
295 gnm_sheet_view_update (sv
);
296 if (wb_control_cur_sheet (wbc
) != sheet
)
297 wb_view_sheet_focus (wbc
->wb_view
, sheet
);
303 * This is called when something is entered in the location entry.
304 * We either go there (if the text refers to a cell by address or
305 * name), or we try to define a name for the selection.
308 wb_control_parse_and_jump (WorkbookControl
*wbc
, char const *text
)
310 Sheet
*sheet
= wb_control_cur_sheet (wbc
);
317 if (text
== NULL
|| *text
== '\0')
320 sv
= wb_control_cur_sheet_view (wbc
);
321 parse_pos_init_editpos (&pp
, sv
);
322 target
= value_new_cellrange_parsepos_str (&pp
, text
,
323 GNM_EXPR_PARSE_DEFAULT
);
324 if (target
== NULL
) {
325 GnmExprTop
const *texpr
;
327 texpr
= gnm_expr_parse_str
328 (text
, &pp
, GNM_EXPR_PARSE_DEFAULT
,
329 gnm_conventions_xls_r1c1
, NULL
);
331 target
= gnm_expr_top_get_range (texpr
);
332 gnm_expr_top_unref (texpr
);
335 if (target
== NULL
) {
336 GnmExprTop
const *texpr
;
338 texpr
= gnm_expr_parse_str
339 (text
, &pp
, GNM_EXPR_PARSE_DEFAULT
,
340 gnm_conventions_default
, NULL
);
342 target
= gnm_expr_top_get_range (texpr
);
343 gnm_expr_top_unref (texpr
);
347 if (target
== NULL
) {
348 /* Not an address; is it a name? */
350 GnmNamedExpr
*nexpr
= expr_name_lookup (
351 parse_pos_init_sheet (&pp
, sheet
), text
);
353 /* If no name, or just a placeholder exists create a name */
354 if (nexpr
== NULL
|| expr_name_is_placeholder (nexpr
)) {
355 wb_create_name (wbc
, text
, &pp
);
358 target
= gnm_expr_top_get_range (nexpr
->texpr
);
359 if (target
== NULL
) {
360 go_cmd_context_error_invalid (GO_CMD_CONTEXT (wbc
),
367 eval_pos_init_editpos (&ep
, sv
);
368 gnm_cellref_make_abs (&range
.a
, &target
->v_range
.cell
.a
, &ep
);
369 gnm_cellref_make_abs (&range
.b
, &target
->v_range
.cell
.b
, &ep
);
370 value_release (target
);
372 return wb_control_jump (wbc
, sheet
, &range
);
376 wb_control_navigate_to_cell (WorkbookControl
*wbc
, wb_control_navigator_t to
)
378 Sheet
*sheet
= wb_control_cur_sheet (wbc
);
379 SheetView
*sv
= wb_control_cur_sheet_view (wbc
);
381 GnmRange
const *first
= selection_first_range (sv
, NULL
, NULL
);
382 GnmRangeRef rangeref
;
385 gnm_sheet_guess_data_range (sheet
, ®ion
);
386 range_ensure_sanity (®ion
, sheet
);
390 region
.end
.row
= region
.start
.row
;
391 region
.start
.col
= first
->start
.col
;
392 region
.end
.col
= first
->end
.col
;
394 case navigator_bottom
:
395 region
.start
.row
= region
.end
.row
;
396 region
.start
.col
= first
->start
.col
;
397 region
.end
.col
= first
->end
.col
;
399 case navigator_first
:
400 region
.end
.col
= region
.start
.col
;
401 region
.start
.row
= first
->start
.row
;
402 region
.end
.row
= first
->end
.row
;
405 region
.start
.col
= region
.end
.col
;
406 region
.start
.row
= first
->start
.row
;
407 region
.end
.row
= first
->end
.row
;
412 gnm_cellref_init (&rangeref
.a
, sheet
,
413 region
.start
.col
, region
.start
.row
, FALSE
);
414 gnm_cellref_init (&rangeref
.b
, sheet
,
415 region
.end
.col
, region
.end
.row
, FALSE
);
417 wb_control_jump (wbc
, sheet
, &rangeref
);
426 cb_wbc_clipboard_modified (G_GNUC_UNUSED GnmApp
*app
, WorkbookControl
*wbc
)
428 wb_control_menu_state_update (wbc
, MS_PASTE_SPECIAL
);
431 /*****************************************************************************/
434 wbc_get_property (GObject
*object
,
439 WorkbookControl
*wbc
= (WorkbookControl
*)object
;
441 switch (property_id
) {
443 g_value_set_object (value
, wbc
->wb_view
);
446 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
452 wbc_set_property (GObject
*object
,
457 WorkbookControl
*wbc
= (WorkbookControl
*)object
;
459 switch (property_id
) {
461 wbc
->wb_view
= g_value_get_object (value
);
464 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
469 static GObjectClass
*parent_klass
;
472 wbc_dispose (GObject
*obj
)
474 WorkbookControl
*wbc
= GNM_WBC (obj
);
475 if (wbc
->clipboard_changed_signal
) {
476 g_signal_handler_disconnect (gnm_app_get_app (),
477 wbc
->clipboard_changed_signal
);
478 wbc
->clipboard_changed_signal
= 0;
481 if (wbc
->wb_view
!= NULL
)
482 wb_view_detach_control (wbc
);
484 parent_klass
->dispose (obj
);
488 workbook_control_class_init (GObjectClass
*object_class
)
490 parent_klass
= g_type_class_peek_parent (object_class
);
491 object_class
->dispose
= wbc_dispose
;
492 object_class
->get_property
= wbc_get_property
;
493 object_class
->set_property
= wbc_set_property
;
495 g_object_class_install_property
498 g_param_spec_object ("view",
500 P_("The workbook view being controlled."),
501 GNM_WORKBOOK_VIEW_TYPE
,
507 workbook_control_init (GObject
*obj
)
509 WorkbookControl
*wbc
= GNM_WBC (obj
);
511 wbc
->clipboard_changed_signal
= g_signal_connect (
513 "clipboard_modified",
514 G_CALLBACK (cb_wbc_clipboard_modified
), wbc
);
518 wbc_cmd_context_init (G_GNUC_UNUSED GOCmdContextClass
*iface
)
521 iface
->get_password
= ;
522 iface
->set_sensitive
= ;
523 iface
->error
.error
= ;
524 iface
->error
.error_info
= ;
525 iface
->error
.error_info_list
= ;
526 iface
->progress_set
= ;
527 iface
->progress_message_set
= ;
531 GSF_CLASS_FULL (WorkbookControl
, workbook_control
, NULL
, NULL
,
532 workbook_control_class_init
, NULL
, workbook_control_init
,
533 GO_TYPE_DOC_CONTROL
, 0,
534 GSF_INTERFACE (wbc_cmd_context_init
, GO_TYPE_CMD_CONTEXT
))
538 wb_control_set_view (WorkbookControl
*wbc
,
539 WorkbookView
*opt_view
, Workbook
*opt_wb
)
543 g_return_if_fail (GNM_IS_WBC (wbc
));
544 g_return_if_fail (wbc
->wb_view
== NULL
);
546 wbv
= (opt_view
!= NULL
) ? opt_view
: workbook_view_new (opt_wb
);
547 wb_view_attach_control (wbv
, wbc
);
548 go_doc_control_set_doc (GO_DOC_CONTROL (wbc
), GO_DOC (wb_view_get_workbook (wbv
)));
552 wb_control_init_state (WorkbookControl
*wbc
)
555 WorkbookControlClass
*wbc_class
;
557 g_return_if_fail (GNM_IS_WBC (wbc
));
559 /* Setup the undo/redo combos */
560 command_setup_combos (wbc
);
562 /* Add views for all existing sheets */
563 wbv
= wb_control_view (wbc
);
564 WORKBOOK_FOREACH_SHEET(wb_control_get_workbook (wbc
), sheet
, {
565 SHEET_FOREACH_VIEW (sheet
, view
, {
566 if (sv_wbv (view
) == wbv
)
567 wb_control_sheet_add (wbc
, view
);
571 wbc_class
= WBC_CLASS (wbc
);
572 if (wbc_class
!= NULL
&& wbc_class
->init_state
!= NULL
)
573 wbc_class
->init_state (wbc
);