GUI: Move .ui files from goffice resources to glib resources
[gnumeric.git] / src / workbook-control.c
blob891a5e0fa1e7f9e36ceb16b0243d1a95895907b8
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /*
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
21 * USA
24 #include <gnumeric-config.h>
25 #include "gnm-i18n.h"
26 #include "gnumeric.h"
27 #include "workbook-control-priv.h"
29 #include "application.h"
30 #include "workbook-view.h"
31 #include "workbook-priv.h"
32 #include "sheet.h"
33 #include "sheet-view.h"
34 #include "sheet-utils.h"
35 #include "selection.h"
36 #include "commands.h"
37 #include "value.h"
38 #include "ranges.h"
39 #include "expr-name.h"
40 #include "expr.h"
41 #include "command-context.h"
42 #include <goffice/goffice.h>
43 #include <gsf/gsf-impl-utils.h>
45 enum {
46 PROP_0,
47 PROP_VIEW
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 \
53 { \
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)
63 /**
64 * workbook_control_new_wrapper:
65 * @wbc: #WorkbookControl
66 * @wbv: #WorkbookView
67 * @wb: #Workbook
68 * @extra: (allow-none):
70 * Returns: (transfer full): the newly allocated #WorkbookControl.
71 **/
72 WorkbookControl *
73 workbook_control_new_wrapper (WorkbookControl *wbc, WorkbookView *wbv, Workbook *wb,
74 void *extra)
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);
82 return NULL;
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),
108 (wbc, undo, redo))
110 WBC_VIRTUAL_FULL (menu_state_update, menu_state.update,
111 (WorkbookControl *wbc, int flags),
112 (wbc, 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))
119 void
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);
145 gboolean
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 */
179 * wb_control_view:
180 * @wbc: #WorkbookControl
182 * Returns: (transfer none): the workbook view.
184 WorkbookView *
185 wb_control_view (WorkbookControl const *wbc)
187 g_return_val_if_fail (GNM_IS_WBC (wbc), NULL);
188 return wbc->wb_view;
192 * wb_control_get_doc:
193 * @wbc: #WorkbookControl
195 * Returns: (transfer none): the workbook set as a #GODoc.
197 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.
209 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.
222 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.
235 SheetView *
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);
242 static void
243 wb_create_name (WorkbookControl *wbc, char const *text, GnmParsePos *pp)
245 GnmRange const *r;
246 GnmCellRef a, b;
247 GnmExpr const *target_range;
249 r = selection_first_range (wb_control_cur_sheet_view (wbc),
250 GO_CMD_CONTEXT (wbc), _("Define Name"));
251 if (r != NULL) {
252 a.sheet = b.sheet = wb_control_cur_sheet (wbc);
253 a.col = r->start.col;
254 a.row = r->start.row;
255 b.col = r->end.col;
256 b.row = r->end.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);
261 else
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.
271 gboolean
272 wb_control_jump (WorkbookControl *wbc, Sheet *sheet, const GnmRangeRef *r)
274 SheetView *sv;
275 GnmCellPos tmp;
277 if (r->a.sheet)
278 sheet = r->a.sheet;
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);
285 return FALSE;
288 sv = sheet_get_view (sheet, wb_control_view (wbc));
290 tmp.col = r->a.col;
291 tmp.row = r->a.row;
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);
299 return TRUE;
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.
307 gboolean
308 wb_control_parse_and_jump (WorkbookControl *wbc, char const *text)
310 Sheet *sheet = wb_control_cur_sheet (wbc);
311 GnmParsePos pp;
312 GnmEvalPos ep;
313 GnmValue *target;
314 GnmRangeRef range;
315 SheetView *sv;
317 if (text == NULL || *text == '\0')
318 return FALSE;
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);
330 if (texpr != 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);
341 if (texpr != 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? */
349 GnmParsePos pp;
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);
356 return FALSE;
357 } else {
358 target = gnm_expr_top_get_range (nexpr->texpr);
359 if (target == NULL) {
360 go_cmd_context_error_invalid (GO_CMD_CONTEXT (wbc),
361 _("Address"), text);
362 return FALSE;
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);
375 void
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);
380 GnmRange region;
381 GnmRange const *first = selection_first_range (sv, NULL, NULL);
382 GnmRangeRef rangeref;
384 region = *first;
385 gnm_sheet_guess_data_range (sheet, &region);
386 range_ensure_sanity (&region, sheet);
388 switch (to) {
389 case navigator_top:
390 region.end.row = region.start.row;
391 region.start.col = first->start.col;
392 region.end.col = first->end.col;
393 break;
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;
398 break;
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;
403 break;
404 case navigator_last:
405 region.start.col = region.end.col;
406 region.start.row = first->start.row;
407 region.end.row = first->end.row;
408 break;
409 default:
410 break;
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);
419 return;
425 static void
426 cb_wbc_clipboard_modified (G_GNUC_UNUSED GnmApp *app, WorkbookControl *wbc)
428 wb_control_menu_state_update (wbc, MS_PASTE_SPECIAL);
431 /*****************************************************************************/
433 static void
434 wbc_get_property (GObject *object,
435 guint property_id,
436 GValue *value,
437 GParamSpec *pspec)
439 WorkbookControl *wbc = (WorkbookControl *)object;
441 switch (property_id) {
442 case PROP_VIEW:
443 g_value_set_object (value, wbc->wb_view);
444 break;
445 default:
446 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
447 break;
451 static void
452 wbc_set_property (GObject *object,
453 guint property_id,
454 GValue const *value,
455 GParamSpec *pspec)
457 WorkbookControl *wbc = (WorkbookControl *)object;
459 switch (property_id) {
460 case PROP_VIEW:
461 wbc->wb_view = g_value_get_object (value);
462 break;
463 default:
464 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
465 break;
469 static GObjectClass *parent_klass;
471 static void
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);
487 static void
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
496 (object_class,
497 PROP_VIEW,
498 g_param_spec_object ("view",
499 P_("View"),
500 P_("The workbook view being controlled."),
501 GNM_WORKBOOK_VIEW_TYPE,
502 GSF_PARAM_STATIC |
503 G_PARAM_READWRITE));
506 static void
507 workbook_control_init (GObject *obj)
509 WorkbookControl *wbc = GNM_WBC (obj);
511 wbc->clipboard_changed_signal = g_signal_connect (
512 gnm_app_get_app (),
513 "clipboard_modified",
514 G_CALLBACK (cb_wbc_clipboard_modified), wbc);
517 static void
518 wbc_cmd_context_init (G_GNUC_UNUSED GOCmdContextClass *iface)
520 #if 0
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 = ;
528 #endif
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))
537 void
538 wb_control_set_view (WorkbookControl *wbc,
539 WorkbookView *opt_view, Workbook *opt_wb)
541 WorkbookView *wbv;
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)));
551 void
552 wb_control_init_state (WorkbookControl *wbc)
554 WorkbookView *wbv;
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);