static void html_write_border_style_40_for_merged_cell (GsfOutput *output, GnmStyle const *style, Sheet *sheet, gint row, gint col) { GnmBorder *border; GnmRange const *merge_range; GnmCellPos pos; pos.col = col; pos.row = row; border = gnm_style_get_border (style, MSTYLE_BORDER_TOP); if (!gnm_style_border_is_blank (border)) html_write_one_border_style_40 (output, border, "border-top"); border = gnm_style_get_border (style, MSTYLE_BORDER_LEFT); if (!gnm_style_border_is_blank (border)) html_write_one_border_style_40 (output, border, "border-left"); merge_range = gnm_sheet_merge_contains_pos (sheet, &pos); if (merge_range != NULL) { style = sheet_style_get (sheet, merge_range->end.col, merge_range->end.row); if (style == NULL) return; } border = gnm_style_get_border (style, MSTYLE_BORDER_BOTTOM); if (!gnm_style_border_is_blank (border)) html_write_one_border_style_40 (output, border, "border-bottom"); border = gnm_style_get_border (style, MSTYLE_BORDER_RIGHT); if (!gnm_style_border_is_blank (border)) html_write_one_border_style_40 (output, border, "border-right"); }
/* * write_row: * * @output: the stream * @sheet: the gnumeric sheet * @row: the row number * */ static void write_row (GsfOutput *output, Sheet *sheet, gint row, GnmRange *range) { char const *text = NULL; char *formatted_string = NULL; GnmCell *cell; GnmStyle const *style; GODateConventions const *date_conv = sheet->workbook ? workbook_date_conv (sheet->workbook) : NULL; gint col; for (col = range->start.col; col <= range->end.col; col++) { GnmRange const *merge_range; GnmCellPos pos; pos.col = col; pos.row = row; merge_range = gnm_sheet_merge_contains_pos (sheet, &pos); if (merge_range != NULL) { /* If cell is inside a merged region, we use the corner cell of the merged region: */ cell = sheet_cell_get (sheet, merge_range->start.col, merge_range->start.row); } else { cell = sheet_cell_get (sheet, col, row); } if (cell != NULL && cell->value) { text = value_peek_string (cell->value); pwcsv_print_encoded (output, text); style = sheet_style_get (sheet, col, row); GOFormat const *format = gnm_style_get_format (style); // set col_width to 16-something. This works around gnumeric quirk // where, in wider cells, it formats 9,3 as 9,300000000000001 formatted_string = format_value (format, cell->value, 16, date_conv); pwcsv_print_encoded (output, formatted_string); html_write_cell_content (output, cell, style, formatted_string); g_free (formatted_string); /* Without this, we're accumulating lots of heap memory on big spreadsheets. */ gnm_cell_unrender(cell); } else { gsf_output_puts (output, ",,,"); } } gsf_output_puts (output, "\n"); }
static void thrash_scroll (Sheet *sheet) { int i; for (i = 0; i < SCREEN_SLIDES * SCREEN_INCR; i += SCREEN_INCR) { int j; for (j = 0; j < SCREEN_HEIGHT; j++) { int k; for (k = 0; k < SCREEN_WIDTH; k++) { GnmStyle const *style; style = sheet_style_get (sheet, k, i + j); } } } }
static void wbcg_edit_init_markup (WBCGtk *wbcg, PangoAttrList *markup) { SheetView const *sv; char const *text; GnmStyle const *style; g_return_if_fail (wbcg->edit_line.full_content == NULL); wbcg->edit_line.markup = markup; sv = wb_control_cur_sheet_view (GNM_WBC (wbcg)); style = sheet_style_get (sv->sheet, sv->edit_pos.col, sv->edit_pos.row); wbcg->edit_line.cell_attrs = gnm_style_generate_attrs_full (style); wbcg->edit_line.full_content = pango_attr_list_copy (wbcg->edit_line.cell_attrs); pango_attr_list_splice (wbcg->edit_line.full_content, markup, 0, 0); text = gtk_entry_get_text (wbcg_get_entry (wbcg)); set_cur_fmt (wbcg, strlen (text) - 1); }
static GnmValue * validation_eval_range_cb (GnmCellIter const *iter, validation_eval_t *closure) { ValidationStatus status; gboolean showed_dialog; GnmStyle const *mstyle = sheet_style_get (closure->sheet, iter->pp.eval.col, iter->pp.eval.row); if (mstyle != NULL) { status = gnm_validation_eval (closure->wbc, mstyle, closure->sheet, &iter->pp.eval, &showed_dialog); if (closure->showed_dialog) *closure->showed_dialog = *closure->showed_dialog || showed_dialog; if (status != GNM_VALIDATION_STATUS_VALID) { closure->status = status; return VALUE_TERMINATE; } } return NULL; }
/* * cell_calc_span: * @cell: The cell we will examine * @col1: return value: the first column used by this cell * @col2: return value: the last column used by this cell * * This routine returns the column interval used by a GnmCell. */ void cell_calc_span (GnmCell const *cell, int *col1, int *col2) { Sheet *sheet; int h_align, v_align, left, max_col, min_col; int row, pos; int cell_width_pixel, indented_w; GnmStyle const *style; ColRowInfo const *ci; GnmRange const *merge_left; GnmRange const *merge_right; g_return_if_fail (cell != NULL); sheet = cell->base.sheet; style = gnm_cell_get_style (cell); h_align = gnm_style_default_halign (style, cell); /* * Report only one column is used if * - Cell is in a hidden col * - Cell is a number * - Cell is the top left of a merged cell * - The text fits inside column (for non center across selection) * - The alignment mode are set to "justify" */ if (sheet != NULL && h_align != HALIGN_CENTER_ACROSS_SELECTION && (gnm_cell_is_merged (cell) || (!sheet->display_formulas && gnm_cell_is_number (cell)))) { *col1 = *col2 = cell->pos.col; return; } v_align = gnm_style_get_align_v (style); row = cell->pos.row; indented_w = cell_width_pixel = gnm_cell_rendered_width (cell); if (h_align == HALIGN_LEFT || h_align == HALIGN_RIGHT) { indented_w += gnm_cell_rendered_offset (cell); if (sheet->text_is_rtl) h_align = (h_align == HALIGN_LEFT) ? HALIGN_RIGHT : HALIGN_LEFT; } ci = sheet_col_get_info (sheet, cell->pos.col); if (gnm_cell_is_empty (cell) || !ci->visible || (h_align != HALIGN_CENTER_ACROSS_SELECTION && (gnm_style_get_wrap_text (style) || indented_w <= COL_INTERNAL_WIDTH (ci))) || h_align == HALIGN_JUSTIFY || h_align == HALIGN_FILL || h_align == HALIGN_DISTRIBUTED || v_align == VALIGN_JUSTIFY || v_align == VALIGN_DISTRIBUTED) { *col1 = *col2 = cell->pos.col; return; } gnm_sheet_merge_get_adjacent (sheet, &cell->pos, &merge_left, &merge_right); min_col = (merge_left != NULL) ? merge_left->end.col : -1; max_col = (merge_right != NULL) ? merge_right->start.col : gnm_sheet_get_max_cols (sheet); *col1 = *col2 = cell->pos.col; switch (h_align) { case HALIGN_LEFT: pos = cell->pos.col + 1; left = indented_w - COL_INTERNAL_WIDTH (ci); for (; left > 0 && pos < max_col; pos++){ ColRowInfo const *ci = sheet_col_get_info (sheet, pos); if (ci->visible) { if (!cellspan_is_empty (pos, cell)) return; /* The space consumed is: * - The margin_b from the last column * - The width of the cell */ left -= ci->size_pixels - 1; *col2 = pos; } } return; case HALIGN_RIGHT: pos = cell->pos.col - 1; left = indented_w - COL_INTERNAL_WIDTH (ci); for (; left > 0 && pos > min_col; pos--){ ColRowInfo const *ci = sheet_col_get_info (sheet, pos); if (ci->visible) { if (!cellspan_is_empty (pos, cell)) return; /* The space consumed is: * - The margin_a from the last column * - The width of this cell */ left -= ci->size_pixels - 1; *col1 = pos; } } return; case HALIGN_CENTER: { int remain_left, remain_right; int pos_l, pos_r; pos_l = pos_r = cell->pos.col; left = cell_width_pixel - COL_INTERNAL_WIDTH (ci); remain_left = left / 2 + (left % 2); remain_right = left / 2; for (; remain_left > 0 || remain_right > 0;){ ColRowInfo const *ci; if (--pos_l > min_col){ ci = sheet_col_get_info (sheet, pos_l); if (ci->visible) { if (cellspan_is_empty (pos_l, cell)) { remain_left -= ci->size_pixels - 1; *col1 = pos_l; } else remain_left = 0; } } else remain_left = 0; if (++pos_r < max_col){ ci = sheet_col_get_info (sheet, pos_r); if (ci->visible) { if (cellspan_is_empty (pos_r, cell)) { remain_right -= ci->size_pixels - 1; *col2 = pos_r; } else max_col = remain_right = 0; } } else remain_right = 0; } /* for */ break; } /* case HALIGN_CENTER */ case HALIGN_CENTER_ACROSS_SELECTION: { int const row = cell->pos.row; int pos_l, pos_r; pos_l = pos_r = cell->pos.col; while (--pos_l > min_col) { ColRowInfo const *ci = sheet_col_get_info (sheet, pos_l); if (ci->visible) { if (cellspan_is_empty (pos_l, cell)) { GnmStyle const * const style = sheet_style_get (cell->base.sheet, pos_l, row); if (gnm_style_get_align_h (style) != HALIGN_CENTER_ACROSS_SELECTION) break; *col1 = pos_l; } else break; } } while (++pos_r < max_col) { ColRowInfo const *ci = sheet_col_get_info (sheet, pos_r); if (ci->visible) { if (cellspan_is_empty (pos_r, cell)) { GnmStyle const * const style = sheet_style_get (cell->base.sheet, pos_r, row); if (gnm_style_get_align_h (style) != HALIGN_CENTER_ACROSS_SELECTION) break; *col2 = pos_r; } else break; } } break; } default: g_warning ("Unknown horizontal alignment type %x.", h_align); } /* switch */ }
static void write_cell (GsfOutput *output, Sheet *sheet, gint row, gint col, html_version_t version, gboolean is_merge) { GnmCell *cell; GnmStyle const *style; guint r, g, b; style = sheet_style_get (sheet, col, row); if (style != NULL && version != HTML32 && version != HTML40 && gnm_style_get_pattern (style) != 0 && gnm_style_is_element_set (style, MSTYLE_COLOR_BACK)) { html_get_back_color (style, &r, &g, &b); gsf_output_printf (output, " bgcolor=\"#%02X%02X%02X\"", r, g, b); } cell = sheet_cell_get (sheet, col, row); if (cell != NULL) { switch (gnm_style_get_align_v (style)) { case GNM_VALIGN_TOP: gsf_output_puts (output, " valign=\"top\" "); break; case GNM_VALIGN_BOTTOM: gsf_output_puts (output, " valign=\"bottom\" "); break; case GNM_VALIGN_DISTRIBUTED: case GNM_VALIGN_CENTER: gsf_output_puts (output, " valign=\"center\" "); break; case GNM_VALIGN_JUSTIFY: gsf_output_puts (output, " valign=\"baseline\" "); break; default: break; } switch (gnm_style_default_halign (style, cell)) { case GNM_HALIGN_RIGHT: gsf_output_puts (output, " align=\"right\" "); break; case GNM_HALIGN_DISTRIBUTED: case GNM_HALIGN_CENTER: case GNM_HALIGN_CENTER_ACROSS_SELECTION: gsf_output_puts (output, " align=\"center\" "); break; case GNM_HALIGN_LEFT: gsf_output_puts (output, " align=\"left\" "); break; case GNM_HALIGN_JUSTIFY: gsf_output_puts (output, " align=\"justify\" "); break; default: break; } } if (version == HTML40 || version == HTML40F || version ==XHTML) { if (style != NULL) { gsf_output_printf (output, " style=\""); if (gnm_style_get_pattern (style) != 0 && gnm_style_is_element_set (style, MSTYLE_COLOR_BACK)) { html_get_back_color (style, &r, &g, &b); gsf_output_printf (output, "background:#%02X%02X%02X;", r, g, b); } if (cell != NULL) { gint size = (int) (gnm_style_get_font_size (style) + 0.5); gsf_output_printf (output, " font-size:%ipt;", size); html_get_text_color (cell, style, &r, &g, &b); if (r > 0 || g > 0 || b > 0) gsf_output_printf (output, " color:#%02X%02X%02X;", r, g, b); if (gnm_style_get_contents_hidden (style)) gsf_output_puts (output, " visibility:hidden;"); } if (is_merge) html_write_border_style_40_for_merged_cell (output, style, sheet, row, col); else html_write_border_style_40 (output, style); gsf_output_printf (output, "\""); } } gsf_output_printf (output, ">"); html_write_cell_content (output, cell, style, version); gsf_output_puts (output, "</td>\n"); }
/** * 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; }
static gboolean item_grid_draw_region (GocItem const *item, cairo_t *cr, double x_0, double y_0, double x_1, double y_1) { GocCanvas *canvas = item->canvas; double scale = canvas->pixels_per_unit; gint64 x0 = x_0 * scale, y0 = y_0 * scale, x1 = x_1 * scale, y1 = y_1 * scale; gint width = x1 - x0; gint height = y1 - y0; GnmPane *pane = GNM_PANE (canvas); Sheet const *sheet = scg_sheet (pane->simple.scg); WBCGtk *wbcg = scg_wbcg (pane->simple.scg); GnmCell const * const edit_cell = wbcg->editing_cell; GnmItemGrid *ig = GNM_ITEM_GRID (item); ColRowInfo const *ri = NULL, *next_ri = NULL; int const dir = sheet->text_is_rtl ? -1 : 1; SheetView const *sv = scg_view (ig->scg); WorkbookView *wbv = sv_wbv (sv); gboolean show_function_cell_markers = wbv->show_function_cell_markers; gboolean show_extension_markers = wbv->show_extension_markers; /* we use the selected background color fromĀ an entry for selected cells */ GtkWidget *entry = gtk_entry_new (); GtkStyleContext *ctxt = gtk_widget_get_style_context (entry); /* To ensure that far and near borders get drawn we pretend to draw +-2 * pixels around the target area which would include the surrounding * borders if necessary */ /* TODO : there is an opportunity to speed up the redraw loop by only * painting the borders of the edges and not the content. * However, that feels like more hassle that it is worth. Look into this someday. */ int x; gint64 y, start_x, offset; int col, row, n, start_col, end_col; int start_row = gnm_pane_find_row (pane, y0-2, &y); int end_row = gnm_pane_find_row (pane, y1+2, NULL); gint64 const start_y = y - canvas->scroll_y1 * scale; GnmStyleRow sr, next_sr; GnmStyle const **styles; GnmBorder const **borders, **prev_vert; GnmBorder const *none = sheet->hide_grid ? NULL : gnm_style_border_none (); GnmRange view; GSList *merged_active, *merged_active_seen, *merged_used, *merged_unused, *ptr, **lag; int *colwidths = NULL; gboolean const draw_selection = ig->scg->selected_objects == NULL && wbcg->new_object == NULL; start_col = gnm_pane_find_col (pane, x0-2, &start_x); end_col = gnm_pane_find_col (pane, x1+2, NULL); g_return_val_if_fail (start_col <= end_col, TRUE); #if 0 g_printerr ("%s:", cell_coord_name (start_col, start_row)); g_printerr ("%s <= %ld vs ???", cell_coord_name(end_col, end_row), (long)y); g_printerr (" [%s]\n", cell_coord_name (ig->bound.end.col, ig->bound.end.row)); #endif /* clip to bounds */ if (end_col > ig->bound.end.col) end_col = ig->bound.end.col; if (end_row > ig->bound.end.row) end_row = ig->bound.end.row; /* Skip any hidden cols/rows at the start */ for (; start_col <= end_col ; ++start_col) { ri = sheet_col_get_info (sheet, start_col); if (ri->visible) break; } for (; start_row <= end_row ; ++start_row) { ri = sheet_row_get_info (sheet, start_row); if (ri->visible) break; } /* if everything is hidden no need to draw */ if (end_col < ig->bound.start.col || start_col > ig->bound.end.col || end_row < ig->bound.start.row || start_row > ig->bound.end.row) return TRUE; /* Respan all rows that need it. */ for (row = start_row; row <= end_row; row++) { ColRowInfo const *ri = sheet_row_get_info (sheet, row); if (ri->visible && ri->needs_respan) row_calc_spans ((ColRowInfo *)ri, row, sheet); } sheet_style_update_grid_color (sheet); /* Fill entire region with default background (even past far edge) */ cairo_save (cr); if (canvas->direction == GOC_DIRECTION_LTR) gtk_render_background (goc_item_get_style_context (item), cr, x0 - canvas->scroll_x1 * scale, y0 - canvas->scroll_y1 * scale, width, height); else gtk_render_background (goc_item_get_style_context (item), cr, canvas->width - x0 + canvas->scroll_x1 * scale - width, y0 - canvas->scroll_y1 * scale, width, height); cairo_restore (cr); /* Get ordered list of merged regions */ merged_active = merged_active_seen = merged_used = NULL; merged_unused = gnm_sheet_merge_get_overlap (sheet, range_init (&view, start_col, start_row, end_col, end_row)); /* * allocate a single blob of memory for all 8 arrays of pointers. * - 6 arrays of n GnmBorder const * * - 2 arrays of n GnmStyle const * * * then alias the arrays for easy access so that array [col] is valid * for all elements start_col-1 .. end_col+1 inclusive. * Note that this means that in some cases array [-1] is legal. */ n = end_col - start_col + 3; /* 1 before, 1 after, 1 fencepost */ style_row_init (&prev_vert, &sr, &next_sr, start_col, end_col, g_alloca (n * 8 * sizeof (gpointer)), sheet->hide_grid); /* load up the styles for the first row */ next_sr.row = sr.row = row = start_row; sheet_style_get_row (sheet, &sr); /* Collect the column widths */ colwidths = g_alloca (n * sizeof (int)); colwidths -= start_col; for (col = start_col; col <= end_col; col++) { ColRowInfo const *ci = sheet_col_get_info (sheet, col); colwidths[col] = ci->visible ? ci->size_pixels : -1; } goc_canvas_c2w (canvas, start_x / scale, 0, &x, NULL); start_x = x; for (y = start_y; row <= end_row; row = sr.row = next_sr.row, ri = next_ri) { /* Restore the set of ranges seen, but still active. * Reinverting list to maintain the original order */ g_return_val_if_fail (merged_active == NULL, TRUE); #if DEBUG_SELECTION_PAINT g_printerr ("row = %d (startcol = %d)\n", row, start_col); #endif while (merged_active_seen != NULL) { GSList *tmp = merged_active_seen->next; merged_active_seen->next = merged_active; merged_active = merged_active_seen; merged_active_seen = tmp; MERGE_DEBUG (merged_active->data, " : seen -> active\n"); } /* find the next visible row */ while (1) { ++next_sr.row; if (next_sr.row <= end_row) { next_ri = sheet_row_get_info (sheet, next_sr.row); if (next_ri->visible) { sheet_style_get_row (sheet, &next_sr); break; } } else { for (col = start_col ; col <= end_col; ++col) next_sr.vertical [col] = next_sr.bottom [col] = none; break; } } /* look for merges that start on this row, on the first painted row * also check for merges that start above. */ view.start.row = row; lag = &merged_unused; for (ptr = merged_unused; ptr != NULL; ) { GnmRange * const r = ptr->data; if (r->start.row <= row) { GSList *tmp = ptr; ptr = *lag = tmp->next; if (r->end.row < row) { tmp->next = merged_used; merged_used = tmp; MERGE_DEBUG (r, " : unused -> used\n"); } else { ColRowInfo const *ci = sheet_col_get_info (sheet, r->start.col); g_slist_free_1 (tmp); merged_active = g_slist_insert_sorted (merged_active, r, (GCompareFunc)merged_col_cmp); MERGE_DEBUG (r, " : unused -> active\n"); if (ci->visible) item_grid_draw_merged_range (cr, ig, start_x, y, &view, r, draw_selection, ctxt); } } else { lag = &(ptr->next); ptr = ptr->next; } } for (col = start_col, x = start_x; col <= end_col ; col++) { GnmStyle const *style; CellSpanInfo const *span; ColRowInfo const *ci = sheet_col_get_info (sheet, col); #if DEBUG_SELECTION_PAINT g_printerr ("col [%d] = %d\n", col, x); #endif if (!ci->visible) { if (merged_active != NULL) { GnmRange const *r = merged_active->data; if (r->end.col == col) { ptr = merged_active; merged_active = merged_active->next; if (r->end.row <= row) { ptr->next = merged_used; merged_used = ptr; MERGE_DEBUG (r, " : active2 -> used\n"); } else { ptr->next = merged_active_seen; merged_active_seen = ptr; MERGE_DEBUG (r, " : active2 -> seen\n"); } } } continue; } /* Skip any merged regions */ if (merged_active != NULL) { GnmRange const *r = merged_active->data; if (r->start.col <= col) { gboolean clear_top, clear_bottom = FALSE; int i, first = r->start.col; int last = r->end.col; ptr = merged_active; merged_active = merged_active->next; if (r->end.row <= row) { ptr->next = merged_used; merged_used = ptr; MERGE_DEBUG (r, " : active -> used\n"); /* in case something managed the bottom of a merge */ if (r->end.row < row) goto plain_draw; } else { ptr->next = merged_active_seen; merged_active_seen = ptr; MERGE_DEBUG (r, " : active -> seen\n"); if (next_sr.row <= r->end.row) clear_bottom = TRUE; } x += dir * scg_colrow_distance_get ( pane->simple.scg, TRUE, col, last+1); col = last; if (first < start_col) { first = start_col; sr.vertical [first] = NULL; } if (last > end_col) { last = end_col; sr.vertical [last+1] = NULL; } clear_top = (r->start.row != row); /* Clear the borders */ for (i = first ; i <= last ; i++) { if (clear_top) sr.top [i] = NULL; if (clear_bottom) sr.bottom [i] = NULL; if (i > first) sr.vertical [i] = NULL; } continue; } } plain_draw : /* a quick hack to deal with 142267 */ if (dir < 0) x -= ci->size_pixels; style = sr.styles [col]; item_grid_draw_background (cr, ig, style, col, row, x, y, ci->size_pixels, ri->size_pixels, draw_selection, ctxt); /* Is this part of a span? * 1) There are cells allocated in the row * (indicated by ri->spans != NULL) * 2) Look in the rows hash table to see if * there is a span descriptor. */ if (NULL == ri->spans || NULL == (span = row_span_get (ri, col))) { /* If it is being edited pretend it is empty to * avoid problems with long cells' * contents extending past the edge of the edit * box. Ignore blanks too. */ GnmCell const *cell = sheet_cell_get (sheet, col, row); if (!gnm_cell_is_empty (cell) && cell != edit_cell) { if (show_function_cell_markers) draw_function_marker (ig, cell, cr, x, y, ci->size_pixels, ri->size_pixels, dir); cell_draw (cell, cr, x, y, ci->size_pixels, ri->size_pixels, -1, show_extension_markers); } /* Only draw spaning cells after all the backgrounds * that we are going to draw have been drawn. No need * to draw the edit cell, or blanks. */ } else if (edit_cell != span->cell && (col == span->right || col == end_col)) { GnmCell const *cell = span->cell; int const start_span_col = span->left; int const end_span_col = span->right; int real_x = x; ColRowInfo const *cell_col = sheet_col_get_info (sheet, cell->pos.col); int center_offset = cell_col->size_pixels/2; int tmp_width = ci->size_pixels; if (col != cell->pos.col) style = sheet_style_get (sheet, cell->pos.col, row); /* x, y are relative to this cell origin, but the cell * might be using columns to the left (if it is set to right * justify or center justify) compute the pixel difference */ if (dir > 0 && start_span_col != cell->pos.col) center_offset += scg_colrow_distance_get ( pane->simple.scg, TRUE, start_span_col, cell->pos.col); else if (dir < 0 && end_span_col != cell->pos.col) center_offset += scg_colrow_distance_get ( pane->simple.scg, TRUE, cell->pos.col, end_span_col); if (start_span_col != col) { offset = scg_colrow_distance_get ( pane->simple.scg, TRUE, start_span_col, col); tmp_width += offset; if (dir > 0) real_x -= offset; sr.vertical [col] = NULL; } if (end_span_col != col) { offset = scg_colrow_distance_get ( pane->simple.scg, TRUE, col+1, end_span_col + 1); tmp_width += offset; if (dir < 0) real_x -= offset; } if (show_function_cell_markers) draw_function_marker (ig, cell, cr, real_x, y, tmp_width, ri->size_pixels, dir); cell_draw (cell, cr, real_x, y, tmp_width, ri->size_pixels, center_offset, show_extension_markers); } else if (col != span->left) sr.vertical [col] = NULL; if (dir > 0) x += ci->size_pixels; } gnm_style_borders_row_draw (prev_vert, &sr, cr, start_x, y, y+ri->size_pixels, colwidths, TRUE, dir); /* In case there were hidden merges that trailed off the end */ while (merged_active != NULL) { GnmRange const *r = merged_active->data; ptr = merged_active; merged_active = merged_active->next; if (r->end.row <= row) { ptr->next = merged_used; merged_used = ptr; MERGE_DEBUG (r, " : active3 -> used\n"); } else { ptr->next = merged_active_seen; merged_active_seen = ptr; MERGE_DEBUG (r, " : active3 -> seen\n"); } } /* roll the pointers */ borders = prev_vert; prev_vert = sr.vertical; sr.vertical = next_sr.vertical; next_sr.vertical = borders; borders = sr.top; sr.top = sr.bottom; sr.bottom = next_sr.top = next_sr.bottom; next_sr.bottom = borders; styles = sr.styles; sr.styles = next_sr.styles; next_sr.styles = styles; y += ri->size_pixels; } if (ig->bound.start.row > 0 && start_y < 1) ig_cairo_draw_bound (ig, cr, start_x, 1, x, 1); if (ig->bound.start.col > 0) { if (canvas->direction == GOC_DIRECTION_RTL && start_x >= goc_canvas_get_width (canvas)) { x = goc_canvas_get_width (canvas); ig_cairo_draw_bound (ig, cr, x, start_y, x, y); } else if (canvas->direction == GOC_DIRECTION_LTR && start_x < 1) ig_cairo_draw_bound (ig, cr, 1, start_y, 1, y); } g_object_ref_sink (entry); g_object_unref (entry); g_slist_free (merged_used); /* merges with bottom in view */ g_slist_free (merged_active_seen); /* merges with bottom the view */ g_slist_free (merged_unused); /* merges in hidden rows */ g_return_val_if_fail (merged_active == NULL, TRUE); return TRUE; }
static void item_grid_draw_merged_range (cairo_t *cr, GnmItemGrid *ig, int start_x, int start_y, GnmRange const *view, GnmRange const *range, gboolean draw_selection, GtkStyleContext *ctxt) { int l, r, t, b, last; SheetView const *sv = scg_view (ig->scg); WorkbookView *wbv = sv_wbv (sv); gboolean show_function_cell_markers = wbv->show_function_cell_markers; gboolean show_extension_markers = wbv->show_extension_markers; Sheet const *sheet = sv->sheet; GnmCell const *cell = sheet_cell_get (sheet, range->start.col, range->start.row); int const dir = sheet->text_is_rtl ? -1 : 1; /* load style from corner which may not be visible */ GnmStyle const *style = sheet_style_get (sheet, range->start.col, range->start.row); gboolean const is_selected = draw_selection && (sv->edit_pos.col != range->start.col || sv->edit_pos.row != range->start.row) && sv_is_full_range_selected (sv, range); /* Get the coordinates of the visible region */ l = r = start_x; if (view->start.col < range->start.col) l += dir * scg_colrow_distance_get (ig->scg, TRUE, view->start.col, range->start.col); if (range->end.col <= (last = view->end.col)) last = range->end.col; r += dir * scg_colrow_distance_get (ig->scg, TRUE, view->start.col, last+1); t = b = start_y; if (view->start.row < range->start.row) t += scg_colrow_distance_get (ig->scg, FALSE, view->start.row, range->start.row); if (range->end.row <= (last = view->end.row)) last = range->end.row; b += scg_colrow_distance_get (ig->scg, FALSE, view->start.row, last+1); if (l == r || t == b) return; if (style->conditions) { GnmEvalPos ep; int res; eval_pos_init (&ep, (Sheet *)sheet, range->start.col, range->start.row); if ((res = gnm_style_conditions_eval (style->conditions, &ep)) >= 0) style = g_ptr_array_index (style->cond_styles, res); } /* Check for background THEN selection */ if (gnumeric_background_set (style, cr, is_selected, ctxt) || is_selected) { /* Remember X excludes the far pixels */ if (dir > 0) cairo_rectangle (cr, l, t, r-l+1, b-t+1); else cairo_rectangle (cr, r, t, l-r+1, b-t+1); cairo_fill (cr); } /* Expand the coords to include non-visible areas too. The clipped * region is only necessary when drawing the background */ if (range->start.col < view->start.col) l -= dir * scg_colrow_distance_get (ig->scg, TRUE, range->start.col, view->start.col); if (view->end.col < range->end.col) r += dir * scg_colrow_distance_get (ig->scg, TRUE, view->end.col+1, range->end.col+1); if (range->start.row < view->start.row) t -= scg_colrow_distance_get (ig->scg, FALSE, range->start.row, view->start.row); if (view->end.row < range->end.row) b += scg_colrow_distance_get (ig->scg, FALSE, view->end.row+1, range->end.row+1); if (cell != NULL) { ColRowInfo *ri = sheet_row_get (sheet, range->start.row); if (ri->needs_respan) row_calc_spans (ri, cell->pos.row, sheet); if (dir > 0) { if (show_function_cell_markers) draw_function_marker (ig, cell, cr, l, t, r - l, b - t, dir); cell_draw (cell, cr, l, t, r - l, b - t, -1, show_extension_markers); } else { if (show_function_cell_markers) draw_function_marker (ig, cell, cr, r, t, l - r, b - t, dir); cell_draw (cell, cr, r, t, l - r, b - t, -1, show_extension_markers); } } if (dir > 0) gnm_style_border_draw_diag (style, cr, l, t, r, b); else gnm_style_border_draw_diag (style, cr, r, t, l, b); }
GnumericStylePtr gnumeric_sheet_get_style(GnumericSheetPtr sheet, int x, int y) { GnmStyle const *r = sheet_style_get((Sheet*)sheet,x,y); if (r==NULL) return NULL; return gnm_style_dup(r); }
int gnumeric_sheet_get_cell(GnumericSheetPtr sheet, int x, int y, GSheetCellPtr cell) { gsheetcell_zero(cell); GnmValue const *value = sheet_cell_get_value((Sheet*)sheet,x,y); if (value==NULL) return 0; if (value->type == VALUE_EMPTY) return 0; GnmCell const *gcell = sheet_cell_get((Sheet*)sheet,x,y); if (gcell) { if (gnm_cell_has_expr (gcell)) { if (gcell->base.texpr->expr) { const GnmExpr *expr = gcell->base.texpr->expr; if (expr) { if (expr->oper==GNM_EXPR_OP_FUNCALL) { if (expr->func.func) { const char *name = expr->func.func->name; if (name) { if (strcasecmp(name,"hyperlink")==0) { // Hyperlink. Take url part. char *url = NULL; char *txt = NULL; if (expr->func.argc==2) { const GnmExpr *expr0 = expr->func.argv[0]; if (expr0) { if (expr0->oper == GNM_EXPR_OP_CONSTANT) { url = value_get_as_string(expr0->constant.value); } } const GnmExpr *expr1 = expr->func.argv[1]; if (expr1) { if (expr1->oper == GNM_EXPR_OP_CONSTANT) { txt = value_get_as_string(expr1->constant.value); } } } if (url&&txt) { if (strcasecmp(url,txt)==0) { cell->all = url; cell->url = g_strdup(url); cell->txt = g_strdup(url); cell->is_url = 1; return 0; } cell->all = g_strconcat("[",url,"|",txt,"]",NULL); cell->url = url; cell->txt = txt; cell->is_url = 1; return 0; } else { if (url) g_free(url); if (txt) g_free(txt); } } } } } } } //return gnm_cell_get_entered_text(cell); } } GnmStyle const *style = sheet_style_get((Sheet*)sheet,x,y); GnmHLink* hlink = gnm_style_get_hlink (style); const guchar* hlink_target = NULL; if (hlink && IS_GNM_HLINK_URL (hlink)) { hlink_target = gnm_hlink_get_target (hlink); if (hlink_target) { //char *str = value_get_as_string(value); //if (!str) return str; //const char *str2 = " "; //char *result = g_strconcat(str,str2,hlink_target); //g_free(str); //return result; cell->is_url = 1; cell->all = g_strdup(hlink_target); cell->url = g_strdup(hlink_target); cell->txt = g_strdup(hlink_target); return 0; } } cell->all = value_get_as_string(value); return 0; }