Update Spanish translation
[gnumeric.git] / src / workbook-control.c
blobe0f48adc59e96596504d95eb06e277f0190881bc
2 /*
3 * workbook-control.c: The base class for the displaying a workbook.
5 * Copyright (C) 2000-2002 Jody Goldberg (jody@gnome.org)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) version 3.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20 * USA
23 #include <gnumeric-config.h>
24 #include <gnm-i18n.h>
25 #include <gnumeric.h>
26 #include <workbook-control-priv.h>
28 #include <application.h>
29 #include <workbook-view.h>
30 #include <workbook-priv.h>
31 #include <sheet.h>
32 #include <sheet-view.h>
33 #include <sheet-utils.h>
34 #include <selection.h>
35 #include <commands.h>
36 #include <value.h>
37 #include <ranges.h>
38 #include <expr-name.h>
39 #include <expr.h>
40 #include <command-context.h>
41 #include <goffice/goffice.h>
42 #include <gsf/gsf-impl-utils.h>
44 enum {
45 PROP_0,
46 PROP_VIEW
49 #define WBC_CLASS(o) GNM_WBC_CLASS (G_OBJECT_GET_CLASS (o))
50 #define WBC_VIRTUAL_FULL(func, handle, arglist, call) \
51 void wb_control_ ## func arglist \
52 { \
53 WorkbookControlClass *wbc_class = WBC_CLASS (wbc); \
55 g_return_if_fail (wbc_class != NULL); \
57 if (wbc_class != NULL && wbc_class->handle != NULL) \
58 wbc_class->handle call; \
60 #define WBC_VIRTUAL(func, arglist, call) WBC_VIRTUAL_FULL(func, func, arglist, call)
62 /**
63 * workbook_control_new_wrapper:
64 * @wbc: #WorkbookControl
65 * @wbv: #WorkbookView
66 * @wb: #Workbook
67 * @extra: (allow-none):
69 * Returns: (transfer full): the newly allocated #WorkbookControl.
70 **/
71 WorkbookControl *
72 workbook_control_new_wrapper (WorkbookControl *wbc, WorkbookView *wbv, Workbook *wb,
73 void *extra)
75 WorkbookControlClass *wbc_class = WBC_CLASS (wbc);
77 g_return_val_if_fail (wbc_class != NULL, NULL);
79 if (wbc_class != NULL && wbc_class->control_new != NULL)
80 return wbc_class->control_new (wbc, wbv, wb, extra);
81 return NULL;
84 WBC_VIRTUAL (style_feedback,
85 (WorkbookControl *wbc, GnmStyle const *changes), (wbc, changes))
86 WBC_VIRTUAL (edit_line_set,
87 (WorkbookControl *wbc, char const *text), (wbc, text))
88 WBC_VIRTUAL (selection_descr_set,
89 (WorkbookControl *wbc, char const *text), (wbc, text))
91 WBC_VIRTUAL_FULL (sheet_remove, sheet.remove,
92 (WorkbookControl *wbc, Sheet *sheet), (wbc, sheet))
93 WBC_VIRTUAL_FULL (sheet_focus, sheet.focus,
94 (WorkbookControl *wbc, Sheet *sheet), (wbc, sheet))
95 WBC_VIRTUAL_FULL (sheet_remove_all, sheet.remove_all,
96 (WorkbookControl *wbc), (wbc))
98 WBC_VIRTUAL_FULL (undo_redo_truncate, undo_redo.truncate,
99 (WorkbookControl *wbc, int n, gboolean is_undo), (wbc, n, is_undo))
100 WBC_VIRTUAL_FULL (undo_redo_pop, undo_redo.pop,
101 (WorkbookControl *wbc, gboolean is_undo), (wbc, is_undo))
102 WBC_VIRTUAL_FULL (undo_redo_push, undo_redo.push,
103 (WorkbookControl *wbc, gboolean is_undo, char const *text, gpointer key),
104 (wbc, is_undo, text, key))
105 WBC_VIRTUAL_FULL (undo_redo_labels, undo_redo.labels,
106 (WorkbookControl *wbc, char const *undo, char const *redo),
107 (wbc, undo, redo))
109 WBC_VIRTUAL_FULL (menu_state_update, menu_state.update,
110 (WorkbookControl *wbc, int flags),
111 (wbc, flags))
113 WBC_VIRTUAL (paste_from_selection,
114 (WorkbookControl *wbc, GnmPasteTarget const *pt), (wbc, pt))
115 WBC_VIRTUAL (update_action_sensitivity,
116 (WorkbookControl *wbc), (wbc))
118 void
119 wb_control_sheet_add (WorkbookControl *wbc, SheetView *sv)
121 WorkbookControlClass *wbc_class;
123 g_return_if_fail (GNM_IS_WBC (wbc));
125 wbc_class = WBC_CLASS (wbc);
126 if (wbc_class != NULL && wbc_class->sheet.add != NULL) {
127 Sheet *new_sheet = sv_sheet (sv);
129 wbc_class->sheet.add (wbc, sv);
131 /* If this is the current sheet init the display */
132 if (new_sheet == wb_control_cur_sheet (wbc)) {
133 WorkbookView *wbv = wb_control_view (wbc);
134 wb_control_sheet_focus (wbc, new_sheet);
135 wb_view_selection_desc (wbv, TRUE, wbc);
136 wb_view_edit_line_set (wbv, wbc);
137 wb_control_style_feedback (wbc, NULL);
138 wb_control_menu_state_update (wbc, MS_ALL);
139 wb_control_update_action_sensitivity (wbc);
144 gboolean
145 wb_control_claim_selection (WorkbookControl *wbc)
147 WorkbookControlClass *wbc_class;
149 g_return_val_if_fail (GNM_IS_WBC (wbc), FALSE);
151 wbc_class = WBC_CLASS (wbc);
152 if (wbc_class != NULL && wbc_class->claim_selection != NULL)
153 return wbc_class->claim_selection (wbc);
154 return TRUE; /* no handler means we always get the selection */
158 * wb_control_validation_msg:
159 * 1 : ignore invalid and accept result
160 * 0 : discard invalid and finish editing
161 * -1 : continue editing
164 wb_control_validation_msg (WorkbookControl *wbc, ValidationStyle v,
165 char const *title, char const *msg)
167 WorkbookControlClass *wbc_class;
169 g_return_val_if_fail (GNM_IS_WBC (wbc), 1);
171 wbc_class = WBC_CLASS (wbc);
172 if (wbc_class != NULL && wbc_class->validation_msg != NULL)
173 return wbc_class->validation_msg (wbc, v, title, msg);
174 return 1; /* no handler, always accept */
178 * wb_control_view:
179 * @wbc: #WorkbookControl
181 * Returns: (transfer none): the workbook view.
183 WorkbookView *
184 wb_control_view (WorkbookControl const *wbc)
186 g_return_val_if_fail (GNM_IS_WBC (wbc), NULL);
187 return wbc->wb_view;
191 * wb_control_get_doc:
192 * @wbc: #WorkbookControl
194 * Returns: (transfer none): the workbook set as a #GODoc.
196 GODoc *
197 wb_control_get_doc (WorkbookControl const *wbc)
199 return GO_DOC (wb_control_get_workbook (wbc));
203 * wb_control_get_workbook:
204 * @wbc: #WorkbookControl
206 * Returns: (transfer none): the workbook.
208 Workbook *
209 wb_control_get_workbook (WorkbookControl const *wbc)
211 g_return_val_if_fail (GNM_IS_WBC (wbc), NULL);
212 return wbc->wb_view ? wb_view_get_workbook (wbc->wb_view) : NULL;
216 * wb_control_cur_sheet:
217 * @wbc: #WorkbookControl
219 * Returns: (transfer none): the current sheet.
221 Sheet *
222 wb_control_cur_sheet (WorkbookControl const *wbc)
224 g_return_val_if_fail (GNM_IS_WBC (wbc), NULL);
225 return wb_view_cur_sheet (wbc->wb_view);
229 * wb_control_cur_sheet_view:
230 * @wbc: #WorkbookControl
232 * Returns: (transfer none): the current sheet view.
234 SheetView *
235 wb_control_cur_sheet_view (WorkbookControl const *wbc)
237 g_return_val_if_fail (GNM_IS_WBC (wbc), NULL);
238 return wb_view_cur_sheet_view (wbc->wb_view);
241 static void
242 wb_create_name (WorkbookControl *wbc, char const *text, GnmParsePos *pp)
244 GnmRange const *r;
245 GnmCellRef a, b;
246 GnmExpr const *target_range;
248 r = selection_first_range (wb_control_cur_sheet_view (wbc),
249 GO_CMD_CONTEXT (wbc), _("Define Name"));
250 if (r != NULL) {
251 a.sheet = b.sheet = wb_control_cur_sheet (wbc);
252 a.col = r->start.col;
253 a.row = r->start.row;
254 b.col = r->end.col;
255 b.row = r->end.row;
256 a.col_relative = a.row_relative = b.col_relative = b.row_relative = FALSE;
257 pp->sheet = NULL; /* make it a global name */
258 if (gnm_cellref_equal (&a, &b))
259 target_range = gnm_expr_new_cellref (&a);
260 else
261 target_range = gnm_expr_new_constant (
262 value_new_cellrange_unsafe (&a, &b));
263 cmd_define_name (wbc, text, pp, gnm_expr_top_new (target_range), NULL);
268 * Select the given range and make the it visible.
270 gboolean
271 wb_control_jump (WorkbookControl *wbc, Sheet *sheet, const GnmRangeRef *r)
273 SheetView *sv;
274 GnmCellPos tmp;
276 if (r->a.sheet)
277 sheet = r->a.sheet;
279 if (!sheet_is_visible (sheet)) {
280 go_cmd_context_error_invalid
281 (GO_CMD_CONTEXT (wbc),
282 _("Cannot jump to an invisible sheet"),
283 sheet->name_unquoted);
284 return FALSE;
287 sv = sheet_get_view (sheet, wb_control_view (wbc));
289 tmp.col = r->a.col;
290 tmp.row = r->a.row;
291 sv_selection_set (sv, &tmp, r->a.col, r->a.row, r->b.col, r->b.row);
292 gnm_sheet_view_make_cell_visible (sv, r->b.col, r->b.row, FALSE);
293 gnm_sheet_view_make_cell_visible (sv, r->a.col, r->a.row, FALSE);
294 gnm_sheet_view_update (sv);
295 if (wb_control_cur_sheet (wbc) != sheet)
296 wb_view_sheet_focus (wbc->wb_view, sheet);
298 return TRUE;
302 * This is called when something is entered in the location entry.
303 * We either go there (if the text refers to a cell by address or
304 * name), or we try to define a name for the selection.
306 gboolean
307 wb_control_parse_and_jump (WorkbookControl *wbc, char const *text)
309 Sheet *sheet = wb_control_cur_sheet (wbc);
310 GnmParsePos pp;
311 GnmEvalPos ep;
312 GnmValue *target;
313 GnmRangeRef range;
314 SheetView *sv;
316 if (text == NULL || *text == '\0')
317 return FALSE;
319 sv = wb_control_cur_sheet_view (wbc);
320 parse_pos_init_editpos (&pp, sv);
321 target = value_new_cellrange_parsepos_str (&pp, text,
322 GNM_EXPR_PARSE_DEFAULT);
323 if (target == NULL) {
324 GnmExprTop const *texpr;
326 texpr = gnm_expr_parse_str
327 (text, &pp, GNM_EXPR_PARSE_DEFAULT,
328 gnm_conventions_xls_r1c1, NULL);
329 if (texpr != NULL) {
330 target = gnm_expr_top_get_range (texpr);
331 gnm_expr_top_unref (texpr);
334 if (target == NULL) {
335 GnmExprTop const *texpr;
337 texpr = gnm_expr_parse_str
338 (text, &pp, GNM_EXPR_PARSE_DEFAULT,
339 gnm_conventions_default, NULL);
340 if (texpr != NULL) {
341 target = gnm_expr_top_get_range (texpr);
342 gnm_expr_top_unref (texpr);
346 if (target == NULL) {
347 /* Not an address; is it a name? */
348 GnmParsePos pp;
349 GnmNamedExpr *nexpr = expr_name_lookup (
350 parse_pos_init_sheet (&pp, sheet), text);
352 /* If no name, or just a placeholder exists create a name */
353 if (nexpr == NULL || expr_name_is_placeholder (nexpr)) {
354 wb_create_name (wbc, text, &pp);
355 return FALSE;
356 } else {
357 target = gnm_expr_top_get_range (nexpr->texpr);
358 if (target == NULL) {
359 go_cmd_context_error_invalid (GO_CMD_CONTEXT (wbc),
360 _("Address"), text);
361 return FALSE;
366 eval_pos_init_editpos (&ep, sv);
367 gnm_cellref_make_abs (&range.a, &target->v_range.cell.a, &ep);
368 gnm_cellref_make_abs (&range.b, &target->v_range.cell.b, &ep);
369 value_release (target);
371 return wb_control_jump (wbc, sheet, &range);
374 void
375 wb_control_navigate_to_cell (WorkbookControl *wbc, wb_control_navigator_t to)
377 Sheet *sheet = wb_control_cur_sheet (wbc);
378 SheetView *sv = wb_control_cur_sheet_view (wbc);
379 GnmRange region;
380 GnmRange const *first = selection_first_range (sv, NULL, NULL);
381 GnmRangeRef rangeref;
383 region = *first;
384 gnm_sheet_guess_data_range (sheet, &region);
385 range_ensure_sanity (&region, sheet);
387 switch (to) {
388 case navigator_top:
389 region.end.row = region.start.row;
390 region.start.col = first->start.col;
391 region.end.col = first->end.col;
392 break;
393 case navigator_bottom:
394 region.start.row = region.end.row;
395 region.start.col = first->start.col;
396 region.end.col = first->end.col;
397 break;
398 case navigator_first:
399 region.end.col = region.start.col;
400 region.start.row = first->start.row;
401 region.end.row = first->end.row;
402 break;
403 case navigator_last:
404 region.start.col = region.end.col;
405 region.start.row = first->start.row;
406 region.end.row = first->end.row;
407 break;
408 default:
409 break;
411 gnm_cellref_init (&rangeref.a, sheet,
412 region.start.col, region.start.row, FALSE);
413 gnm_cellref_init (&rangeref.b, sheet,
414 region.end.col, region.end.row, FALSE);
416 wb_control_jump (wbc, sheet, &rangeref);
418 return;
424 static void
425 cb_wbc_clipboard_modified (G_GNUC_UNUSED GnmApp *app, WorkbookControl *wbc)
427 wb_control_menu_state_update (wbc, MS_PASTE_SPECIAL);
430 /*****************************************************************************/
432 static void
433 wbc_get_property (GObject *object,
434 guint property_id,
435 GValue *value,
436 GParamSpec *pspec)
438 WorkbookControl *wbc = (WorkbookControl *)object;
440 switch (property_id) {
441 case PROP_VIEW:
442 g_value_set_object (value, wbc->wb_view);
443 break;
444 default:
445 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
446 break;
450 static void
451 wbc_set_property (GObject *object,
452 guint property_id,
453 GValue const *value,
454 GParamSpec *pspec)
456 WorkbookControl *wbc = (WorkbookControl *)object;
458 switch (property_id) {
459 case PROP_VIEW:
460 wbc->wb_view = g_value_get_object (value);
461 break;
462 default:
463 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
464 break;
468 static GObjectClass *parent_klass;
470 static void
471 wbc_dispose (GObject *obj)
473 WorkbookControl *wbc = GNM_WBC (obj);
474 if (wbc->clipboard_changed_signal) {
475 g_signal_handler_disconnect (gnm_app_get_app (),
476 wbc->clipboard_changed_signal);
477 wbc->clipboard_changed_signal = 0;
480 if (wbc->wb_view != NULL)
481 wb_view_detach_control (wbc);
483 parent_klass->dispose (obj);
486 static void
487 workbook_control_class_init (GObjectClass *object_class)
489 parent_klass = g_type_class_peek_parent (object_class);
490 object_class->dispose = wbc_dispose;
491 object_class->get_property = wbc_get_property;
492 object_class->set_property = wbc_set_property;
494 g_object_class_install_property
495 (object_class,
496 PROP_VIEW,
497 g_param_spec_object ("view",
498 P_("View"),
499 P_("The workbook view being controlled."),
500 GNM_WORKBOOK_VIEW_TYPE,
501 GSF_PARAM_STATIC |
502 G_PARAM_READWRITE));
505 static void
506 workbook_control_init (GObject *obj)
508 WorkbookControl *wbc = GNM_WBC (obj);
510 wbc->clipboard_changed_signal = g_signal_connect (
511 gnm_app_get_app (),
512 "clipboard_modified",
513 G_CALLBACK (cb_wbc_clipboard_modified), wbc);
516 static void
517 wbc_cmd_context_init (G_GNUC_UNUSED GOCmdContextClass *iface)
519 #if 0
520 iface->get_password = ;
521 iface->set_sensitive = ;
522 iface->error.error = ;
523 iface->error.error_info = ;
524 iface->error.error_info_list= ;
525 iface->progress_set = ;
526 iface->progress_message_set = ;
527 #endif
530 GSF_CLASS_FULL (WorkbookControl, workbook_control, NULL, NULL,
531 workbook_control_class_init, NULL, workbook_control_init,
532 GO_TYPE_DOC_CONTROL, 0,
533 GSF_INTERFACE (wbc_cmd_context_init, GO_TYPE_CMD_CONTEXT))
536 void
537 wb_control_set_view (WorkbookControl *wbc,
538 WorkbookView *opt_view, Workbook *opt_wb)
540 WorkbookView *wbv;
542 g_return_if_fail (GNM_IS_WBC (wbc));
543 g_return_if_fail (wbc->wb_view == NULL);
545 wbv = (opt_view != NULL) ? opt_view : workbook_view_new (opt_wb);
546 wb_view_attach_control (wbv, wbc);
547 go_doc_control_set_doc (GO_DOC_CONTROL (wbc), GO_DOC (wb_view_get_workbook (wbv)));
550 void
551 wb_control_init_state (WorkbookControl *wbc)
553 WorkbookView *wbv;
554 WorkbookControlClass *wbc_class;
556 g_return_if_fail (GNM_IS_WBC (wbc));
558 /* Setup the undo/redo combos */
559 command_setup_combos (wbc);
561 /* Add views for all existing sheets */
562 wbv = wb_control_view (wbc);
563 WORKBOOK_FOREACH_SHEET(wb_control_get_workbook (wbc), sheet, {
564 SHEET_FOREACH_VIEW (sheet, view, {
565 if (sv_wbv (view) == wbv)
566 wb_control_sheet_add (wbc, view);
570 wbc_class = WBC_CLASS (wbc);
571 if (wbc_class != NULL && wbc_class->init_state != NULL)
572 wbc_class->init_state (wbc);