/* * Select the given range and make the it visible. */ static gboolean wb_control_jump (WorkbookControl *wbc, Sheet *sheet, const GnmRangeRef *r) { SheetView *sv; GnmCellPos tmp; if (r->a.sheet) sheet = r->a.sheet; if (!sheet_is_visible (sheet)) { go_cmd_context_error_invalid (GO_CMD_CONTEXT (wbc), _("Cannot jump to an invisible sheet"), sheet->name_unquoted); return FALSE; } sv = sheet_get_view (sheet, wb_control_view (wbc)); tmp.col = r->a.col; tmp.row = r->a.row; sv_selection_set (sv, &tmp, r->a.col, r->a.row, r->b.col, r->b.row); sv_make_cell_visible (sv, r->b.col, r->b.row, FALSE); sv_make_cell_visible (sv, r->a.col, r->a.row, FALSE); sv_update (sv); if (wb_control_cur_sheet (wbc) != sheet) wb_view_sheet_focus (wbc->wb_view, sheet); return TRUE; }
void dialog_workbook_attr (WBCGtk *wbcg) { GtkBuilder *gui; AttrState *state; g_return_if_fail (wbcg != NULL); if (gnm_dialog_raise_if_exists (wbcg, WORKBOOK_ATTRIBUTE_KEY)) return; gui = gnm_gtk_builder_load ("res:ui/workbook-attr.ui", NULL, GO_CMD_CONTEXT (wbcg)); if (gui == NULL) return; /* Initialize */ state = g_new (AttrState, 1); state->gui = gui; state->wbcg = wbcg; state->wbv = wb_control_view (GNM_WBC (wbcg)); state->wb = wb_control_get_workbook (GNM_WBC (wbcg)); attr_dialog_impl (state); /* Select the same page the last invocation used */ attr_dialog_select_page (state, attr_dialog_page); }
void wb_control_sheet_add (WorkbookControl *wbc, SheetView *sv) { WorkbookControlClass *wbc_class; g_return_if_fail (IS_WORKBOOK_CONTROL (wbc)); wbc_class = WBC_CLASS (wbc); if (wbc_class != NULL && wbc_class->sheet.add != NULL) { Sheet *new_sheet = sv_sheet (sv); wbc_class->sheet.add (wbc, sv); /* If this is the current sheet init the display */ if (new_sheet == wb_control_cur_sheet (wbc)) { WorkbookView *wbv = wb_control_view (wbc); wb_control_sheet_focus (wbc, new_sheet); wb_view_selection_desc (wbv, TRUE, wbc); wb_view_edit_line_set (wbv, wbc); wb_control_style_feedback (wbc, NULL); wb_control_menu_state_update (wbc, MS_ALL); wb_control_update_action_sensitivity (wbc); } } }
static void cb_dialog_goto_selection_changed (GtkTreeSelection *the_selection, GotoState *state) { GtkTreeIter iter; GtkTreeModel *model; Sheet *sheet; GnmNamedExpr *name; if (gtk_tree_selection_get_selected (the_selection, &model, &iter)) { gtk_tree_model_get (model, &iter, SHEET_POINTER, &sheet, EXPRESSION, &name, -1); if (name && gnm_expr_top_is_rangeref (name->texpr)) { GnmParsePos pp; char *where_to; if (NULL == sheet) sheet = wb_control_cur_sheet ( WORKBOOK_CONTROL (state->wbcg)); parse_pos_init_sheet (&pp, sheet); where_to = expr_name_as_string (name, &pp, gnm_conventions_default); if (wb_control_parse_and_jump (WORKBOOK_CONTROL (state->wbcg), where_to)) gtk_entry_set_text (state->goto_text, where_to); g_free (where_to); return; } if (sheet) wb_view_sheet_focus ( wb_control_view (WORKBOOK_CONTROL (state->wbcg)), sheet); } }
/* * Advanced Filter tool. */ gint advanced_filter (WorkbookControl *wbc, data_analysis_output_t *dao, GnmValue *database, GnmValue *criteria, gboolean unique_only_flag) { GSList *crit, *rows; GnmEvalPos ep; GnmRange r, s; SheetView *sv; Sheet *sheet = criteria->v_range.cell.a.sheet; /* I don't like this -- minimal fix for now. 509427. */ if (!VALUE_IS_CELLRANGE (criteria)) return analysis_tools_invalid_field; crit = parse_database_criteria ( eval_pos_init_sheet (&ep, wb_control_cur_sheet (wbc)), database, criteria); if (crit == NULL) return analysis_tools_invalid_field; rows = find_rows_that_match (sheet, database->v_range.cell.a.col, database->v_range.cell.a.row + 1, database->v_range.cell.b.col, database->v_range.cell.b.row, crit, unique_only_flag); free_criterias (crit); if (rows == NULL) return analysis_tools_no_records_found; dao_prepare_output (wbc, dao, _("Filtered")); filter (dao, sheet, rows, database->v_range.cell.a.col, database->v_range.cell.b.col, database->v_range.cell.a.row, database->v_range.cell.b.row); g_slist_free_full (rows, (GDestroyNotify)g_free); sv = sheet_get_view (sheet, wb_control_view (wbc)); s = r = *(selection_first_range (sv, NULL, NULL)); r.end.row = r.start.row; sv_selection_reset (sv); sv_selection_add_range (sv, &r); sv_selection_add_range (sv, &s); wb_control_menu_state_update (wbc, MS_FILTER_STATE_CHANGED); return analysis_tools_noerr; }
static gboolean item_grid_button_released (GocItem *item, int button, G_GNUC_UNUSED double x_, G_GNUC_UNUSED double y_) { GnmItemGrid *ig = GNM_ITEM_GRID (item); GnmPane *pane = GNM_PANE (item->canvas); SheetControlGUI *scg = ig->scg; Sheet *sheet = scg_sheet (scg); ItemGridSelectionType selecting = ig->selecting; GdkEvent *event = goc_canvas_get_cur_event (item->canvas); if (button != 1 && button != 2) return FALSE; gnm_pane_slide_stop (pane); switch (selecting) { case GNM_ITEM_GRID_NO_SELECTION: return TRUE; case GNM_ITEM_GRID_SELECTING_FORMULA_RANGE : /* Removal of this code (2 lines) */ /* should fix http://bugzilla.gnome.org/show_bug.cgi?id=63485 */ /* sheet_make_cell_visible (sheet, */ /* sheet->edit_pos.col, sheet->edit_pos.row, FALSE); */ /* Fall through */ case GNM_ITEM_GRID_SELECTING_CELL_RANGE : sv_selection_simplify (scg_view (scg)); wb_view_selection_desc ( wb_control_view (scg_wbc (scg)), TRUE, NULL); break; default: g_assert_not_reached (); } ig->selecting = GNM_ITEM_GRID_NO_SELECTION; gnm_simple_canvas_ungrab (item, gdk_event_get_time (event)); if (selecting == GNM_ITEM_GRID_SELECTING_FORMULA_RANGE) gnm_expr_entry_signal_update ( wbcg_get_entry_logical (scg_wbcg (scg)), TRUE); if (selecting == GNM_ITEM_GRID_SELECTING_CELL_RANGE && button == 1) { GnmCellPos const *pos = sv_is_singleton_selected (scg_view (scg)); if (pos != NULL) { GnmHLink *link; /* check for hyper links */ link = sheet_hlink_find (sheet, pos); if (link != NULL) gnm_hlink_activate (link, scg_wbcg (scg)); } } return TRUE; }
static void cb_entry_changed (G_GNUC_UNUSED GtkEntry *entry, WBCGtk *wbcg) { char const *text; int text_len; WorkbookView *wbv = wb_control_view (GNM_WBC (wbcg)); text = gtk_entry_get_text (wbcg_get_entry (wbcg)); text_len = strlen (text); if (text_len > wbcg->auto_max_size) wbcg->auto_max_size = text_len; if (wbv->do_auto_completion && wbcg->auto_completing) gnm_complete_start (GNM_COMPLETE (wbcg->auto_complete), text); }
/** Create a new Gnumeric workbook, optionally reading a file to populate it. */ USER_OBJECT_ RGnumeric_newWorkbook(USER_OBJECT_ fileName) { WorkbookControl *wbc; USER_OBJECT_ ans; if(GET_LENGTH(fileName)) { wbc = workbook_control_gui_new(NULL, NULL); #ifdef HAVE_WORKBOOK_READ workbook_read(wbc, CHAR_DEREF(STRING_ELT(fileName,0))); #else wb_view_open (wb_control_view (wbc), wbc, CHAR_DEREF(STRING_ELT(fileName,0)), TRUE); #endif } else { wbc = workbook_control_gui_new(NULL, workbook_new_with_sheets(1)); } ans = RGnumeric_workbookReference(wb_control_workbook(wbc)); return(ans); }
static void cursor_change (GtkTreeView *tree_view, DialogState *dd) { int matchno; int lastmatch = dd->matches->len - 1; GtkTreePath *path; gtk_tree_view_get_cursor (tree_view, &path, NULL); if (path) { matchno = gtk_tree_path_get_indices (path)[0]; gtk_tree_path_free (path); } else { matchno = -1; } gtk_widget_set_sensitive (dd->prev_button, matchno > 0); gtk_widget_set_sensitive (dd->next_button, matchno >= 0 && matchno < lastmatch); if (matchno >= 0 && matchno <= lastmatch) { GnmSearchFilterResult *item = g_ptr_array_index (dd->matches, matchno); int col = item->ep.eval.col; int row = item->ep.eval.row; WorkbookControl *wbc = WORKBOOK_CONTROL (dd->wbcg); WorkbookView *wbv = wb_control_view (wbc); SheetView *sv; if (!sheet_is_visible (item->ep.sheet)) return; if (wb_control_cur_sheet (wbc) != item->ep.sheet) wb_view_sheet_focus (wbv, item->ep.sheet); sv = wb_view_cur_sheet_view (wbv); sv_set_edit_pos (sv, &item->ep.eval); sv_selection_set (sv, &item->ep.eval, col, row, col, row); sv_make_cell_visible (sv, col, row, FALSE); sv_update (sv); } }
static void cb_view_ok_clicked (G_GNUC_UNUSED GtkWidget *button, ViewState *state) { WBCGtk *wbcg = state->wbcg; WorkbookControl *wbc = WORKBOOK_CONTROL (wbcg); WorkbookControl *new_wbc; gboolean shared; GdkScreen *screen; GSList *buttons = gtk_radio_button_get_group (state->location_elsewhere); shared = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->gui, "view_shared"))); while (buttons) if (gtk_toggle_button_get_active (buttons->data)) break; else buttons = buttons->next; if (!buttons) { g_assert_not_reached (); return; } else if (buttons->data == state->location_elsewhere) { const char *name = gtk_entry_get_text (state->location_display_name); GdkDisplay *display; if (!name) return; /* Just ignore */ display = gdk_display_open (name); if (!display) { char *error_str = g_strdup_printf (_("Display \"%s\" could not be opened."), name); gtk_widget_destroy (state->dialog); go_gtk_notice_dialog (wbcg_toplevel (wbcg), GTK_MESSAGE_ERROR, "%s", error_str); g_free (error_str); return; } screen = gdk_display_get_default_screen (display); } else { screen = g_object_get_data (buttons->data, "screen"); } gtk_widget_destroy (state->dialog); new_wbc = wb_control_wrapper_new (wbc, shared ? wb_control_view (wbc) : NULL, wb_control_get_workbook (wbc), screen); if (IS_WBC_GTK (new_wbc)) { /* What else would it be? */ WBCGtk *new_wbcg = WBC_GTK (new_wbc); wbcg_copy_toolbar_visibility (new_wbcg, wbcg); _gnm_app_flag_windows_changed (); } }
/* * Refreshes the buttons on a row (un)selection and selects the chosen sheet * for this view. */ static void cb_selection_changed (G_GNUC_UNUSED GtkTreeSelection *ignored, SheetManager *state) { GtkTreeIter iter; Sheet *sheet; gboolean has_iter; GdkRGBA *fore, *back; GtkTreeSelection *selection = gtk_tree_view_get_selection (state->sheet_list); GList *selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL); gboolean multiple = gtk_tree_model_iter_n_children(GTK_TREE_MODEL (state->model), NULL) > 1; int cnt_sel = g_list_length (selected_rows); gboolean single_sel = (cnt_sel < 2); gtk_widget_set_sensitive (state->sort_asc_btn, multiple); gtk_widget_set_sensitive (state->sort_desc_btn, multiple); if (selected_rows == NULL) { gtk_widget_set_sensitive (state->up_btn, FALSE); gtk_widget_set_sensitive (state->down_btn, FALSE); gtk_widget_set_sensitive (state->delete_btn, FALSE); gtk_widget_set_sensitive (state->ccombo_back, FALSE); gtk_widget_set_sensitive (state->ccombo_fore, FALSE); gtk_widget_set_sensitive (state->add_btn, FALSE); gtk_widget_set_sensitive (state->duplicate_btn, FALSE); return; } gtk_tree_model_get_iter (GTK_TREE_MODEL (state->model), &iter, (GtkTreePath *) selected_rows->data); gtk_tree_model_get (GTK_TREE_MODEL (state->model), &iter, SHEET_POINTER, &sheet, BACKGROUND_COLOUR, &back, FOREGROUND_COLOUR, &fore, -1); if (!state->initial_colors_set) { go_combo_color_set_color_gdk (GO_COMBO_COLOR (state->ccombo_back), back); go_combo_color_set_color_gdk (GO_COMBO_COLOR (state->ccombo_fore), fore); state->initial_colors_set = TRUE; } if (back != NULL) gdk_rgba_free (back); if (fore != NULL) gdk_rgba_free (fore); gtk_widget_set_sensitive (state->ccombo_back, TRUE); gtk_widget_set_sensitive (state->ccombo_fore, TRUE); gtk_widget_set_sensitive (state->delete_btn, sheet_order_cnt_visible (state) > cnt_sel); gtk_widget_set_sensitive (state->add_btn, single_sel); gtk_widget_set_sensitive (state->duplicate_btn, single_sel); has_iter = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (state->model), &iter); g_return_if_fail (has_iter); gtk_widget_set_sensitive (state->up_btn, single_sel && !gtk_tree_selection_iter_is_selected (selection, &iter)); gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (state->model), &iter, NULL, gtk_tree_model_iter_n_children (GTK_TREE_MODEL (state->model), NULL) - 1); gtk_widget_set_sensitive (state->down_btn, single_sel && !gtk_tree_selection_iter_is_selected (selection, &iter)); if (sheet != NULL) wb_view_sheet_focus ( wb_control_view (GNM_WBC (state->wbcg)), sheet); g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free); }
void dialog_sheet_order (WBCGtk *wbcg) { SheetManager *state; GtkBuilder *gui; GtkGrid *grid; GOColorGroup *cg; Workbook *wb; GtkWidget *widget; GdkPixbuf *icon; g_return_if_fail (wbcg != NULL); widget = GTK_WIDGET (wbcg_toplevel (wbcg)); gui = gnm_gtk_builder_load ("res:ui/sheet-order.ui", NULL, GO_CMD_CONTEXT (wbcg)); if (gui == NULL) return; wb = wb_control_get_workbook (GNM_WBC (wbcg)); if (g_object_get_data (G_OBJECT (wb), SHEET_ORDER_KEY)) { GtkWidget *dialog = gtk_message_dialog_new (wbcg_toplevel (wbcg), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, _("Another view is already managing sheets")); go_gtk_dialog_run (GTK_DIALOG (dialog), wbcg_toplevel (wbcg)); return; } g_object_set_data (G_OBJECT (wb), SHEET_ORDER_KEY, (gpointer) gui); state = g_new0 (SheetManager, 1); state->gui = gui; state->wbcg = wbcg; state->dialog = go_gtk_builder_get_widget (gui, "sheet-order-dialog"); state->warning = go_gtk_builder_get_widget (gui, "warning"); state->up_btn = go_gtk_builder_get_widget (gui, "up_button"); state->down_btn = go_gtk_builder_get_widget (gui, "down_button"); state->add_btn = go_gtk_builder_get_widget (gui, "add_button"); state->append_btn = go_gtk_builder_get_widget (gui, "append_button"); state->duplicate_btn = go_gtk_builder_get_widget (gui, "duplicate_button"); state->delete_btn = go_gtk_builder_get_widget (gui, "delete_button"); state->apply_names_btn = go_gtk_builder_get_widget (gui, "ok_button"); state->sort_asc_btn = go_gtk_builder_get_widget (gui, "sort-asc-button"); state->sort_desc_btn = go_gtk_builder_get_widget (gui, "sort-desc-button"); state->undo_btn = go_gtk_builder_get_widget (gui, "undo-button"); state->cancel_btn = go_gtk_builder_get_widget (gui, "cancel_button"); state->advanced_check = go_gtk_builder_get_widget (gui, "advanced-check"); state->initial_colors_set = FALSE; state->image_padlock = go_gtk_widget_render_icon_pixbuf (widget, "gnumeric-protection-yes", GTK_ICON_SIZE_MENU); state->image_padlock_no = go_gtk_widget_render_icon_pixbuf (widget, "gnumeric-protection-no", GTK_ICON_SIZE_MENU); state->image_visible = go_gtk_widget_render_icon_pixbuf (widget, "gnumeric-visible", GTK_ICON_SIZE_MENU); state->image_ltr = go_gtk_widget_render_icon_pixbuf (widget, "format-text-direction-ltr", GTK_ICON_SIZE_MENU); state->image_rtl = go_gtk_widget_render_icon_pixbuf (widget, "format-text-direction-rtl", GTK_ICON_SIZE_MENU); /* Listen for changes in the sheet order. */ state->sheet_order_changed_listener = g_signal_connect (G_OBJECT (wb), "sheet_order_changed", G_CALLBACK (cb_sheet_order_changed), state); state->sheet_added_listener = g_signal_connect (G_OBJECT (wb), "sheet_added", G_CALLBACK (cb_sheet_added), state); state->sheet_deleted_listener = g_signal_connect (G_OBJECT (wb), "sheet_deleted", G_CALLBACK (cb_sheet_deleted), state); grid = GTK_GRID (go_gtk_builder_get_widget (gui,"main-grid")); cg = go_color_group_fetch ("back_color_group", wb_control_view (GNM_WBC (wbcg))); icon = go_gtk_widget_render_icon_pixbuf (widget, "gnumeric-bucket", GTK_ICON_SIZE_LARGE_TOOLBAR); state->ccombo_back = go_combo_color_new (icon, _("Default"), 0, cg); g_object_unref (icon); g_object_unref (cg); go_combo_color_set_instant_apply ( GO_COMBO_COLOR (state->ccombo_back), TRUE); gtk_grid_attach (grid, state->ccombo_back, 1, 4, 1, 1); gtk_widget_set_sensitive (state->ccombo_back, FALSE); cg = go_color_group_fetch ("fore_color_group", wb_control_view (GNM_WBC (wbcg))); icon = go_gtk_widget_render_icon_pixbuf (widget, "font", GTK_ICON_SIZE_LARGE_TOOLBAR); state->ccombo_fore = go_combo_color_new (icon, _("Default"), 0, cg); g_object_unref (icon); g_object_unref (cg); go_combo_color_set_instant_apply ( GO_COMBO_COLOR (state->ccombo_fore), TRUE); gtk_grid_attach (grid, state->ccombo_fore, 2, 4, 1, 1); gtk_widget_set_sensitive (state->ccombo_fore, FALSE); create_sheet_list (state); populate_sheet_list (state); #define CONNECT(o,s,c) g_signal_connect(G_OBJECT(o),s,G_CALLBACK(c),state) CONNECT (state->up_btn, "clicked", cb_up); CONNECT (state->down_btn, "clicked", cb_down); CONNECT (state->sort_asc_btn, "clicked", cb_asc); CONNECT (state->sort_desc_btn, "clicked", cb_desc); CONNECT (state->add_btn, "clicked", cb_add_clicked); CONNECT (state->append_btn, "clicked", cb_append_clicked); CONNECT (state->duplicate_btn, "clicked", cb_duplicate_clicked); CONNECT (state->delete_btn, "clicked", cb_delete_clicked); CONNECT (state->apply_names_btn, "clicked", cb_apply_names_clicked); CONNECT (state->cancel_btn, "clicked", cb_cancel_clicked); CONNECT (state->undo_btn, "clicked", cb_undo_clicked); CONNECT (state->advanced_check, "toggled", cb_adv_check_toggled); CONNECT (state->ccombo_back, "color_changed", cb_color_changed_back); CONNECT (state->ccombo_fore, "color_changed", cb_color_changed_fore); CONNECT (state->model, "rows-reordered", cb_dialog_order_changed); state->model_row_insertion_listener = CONNECT (state->model, "row-inserted", cb_dialog_order_changed_by_insertion); #undef CONNECT cb_adv_check_toggled (NULL, state); gnm_init_help_button ( go_gtk_builder_get_widget (state->gui, "help_button"), GNUMERIC_HELP_LINK_SHEET_MANAGER); gtk_widget_set_sensitive (state->undo_btn, wb->undo_commands != NULL); gtk_widget_set_sensitive (state->apply_names_btn, FALSE); /* a candidate for merging into attach guru */ wbc_gtk_attach_guru (state->wbcg, GTK_WIDGET (state->dialog)); g_object_set_data_full (G_OBJECT (state->dialog), "state", state, (GDestroyNotify) cb_sheet_order_destroy); g_signal_connect (G_OBJECT (state->dialog), "destroy", G_CALLBACK (destroy_cb), NULL); gnm_restore_window_geometry (GTK_WINDOW (state->dialog), SHEET_ORDER_KEY); go_gtk_nonmodal_dialog (wbcg_toplevel (state->wbcg), GTK_WINDOW (state->dialog)); gtk_widget_show_all (GTK_WIDGET (state->dialog)); }
/** * wbcg_edit_finish: * @wbcg: #WBCGtk * @result: what should we do with the content * @showed_dialog: If non-NULL will indicate if a dialog was displayed. * * Return: TRUE if editing completed successfully, or we were no editing. **/ gboolean wbcg_edit_finish (WBCGtk *wbcg, WBCEditResult result, gboolean *showed_dialog) { Sheet *sheet; SheetView *sv; WorkbookControl *wbc; WorkbookView *wbv; g_return_val_if_fail (GNM_IS_WBC_GTK (wbcg), FALSE); wbc = GNM_WBC (wbcg); wbv = wb_control_view (wbc); wbcg_focus_cur_scg (wbcg); gnm_expr_entry_close_tips (wbcg_get_entry_logical (wbcg)); if (showed_dialog != NULL) *showed_dialog = FALSE; /* Remove the range selection cursor if it exists */ if (NULL != wbcg->rangesel) scg_rangesel_stop (wbcg->rangesel, result == WBC_EDIT_REJECT); if (!wbcg_is_editing (wbcg)) { /* We may have a guru up even if we are not editing. remove it. * Do NOT remove until later it if we are editing, it is possible * that we may want to continue editing. */ if (wbcg->edit_line.guru != NULL) { GtkWidget *w = wbcg->edit_line.guru; wbc_gtk_detach_guru (wbcg); gtk_widget_destroy (w); } return TRUE; } g_return_val_if_fail (IS_SHEET (wbcg->editing_sheet), TRUE); sheet = wbcg->editing_sheet; sv = sheet_get_view (sheet, wbv); /* Save the results before changing focus */ if (result != WBC_EDIT_REJECT) { ValidationStatus valid = GNM_VALIDATION_STATUS_VALID; char *free_txt = NULL; char const *txt; GnmStyle const *mstyle; char const *expr_txt = NULL; GOFormat const *fmt; GnmValue *value; GOUndo *u = NULL; GSList *selection = selection_get_ranges (sv, FALSE); GnmParsePos pp; GnmExprTop const *texpr = NULL; parse_pos_init_editpos (&pp, sv); /* Array only works on single range. */ if (result == WBC_EDIT_ACCEPT_ARRAY && (selection == NULL || selection->next != NULL)) result = WBC_EDIT_ACCEPT_RANGE; /******* Check whether we would split a range ********/ switch (result) { case (WBC_EDIT_ACCEPT_RANGE): case (WBC_EDIT_ACCEPT_ARRAY): { if (sheet_ranges_split_region (sheet, selection, GO_CMD_CONTEXT (wbc), _("Set Text"))) { range_fragment_free (selection); if (showed_dialog != NULL) *showed_dialog = TRUE; return FALSE; } if (result == WBC_EDIT_ACCEPT_ARRAY && sheet_range_contains_merges_or_arrays (sheet, selection->data, GO_CMD_CONTEXT (wbc), _("Set Text"), TRUE, FALSE)) { range_fragment_free (selection); if (showed_dialog != NULL) *showed_dialog = TRUE; return FALSE; } break; } case (WBC_EDIT_ACCEPT_WO_AC): case (WBC_EDIT_ACCEPT): { GnmCell const *cell = sheet_cell_get (sheet, sv->edit_pos.col, sv->edit_pos.row); if (gnm_cell_is_nonsingleton_array (cell)) { gnm_cmd_context_error_splits_array (GO_CMD_CONTEXT (wbc), _("Set Text"), NULL); if (showed_dialog != NULL) *showed_dialog = TRUE; range_fragment_free (selection); return FALSE; } break; } case (WBC_EDIT_REJECT): default: /* We should not be able to get here! */ break; } /******* Check whether the range is locked ********/ switch (result) { case (WBC_EDIT_ACCEPT_RANGE): case (WBC_EDIT_ACCEPT_ARRAY): { if (cmd_selection_is_locked_effective (sheet, selection, wbc, _("Set Text"))) { range_fragment_free (selection); if (showed_dialog != NULL) *showed_dialog = TRUE; return FALSE; } break; } case (WBC_EDIT_ACCEPT_WO_AC): case (WBC_EDIT_ACCEPT): { GnmRange r; r.end = r.start = pp.eval; if (cmd_cell_range_is_locked_effective (sheet, &r, wbc, _("Set Text"))) { range_fragment_free (selection); if (showed_dialog != NULL) *showed_dialog = TRUE; return FALSE; } break; } case (WBC_EDIT_REJECT): default: /* We should not be able to get here! */ break; } /*****************************************************/ txt = wbcg_edit_get_display_text (wbcg); mstyle = sheet_style_get (sheet, sv->edit_pos.col, sv->edit_pos.row); fmt = gnm_cell_get_format (sheet_cell_fetch (sheet, sv->edit_pos.col, sv->edit_pos.row)); value = format_match (txt, fmt, workbook_date_conv (sheet->workbook)); if (value == NULL) expr_txt = gnm_expr_char_start_p (txt); else value_release (value); /* NOTE : do not modify gnm_expr_char_start_p to exclude "-" * it _can_ start an expression, which is required for rangesel * it just isn't an expression. */ if (expr_txt != NULL && *expr_txt != '\0' && strcmp (expr_txt, "-")) { GnmExprTop const *texpr_test = NULL; GnmParseError perr; parse_error_init (&perr); texpr_test = gnm_expr_parse_str (expr_txt, &pp, GNM_EXPR_PARSE_DEFAULT, NULL, &perr); /* Try adding a single extra closing paren to see if it helps */ if (texpr_test == NULL && perr.err != NULL && perr.err->code == PERR_MISSING_PAREN_CLOSE) { GnmParseError tmp_err; char *tmp = g_strconcat (txt, ")", NULL); parse_error_init (&tmp_err); texpr_test = gnm_expr_parse_str (gnm_expr_char_start_p (tmp), &pp, GNM_EXPR_PARSE_DEFAULT, NULL, &tmp_err); parse_error_free (&tmp_err); if (texpr_test != NULL) { txt = free_txt = tmp; expr_txt = gnm_expr_char_start_p (txt); } else g_free (tmp); } if (texpr_test == NULL && perr.err != NULL) { ValidationStatus reedit; /* set focus _before_ selection. gtk2 seems to * screw with selection in gtk_entry_grab_focus * (no longer required now that we clear * gtk-entry-select-on-focus) */ gtk_window_set_focus (wbcg_toplevel (wbcg), (GtkWidget *) wbcg_get_entry (wbcg)); if (perr.begin_char != 0 || perr.end_char != 0) { int offset = expr_txt - txt; gtk_editable_select_region (GTK_EDITABLE (wbcg_get_entry (wbcg)), offset + perr.begin_char, offset + perr.end_char); } else gtk_editable_set_position ( GTK_EDITABLE (wbcg_get_entry (wbcg)), -1); reedit = wb_control_validation_msg (GNM_WBC (wbcg), GNM_VALIDATION_STYLE_PARSE_ERROR, NULL, perr.err->message); if (showed_dialog != NULL) *showed_dialog = TRUE; parse_error_free (&perr); if (reedit == GNM_VALIDATION_STATUS_INVALID_EDIT) { range_fragment_free (selection); return FALSE; } /* restore focus to sheet , or we'll leave edit * mode only to jump right back in the new * cell because it looks like someone just * focused on the edit line (eg hit F2) */ wbcg_focus_cur_scg (wbcg); } if (texpr_test != NULL) gnm_expr_top_unref (texpr_test); } /* We only enter an array formula if the text is a formula */ if (result == WBC_EDIT_ACCEPT_ARRAY && !expr_txt) result = WBC_EDIT_ACCEPT_RANGE; if (result == WBC_EDIT_ACCEPT_ARRAY) { GnmParsePos pp_array; GnmRange *r = selection->data; parse_pos_init (&pp_array, sheet->workbook, sheet, r->start.col, r->start.row); if ((texpr = gnm_expr_parse_str (expr_txt, &pp_array, GNM_EXPR_PARSE_DEFAULT, sheet_get_conventions (sheet), NULL)) == NULL) result = WBC_EDIT_ACCEPT_RANGE; } /* We need to save the information that we will temporarily overwrite */ /* We then assign the information. No need to worry about formatting */ /* Finally we can check the validation! */ switch (result) { case (WBC_EDIT_ACCEPT_RANGE): { GSList *l; for (l = selection; l != NULL; l = l->next) { GnmRange *r = l->data; u = go_undo_combine (u, clipboard_copy_range_undo (sheet, r)); } for (l = selection; l != NULL; l = l->next) { GnmRange *r = l->data; /* We do this separately since there may be overlap between ranges */ sheet_range_set_text (&pp, r, txt); valid = gnm_validation_eval_range (wbc, sheet, &sv->edit_pos, r, showed_dialog); if (valid != GNM_VALIDATION_STATUS_VALID) break; } break; } case (WBC_EDIT_ACCEPT_ARRAY): { GnmRange *r = selection->data; u = go_undo_combine (u, clipboard_copy_range_undo (sheet, r)); if (texpr) { gnm_expr_top_ref (texpr); gnm_cell_set_array_formula (sheet, r->start.col, r->start.row, r->end.col, r->end.row, texpr); sheet_region_queue_recalc (sheet, r); } valid = gnm_validation_eval_range (wbc, sheet, &sv->edit_pos, r, showed_dialog); break; } case (WBC_EDIT_ACCEPT_WO_AC): case (WBC_EDIT_ACCEPT): { GnmRange r; GnmCell *cell; range_init_cellpos (&r, &sv->edit_pos); u = clipboard_copy_range_undo (sheet, &r); cell = sheet_cell_fetch (sheet, sv->edit_pos.col, sv->edit_pos.row); sheet_cell_set_text (cell, txt, wbcg->edit_line.markup); valid = gnm_validation_eval (wbc, mstyle, sheet, &sv->edit_pos, showed_dialog); break; } case (WBC_EDIT_REJECT): default: /* We should not be able to get here! */ break; } range_fragment_free (selection); /* We need to rebuild the original info first. */ go_undo_undo (u); g_object_unref (u); /* Now we can respond to our validation information */ if (valid != GNM_VALIDATION_STATUS_VALID) { result = WBC_EDIT_REJECT; if (valid == GNM_VALIDATION_STATUS_INVALID_EDIT) { gtk_window_set_focus (wbcg_toplevel (wbcg), (GtkWidget *) wbcg_get_entry (wbcg)); g_free (free_txt); if (texpr != NULL) gnm_expr_top_unref (texpr); return FALSE; } } else { if (result == WBC_EDIT_ACCEPT_ARRAY) { cmd_area_set_array_expr (wbc, sv, texpr); } else { PangoAttrList *res_markup = wbcg->edit_line.markup ? pango_attr_list_copy (wbcg->edit_line.markup) : NULL; if (result == WBC_EDIT_ACCEPT) cmd_set_text (wbc, sheet, &sv->edit_pos, txt, res_markup, TRUE); else if (result == WBC_EDIT_ACCEPT_WO_AC) cmd_set_text (wbc, sheet, &sv->edit_pos, txt, res_markup, FALSE); else cmd_area_set_text (wbc, sv, txt, res_markup); if (res_markup) pango_attr_list_unref (res_markup); } } if (texpr != NULL) gnm_expr_top_unref (texpr); g_free (free_txt); } else { if (sv == wb_control_cur_sheet_view (wbc)) { /* Redraw the cell contents in case there was a span */ GnmRange tmp; tmp.start = tmp.end = sv->edit_pos; sheet_range_bounding_box (sv->sheet, &tmp); sv_redraw_range (wb_control_cur_sheet_view (wbc), &tmp); } /* Reload the entry widget with the original contents */ wb_view_edit_line_set (wbv, wbc); } /* Stop editing */ wbcg->editing = FALSE; wbcg->editing_sheet = NULL; wbcg->editing_cell = NULL; if (wbcg->edit_line.guru != NULL) { GtkWidget *w = wbcg->edit_line.guru; wbc_gtk_detach_guru (wbcg); gtk_widget_destroy (w); } if (wbcg->edit_line.signal_insert) { g_signal_handler_disconnect (wbcg_get_entry (wbcg), wbcg->edit_line.signal_insert); wbcg->edit_line.signal_insert = 0; } if (wbcg->edit_line.signal_delete) { g_signal_handler_disconnect (wbcg_get_entry (wbcg), wbcg->edit_line.signal_delete); wbcg->edit_line.signal_delete = 0; } if (wbcg->edit_line.signal_cursor_pos) { g_signal_handler_disconnect (wbcg_get_entry (wbcg), wbcg->edit_line.signal_cursor_pos); wbcg->edit_line.signal_cursor_pos = 0; } if (wbcg->edit_line.signal_selection_bound) { g_signal_handler_disconnect (wbcg_get_entry (wbcg), wbcg->edit_line.signal_selection_bound); wbcg->edit_line.signal_selection_bound = 0; } if (wbcg->edit_line.cell_attrs != NULL) { pango_attr_list_unref (wbcg->edit_line.cell_attrs); wbcg->edit_line.cell_attrs = NULL; } if (wbcg->edit_line.markup) { pango_attr_list_unref (wbcg->edit_line.markup); wbcg->edit_line.markup = NULL; } if (wbcg->edit_line.full_content != NULL) { pango_attr_list_unref (wbcg->edit_line.full_content); wbcg->edit_line.full_content = NULL; } if (wbcg->edit_line.cur_fmt) { pango_attr_list_unref (wbcg->edit_line.cur_fmt); wbcg->edit_line.cur_fmt = NULL; } /* set pos to 0, to ensure that if we start editing by clicking on the * editline at the last position, we'll get the right style feedback */ gtk_editable_set_position ((GtkEditable *) wbcg_get_entry (wbcg), 0); wb_control_update_action_sensitivity (wbc); if (!sheet->workbook->during_destruction) { /* restore focus to original sheet in case things were being selected * on a different page. Do no go through the view, rangesel is * specific to the control. */ wb_control_sheet_focus (wbc, sheet); /* Only the edit sheet has an edit cursor */ scg_edit_stop (wbcg_cur_scg (wbcg)); } wbcg_auto_complete_destroy (wbcg); wb_control_style_feedback (wbc, NULL); /* in case markup messed with things */ return TRUE; }
/** * wbcg_edit_start: * @wbcg: The workbook to be edited. * @blankp: If true, erase current cell contents first. If false, leave the * contents alone. * @cursorp: If true, create an editing cursor in the current sheet. (If * false, the text will be editing in the edit box above the sheet, * but this is not handled by this function.) * * Initiate editing of a cell in the sheet. Note that we have two modes of * editing: * 1) in-cell editing when you just start typing, and * 2) above sheet editing when you hit F2. * * Returns TRUE if we did indeed start editing. Returns FALSE if the * cell-to-be-edited was locked. */ gboolean wbcg_edit_start (WBCGtk *wbcg, gboolean blankp, gboolean cursorp) { /* We could save this, but the situation is rare, if confusing. */ static gboolean warn_on_text_format = TRUE; SheetView *sv; SheetControlGUI *scg; GnmCell *cell; char *text = NULL; int col, row; WorkbookView *wbv; int cursor_pos = -1; g_return_val_if_fail (GNM_IS_WBC_GTK (wbcg), FALSE); if (wbcg_is_editing (wbcg)) return TRUE; /* Avoid recursion, and do not begin editing if a guru is up */ if (wbcg->inside_editing || wbc_gtk_get_guru (wbcg) != NULL) return TRUE; wbcg->inside_editing = TRUE; wbv = wb_control_view (GNM_WBC (wbcg)); sv = wb_control_cur_sheet_view (GNM_WBC (wbcg)); scg = wbcg_cur_scg (wbcg); col = sv->edit_pos.col; row = sv->edit_pos.row; /* don't edit a locked cell */ /* TODO : extend this to disable edits that cannot succeed * like editing a single cell of an array. I think we have enough * information if we look at the selection. */ if (wb_view_is_protected (wbv, TRUE) && gnm_style_get_contents_locked (sheet_style_get (sv->sheet, col, row))) { char *pos = g_strdup_printf ( _("%s!%s is locked"), sv->sheet->name_quoted, cell_coord_name (col, row)); go_cmd_context_error_invalid (GO_CMD_CONTEXT (wbcg), pos, wb_view_is_protected (wbv, FALSE) ? _("Unprotect the workbook to enable editing.") : _("Unprotect the sheet to enable editing.")); wbcg->inside_editing = FALSE; g_free (pos); return FALSE; } cell = sheet_cell_get (sv->sheet, col, row); if (cell && warn_on_text_format && go_format_is_text (gnm_cell_get_format (cell)) && (gnm_cell_has_expr (cell) || !VALUE_IS_STRING (cell->value))) { gint res; /* Using GtkResponseType would yield a warning on the switch */ GtkWidget *check; GtkWidget *align; GtkWidget *d = gnm_message_dialog_create (wbcg_toplevel (wbcg), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, _("You are about to edit a cell with \"text\" format."), _("The cell does not currently contain text, though, so if " "you go on editing then the contents will be turned into " "text.")); gtk_dialog_add_button (GTK_DIALOG (d), GTK_STOCK_EDIT, GTK_RESPONSE_OK); go_gtk_dialog_add_button (GTK_DIALOG (d), _("Remove format"), GTK_STOCK_REMOVE, GNM_RESPONSE_REMOVE); gtk_dialog_add_button (GTK_DIALOG (d), GNM_STOCK_CANCEL, GTK_RESPONSE_CANCEL); gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_CANCEL); check = gtk_check_button_new_with_label (_("Show this dialog next time.")); g_signal_connect (check, "toggled", G_CALLBACK (cb_warn_toggled), &warn_on_text_format); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), TRUE); align = gtk_alignment_new (0.5, 0.5, 0, 0); gtk_container_add (GTK_CONTAINER (align), check); gtk_widget_show_all (align); gtk_box_pack_end (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (d))), align, TRUE, TRUE, 0); res = go_gtk_dialog_run (GTK_DIALOG (d), wbcg_toplevel (wbcg)); switch (res) { case GNM_RESPONSE_REMOVE: { GnmStyle *style = gnm_style_new (); gnm_style_set_format (style, go_format_general ()); if (!cmd_selection_format (GNM_WBC (wbcg), style, NULL, NULL)) break; /* Fall through. */ } default: case GTK_RESPONSE_CANCEL: wbcg->inside_editing = FALSE; return FALSE; case GTK_RESPONSE_OK: break; } } gnm_app_clipboard_unant (); if (blankp) gtk_entry_set_text (wbcg_get_entry (wbcg), ""); else if (cell != NULL) { gboolean quoted = FALSE; text = gnm_cell_get_text_for_editing (cell, sv->sheet, "ed, &cursor_pos); if (text) gtk_entry_set_text (wbcg_get_entry (wbcg), text); if (cell->value != NULL) { GOFormat const *fmt = VALUE_FMT (cell->value); if (fmt != NULL && go_format_is_markup (fmt)) { PangoAttrList *markup = pango_attr_list_copy ((PangoAttrList *)go_format_get_markup (fmt)); if (quoted) go_pango_attr_list_open_hole (markup, 0, 1); wbcg_edit_init_markup (wbcg, markup); } } } gnm_expr_entry_set_scg (wbcg->edit_line.entry, scg); gnm_expr_entry_set_flags (wbcg->edit_line.entry, GNM_EE_SHEET_OPTIONAL | GNM_EE_FORMULA_ONLY, GNM_EE_SINGLE_RANGE | GNM_EE_SHEET_OPTIONAL | GNM_EE_FORMULA_ONLY | GNM_EE_FORCE_REL_REF | GNM_EE_FORCE_ABS_REF); scg_edit_start (scg); /* Redraw the cell contents in case there was a span */ sheet_redraw_region (sv->sheet, col, row, col, row); if (cursorp && /* autocompletion code will not work in the edit line */ wbv->do_auto_completion && (text == NULL || g_unichar_isalpha (g_utf8_get_char (text)))) { wbcg->auto_complete = gnm_complete_sheet_new ( sv->sheet, col, row, workbook_edit_complete_notify, wbcg); wbcg->auto_completing = TRUE; wbcg->auto_max_size = 0; } else wbcg->auto_complete = NULL; /* Give the focus to the edit line */ if (!cursorp) gtk_window_set_focus (wbcg_toplevel (wbcg), (GtkWidget *) wbcg_get_entry (wbcg)); wbcg->editing = TRUE; wbcg->editing_sheet = sv->sheet; wbcg->editing_cell = cell; /* If this assert fails, it means editing was not shut down * properly before */ g_return_val_if_fail (wbcg->edit_line.signal_changed == 0, TRUE); wbcg->edit_line.signal_changed = g_signal_connect ( G_OBJECT (wbcg_get_entry (wbcg)), "changed", G_CALLBACK (cb_entry_changed), wbcg); wbcg->edit_line.signal_insert = g_signal_connect ( G_OBJECT (wbcg_get_entry (wbcg)), "insert-text", G_CALLBACK (cb_entry_insert_text), wbcg); wbcg->edit_line.signal_delete = g_signal_connect ( G_OBJECT (wbcg_get_entry (wbcg)), "delete-text", G_CALLBACK (cb_entry_delete_text), wbcg); wbcg->edit_line.signal_cursor_pos = g_signal_connect_swapped ( G_OBJECT (wbcg_get_entry (wbcg)), "notify::cursor-position", G_CALLBACK (cb_entry_cursor_pos), wbcg); wbcg->edit_line.signal_selection_bound = g_signal_connect_swapped ( G_OBJECT (wbcg_get_entry (wbcg)), "notify::selection-bound", G_CALLBACK (cb_entry_cursor_pos), wbcg); g_free (text); wb_control_update_action_sensitivity (GNM_WBC (wbcg)); wbcg->inside_editing = FALSE; gtk_editable_set_position (GTK_EDITABLE (wbcg_get_entry (wbcg)), cursor_pos); return TRUE; }