/** * gnm_sheet_guess_data_range : * @sheet: #Sheet * @region: #GnmRange * * Makes a guess at the logical range containing @region and returns the possibly * expanded result in @region. The range is also expanded upwards. **/ void gnm_sheet_guess_data_range (Sheet *sheet, GnmRange *region) { int col; int row; int start = region->start.col; /* look for previous empty column */ for (col = start - 1; col >= 0; col--) if (!sheet_cell_or_one_below_is_not_empty (sheet, col, region->start.row)) break; region->start.col = col + 1; /* look for next empty column */ start = region->end.col; for (col = start + 1; col < gnm_sheet_get_max_cols (sheet); col++) if (!sheet_cell_or_one_below_is_not_empty (sheet, col, region->start.row)) break; region->end.col = col - 1; for (col = region->start.col; col <= region->end.col; col++) { gboolean empties = FALSE; for (row = region->start.row - 2; row >= 0; row--) if (!sheet_cell_or_one_below_is_not_empty (sheet, col, row)) { empties = TRUE; break; } region->start.row = empties ? row + 2 : 0; for (row = region->end.row + 1; row < gnm_sheet_get_max_rows (sheet); row++) if (!sheet_cell_or_one_below_is_not_empty (sheet, col, row)) break; region->end.row = row - 1; } return; }
static void cb_append_clicked (G_GNUC_UNUSED GtkWidget *ignore, SheetManager *state) { WorkbookSheetState *old_state; WorkbookControl *wbc = GNM_WBC (state->wbcg); Workbook *wb = wb_control_get_workbook (wbc); GtkTreeIter iter; Sheet *sheet, *old_sheet; workbook_signals_block (state); old_state = workbook_sheet_state_new (wb); old_sheet = workbook_sheet_by_index (wb, 0); workbook_sheet_add (wb, -1, gnm_sheet_get_max_cols (old_sheet), gnm_sheet_get_max_rows (old_sheet)); cmd_reorganize_sheets (wbc, old_state, NULL); update_undo (state, wbc); workbook_signals_unblock (state); sheet = workbook_sheet_by_index (wb, workbook_sheet_count (wb) - 1); g_signal_handler_block (state->model, state->model_row_insertion_listener); gtk_list_store_append (state->model, &iter); g_signal_handler_unblock (state->model, state->model_row_insertion_listener); set_sheet_info_at_iter (state, &iter, sheet); cb_selection_changed (NULL, state); }
static void set_sheet_info_at_iter (SheetManager *state, GtkTreeIter *iter, Sheet *sheet) { GdkRGBA cback, *color = NULL; GdkRGBA cfore, *text_color = NULL; if (sheet->tab_color) color = go_color_to_gdk_rgba (sheet->tab_color->go_color, &cback); if (sheet->tab_text_color) text_color = go_color_to_gdk_rgba (sheet->tab_text_color->go_color, &cfore); gtk_list_store_set (state->model, iter, SHEET_LOCKED, sheet->is_protected, SHEET_LOCK_IMAGE, (sheet->is_protected ? state->image_padlock : state->image_padlock_no), SHEET_VISIBLE, (sheet->visibility == GNM_SHEET_VISIBILITY_VISIBLE), SHEET_VISIBLE_IMAGE, (sheet->visibility == GNM_SHEET_VISIBILITY_VISIBLE ? state->image_visible : NULL), SHEET_ROW_MAX, gnm_sheet_get_max_rows (sheet), SHEET_COL_MAX, gnm_sheet_get_max_cols (sheet), SHEET_NAME, sheet->name_unquoted, SHEET_NEW_NAME, "", SHEET_POINTER, sheet, BACKGROUND_COLOUR, color, FOREGROUND_COLOUR, text_color, SHEET_DIRECTION, sheet->text_is_rtl, SHEET_DIRECTION_IMAGE, (sheet->text_is_rtl ? state->image_rtl : state->image_ltr), -1); }
/** * range_translate: * @range: * @sheet : the sheet in which @range lives * @col_offset: * @row_offset: * * Translate the range and return TRUE if it is invalidated. * * return TRUE if the range is no longer valid. **/ gboolean range_translate (GnmRange *range, Sheet const *sheet, int col_offset, int row_offset) { /* * FIXME: we should probably check for overflow without actually * performing it. */ range->start.col += col_offset; range->end.col += col_offset; range->start.row += row_offset; range->end.row += row_offset; /* check for completely out of bounds */ if (range->start.col >= gnm_sheet_get_max_cols (sheet) || range->start.col < 0 || range->start.row >= gnm_sheet_get_max_rows (sheet) || range->start.row < 0 || range->end.col >= gnm_sheet_get_max_cols (sheet) || range->end.col < 0 || range->end.row >= gnm_sheet_get_max_rows (sheet) || range->end.row < 0) return TRUE; return FALSE; }
/** * range_clip_to_finite : * @range : * @sheet : the sheet in which @range lives * * Clip the range to the area of the sheet with content. * if the range reaches the edge * * The idea here is that users may select a whole column or ow when they * really are only concerned with the extent of the sheet. * On the otehr hand, if users select any smaller region they probably * intend to selec tjust that. * * WARNING THIS IS EXPENSIVE! **/ void range_clip_to_finite (GnmRange *range, Sheet *sheet) { GnmRange extent; /* FIXME : This seems expensive. We should see if there is a faster * way of doing this. possibly using a flag for content changes, and * using the current values as a cache */ extent = sheet_get_extent (sheet, FALSE); if (range->end.col >= gnm_sheet_get_max_cols (sheet) - 1) range->end.col = extent.end.col; if (range->end.row >= gnm_sheet_get_max_rows (sheet) - 1) range->end.row = extent.end.row; }
static void thrash_insert (Sheet *sheet) { int j; GnmStyle *style1 = gnm_style_new (); GnmStyle *style2 = gnm_style_new (); gnm_style_set_font_bold (style1, TRUE); gnm_style_set_font_italic (style1, TRUE); gnm_style_set_font_size (style2, 20.0); for (j = 0; j < INSERT_HEIGHT; j++) { GnmRange r; int i; for (i = 0; i < INSERT_WIDTH; i++) { GnmCell *cell; GnmStyle *setstyle; r.start.col = i; r.start.row = j; r.end = r.start; if (((i / 31) % 2) == 0) setstyle = style1; else setstyle = style2; gnm_style_ref (setstyle); sheet_style_attach (sheet, &r, setstyle); cell = sheet_cell_fetch (sheet, i, j); gnm_cell_set_value (cell, value_new_int (i), NULL); } r.start.col = 0; r.start.row = MAX (0, j - 1); r.end.col = gnm_sheet_get_max_cols (sheet); r.end.row = MIN (gnm_sheet_get_max_rows (sheet), j + 1); sheet_style_optimize (sheet, r); } gnm_style_unref (style1); gnm_style_unref (style2); }
static void gplp_func_file_open (GOFileOpener const *fo, GOPluginService *service, GOIOContext *io_context, gpointer wb_view, GsfInput *input) { ServiceLoaderDataFileOpener *loader_data; Sheet *sheet, *old_sheet; PyObject *open_result = NULL; PyObject *input_wrapper; printf("gplp_func_file_open(start)\n"); g_return_if_fail (GO_IS_PLUGIN_SERVICE_FILE_OPENER (service)); g_return_if_fail (input != NULL); g_return_if_fail (_PyGObject_API != NULL); old_sheet = wb_view_cur_sheet (wb_view); loader_data = g_object_get_data (G_OBJECT (service), "loader_data"); SWITCH_TO_PLUGIN (go_plugin_service_get_plugin (service)); sheet = sheet_new (wb_view_get_workbook (wb_view), _("Some name"), gnm_sheet_get_max_cols (old_sheet), gnm_sheet_get_max_rows (old_sheet)); input_wrapper = pygobject_new (G_OBJECT (input)); if (input_wrapper != NULL) { /* wrapping adds a reference */ g_object_unref (G_OBJECT (input)); open_result = PyObject_CallFunction (loader_data->python_func_file_open, (char *) "NO", py_new_Sheet_object (sheet), input_wrapper); Py_DECREF (input_wrapper); } if (open_result != NULL) { Py_DECREF (open_result); workbook_sheet_attach (wb_view_get_workbook (wb_view), sheet); } else { go_io_error_string (io_context, py_exc_to_string ()); gnm_python_clear_error_if_needed (SERVICE_GET_LOADER (service)->py_object); g_object_unref (sheet); } printf("gplp_func_file_open(end)\n"); }
static void cb_add_clicked (G_GNUC_UNUSED GtkWidget *ignore, SheetManager *state) { GtkTreeIter sel_iter, iter; GtkTreeSelection *selection = gtk_tree_view_get_selection (state->sheet_list); GList *selected_rows; int index = -1; WorkbookSheetState *old_state; WorkbookControl *wbc = GNM_WBC (state->wbcg); Workbook *wb = wb_control_get_workbook (wbc); Sheet *sheet, *old_sheet = NULL; g_return_if_fail (selection != NULL); g_return_if_fail (gtk_tree_selection_count_selected_rows (selection) == 1); selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL); gtk_tree_model_get_iter (GTK_TREE_MODEL (state->model), &sel_iter, (GtkTreePath *) selected_rows->data); g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free); gtk_tree_model_get (GTK_TREE_MODEL (state->model), &sel_iter, SHEET_POINTER, &old_sheet, -1); index = old_sheet->index_in_wb; workbook_signals_block (state); old_state = workbook_sheet_state_new (wb); workbook_sheet_add (wb, index, gnm_sheet_get_max_cols (old_sheet), gnm_sheet_get_max_rows (old_sheet)); cmd_reorganize_sheets (wbc, old_state, NULL); update_undo (state, wbc); workbook_signals_unblock (state); g_signal_handler_block (state->model, state->model_row_insertion_listener); sheet = workbook_sheet_by_index (wb, index); gtk_list_store_insert_before (state->model, &iter, &sel_iter); g_signal_handler_unblock (state->model, state->model_row_insertion_listener); set_sheet_info_at_iter (state, &iter, sheet); cb_selection_changed (NULL, state); }
static GnmStyle * pg_get_style (GnmPreviewGrid *pg, int col, int row) { GnmPreviewGridClass *klass = GNM_PREVIEW_GRID_GET_CLASS (pg); GnmStyle *style; g_return_val_if_fail (col >= 0 && col < gnm_sheet_get_max_cols (pg->sheet), NULL); g_return_val_if_fail (row >= 0 && row < gnm_sheet_get_max_rows (pg->sheet), NULL); g_return_val_if_fail (klass != NULL, NULL); if (klass->get_cell_style) { style = klass->get_cell_style (pg, col, row); if (style != NULL) return style; } return pg->defaults.style; }
/** * pg_get_row_offset: * pg: * @y: offset * @row_origin: if not null the origin of the row containing pixel @y is put here * * Return value: Row containing pixel y (and origin in @row_origin) **/ static int pg_get_row_offset (GnmPreviewGrid *pg, int const y, int *row_origin) { int row = 0; int pixel = 1; int const h = pg->defaults.row_height; g_return_val_if_fail (pg != NULL, 0); do { if (y <= (pixel + h) || h == 0) { if (row_origin) *row_origin = pixel; return row; } pixel += h; } while (++row < gnm_sheet_get_max_rows (pg->sheet)); if (row_origin) *row_origin = pixel; return gnm_sheet_get_last_row (pg->sheet); }
static GnmCell * pg_fetch_cell (GnmPreviewGrid *pg, int col, int row) { GnmPreviewGridClass *klass = GNM_PREVIEW_GRID_GET_CLASS (pg); GnmCell *cell; GnmValue *v = NULL; g_return_val_if_fail (klass != NULL, NULL); g_return_val_if_fail (pg != NULL, NULL); g_return_val_if_fail (col >= 0 && col < gnm_sheet_get_max_cols (pg->sheet), NULL); g_return_val_if_fail (row >= 0 && row < gnm_sheet_get_max_rows (pg->sheet), NULL); if (NULL != klass->get_cell_value) v = (klass->get_cell_value) (pg, col, row); if (NULL == v) v = value_dup (pg->defaults.value); cell = sheet_cell_fetch (pg->sheet, col, row); gnm_cell_set_value (cell, v); gnm_cell_render_value (cell, TRUE); return cell; }
/** * clipboard_paste_region: * @cr: The GnmCellRegion to paste. * @pt: Where to paste the values. * @cc: The context for error handling. * * Pastes the supplied GnmCellRegion (@cr) into the supplied * GnmPasteTarget (@pt). This operation is not undoable. It does not auto grow * the destination if the target is a singleton. This is a simple interface to * paste a region. * * returns : TRUE if there was a problem. **/ gboolean clipboard_paste_region (GnmCellRegion const *cr, GnmPasteTarget const *pt, GOCmdContext *cc) { int repeat_horizontal, repeat_vertical, clearFlags; int dst_cols, dst_rows, src_cols, src_rows; int i, j; GSList *ptr; GnmRange const *r; gboolean has_contents, adjust_merges = TRUE; struct paste_cell_data dat; GnmRange const *merge_src; g_return_val_if_fail (pt != NULL, TRUE); g_return_val_if_fail (cr != NULL, TRUE); /* we do not need any of this fancy stuff when pasting a simple object */ if (cr->cell_content == NULL && cr->styles == NULL && cr->merged == NULL && cr->objects != NULL) { if (pt->paste_flags & (PASTE_COMMENTS | PASTE_OBJECTS)) for (ptr = cr->objects; ptr; ptr = ptr->next) paste_object (pt, ptr->data, pt->range.start.col, pt->range.start.row); return FALSE; } r = &pt->range; dst_cols = range_width (r); dst_rows = range_height (r); src_cols = cr->cols; src_rows = cr->rows; /* If the source is a single cell or a single merge */ /* Treat a target of a single merge specially, don't split the merge */ if ((src_cols == 1 && src_rows == 1) || (g_slist_length (cr->merged) == 1 && (NULL != (merge_src = cr->merged->data)) && range_height (merge_src) == cr->rows && range_width (merge_src) == cr->cols)) { GnmRange const *merge = gnm_sheet_merge_is_corner (pt->sheet, &r->start); if (merge != NULL && range_equal (r, merge)) { dst_cols = dst_rows = 1; adjust_merges = FALSE; src_cols = 1; src_rows = 1; } /* Apparently links do not supercede merges */ } else if (pt->paste_flags & PASTE_LINK) adjust_merges = FALSE; has_contents = pt->paste_flags & (PASTE_CONTENTS|PASTE_AS_VALUES|PASTE_LINK); if (pt->paste_flags & PASTE_TRANSPOSE) { int tmp = src_cols; src_cols = src_rows; src_rows = tmp; } if (cr->not_as_contents && (pt->paste_flags & PASTE_CONTENTS)) { go_cmd_context_error_invalid (cc, _("Unable to paste"), _("Contents can only be pasted by value or by link.")); return TRUE; } /* calculate the tiling */ repeat_horizontal = dst_cols/src_cols; if (repeat_horizontal * src_cols != dst_cols) { char *msg = g_strdup_printf ( _("destination does not have an even multiple of source columns (%d vs %d)\n\n" "Try selecting a single cell or an area of the same shape and size."), dst_cols, src_cols); go_cmd_context_error_invalid (cc, _("Unable to paste"), msg); g_free (msg); return TRUE; } repeat_vertical = dst_rows/src_rows; if (repeat_vertical * src_rows != dst_rows) { char *msg = g_strdup_printf ( _("destination does not have an even multiple of source rows (%d vs %d)\n\n" "Try selecting a single cell or an area of the same shape and size."), dst_rows, src_rows); go_cmd_context_error_invalid (cc, _("Unable to paste"), msg); g_free (msg); return TRUE; } if ((pt->range.start.col + dst_cols) > gnm_sheet_get_max_cols (pt->sheet) || (pt->range.start.row + dst_rows) > gnm_sheet_get_max_rows (pt->sheet)) { go_cmd_context_error_invalid (cc, _("Unable to paste"), _("result passes the sheet boundary")); return TRUE; } clearFlags = 0; /* clear the region where we will paste */ if (has_contents) clearFlags = CLEAR_VALUES | CLEAR_NORESPAN; if (pt->paste_flags & PASTE_COMMENTS) clearFlags |= CLEAR_COMMENTS; /* No need to clear the formats. We will paste over top of these. */ /* if (pt->paste_flags & PASTE_FORMATS) clearFlags |= CLEAR_FORMATS; */ if (pt->paste_flags & (PASTE_OPER_MASK | PASTE_SKIP_BLANKS)) clearFlags = 0; /* remove merged regions even for operations, or blanks */ if (has_contents && adjust_merges) clearFlags |= CLEAR_MERGES; if (clearFlags != 0) { int const dst_col = pt->range.start.col; int const dst_row = pt->range.start.row; sheet_clear_region (pt->sheet, dst_col, dst_row, dst_col + dst_cols - 1, dst_row + dst_rows - 1, clearFlags, cc); } dat.translate_dates = cr->date_conv && !go_date_conv_equal (cr->date_conv, workbook_date_conv (pt->sheet->workbook)); for (i = 0; i < repeat_horizontal ; i++) for (j = 0; j < repeat_vertical ; j++) { int const left = i * src_cols + pt->range.start.col; int const top = j * src_rows + pt->range.start.row; dat.top_left.col = left; dat.top_left.row = top; dat.rinfo.reloc_type = GNM_EXPR_RELOCATE_MOVE_RANGE; dat.rinfo.origin_sheet = dat.rinfo.target_sheet = pt->sheet; if (pt->paste_flags & PASTE_EXPR_LOCAL_RELOCATE) { dat.rinfo.origin.start = cr->base; dat.rinfo.origin.end.col = cr->base.col + cr->cols - 1; dat.rinfo.origin.end.row = cr->base.row + cr->rows - 1; dat.rinfo.col_offset = left - cr->base.col; dat.rinfo.row_offset = top - cr->base.row; } else { dat.rinfo.origin = pt->range; dat.rinfo.col_offset = 0; dat.rinfo.row_offset = 0; } /* Move the styles on here so we get correct formats before recalc */ if (pt->paste_flags & PASTE_FORMATS) { if (pt->paste_flags & PASTE_TRANSPOSE) sheet_style_set_list (pt->sheet, &dat.top_left, cr->styles, (sheet_style_set_list_cb_t) range_transpose, &dat.top_left); else if (pt->paste_flags & PASTE_FLIP_H) { int data = 2 * left + src_cols - 1; sheet_style_set_list (pt->sheet, &dat.top_left, cr->styles, (sheet_style_set_list_cb_t) range_flip_h, &data); } else if (pt->paste_flags & PASTE_FLIP_V) { int data = 2 * top + src_rows - 1; sheet_style_set_list (pt->sheet, &dat.top_left, cr->styles, (sheet_style_set_list_cb_t) range_flip_v, &data); } else sheet_style_set_list (pt->sheet, &dat.top_left, cr->styles, NULL, NULL); } if (has_contents && !(pt->paste_flags & PASTE_DONT_MERGE)) { for (ptr = cr->merged; ptr != NULL ; ptr = ptr->next) { GnmRange tmp = *((GnmRange const *)ptr->data); if (pt->paste_flags & PASTE_TRANSPOSE) { int x; x = tmp.start.col; tmp.start.col = tmp.start.row; tmp.start.row = x; x = tmp.end.col; tmp.end.col = tmp.end.row; tmp.end.row = x; } if (!range_translate (&tmp, pt->sheet, left, top)) gnm_sheet_merge_add (pt->sheet, &tmp, TRUE, cc); } } if (has_contents && (pt->paste_flags & PASTE_LINK)) { paste_link (pt, top, left, cr); continue; } if (has_contents && NULL != cr->cell_content) { dat.pt = pt; dat.cr = cr; g_hash_table_foreach (cr->cell_content, (GHFunc)cb_paste_cell, &dat); } if (pt->paste_flags & (PASTE_COMMENTS | PASTE_OBJECTS)) for (ptr = cr->objects; ptr; ptr = ptr->next) paste_object (pt, ptr->data, left, top); } if (!(pt->paste_flags & PASTE_NO_RECALC)) { if (has_contents) { sheet_region_queue_recalc (pt->sheet, r); sheet_flag_status_update_range (pt->sheet, r); } else sheet_flag_style_update_range (pt->sheet, r); sheet_range_calc_spans (pt->sheet, r, (pt->paste_flags & PASTE_FORMATS) ? GNM_SPANCALC_RE_RENDER : GNM_SPANCALC_RENDER); if (pt->paste_flags & PASTE_UPDATE_ROW_HEIGHT) rows_height_update (pt->sheet, &pt->range, FALSE); sheet_redraw_all (pt->sheet, FALSE); } return FALSE; }
/* * Raturns FALSE on EOF. */ static gboolean dif_parse_data (DifInputContext *ctxt) { gboolean too_many_rows = FALSE, too_many_columns = FALSE; gint row = -1, col = 0; gint val_type; GnmCell *cell; gchar *msg; while (1) { if (!dif_get_line (ctxt)) return FALSE; val_type = atoi (ctxt->line); if (val_type == 0) { gchar const *comma = strchr (ctxt->line, ','); if (comma == NULL) go_io_warning (ctxt->io_context, _("Syntax error at line %d. Ignoring."), ctxt->line_no); else if (col > gnm_sheet_get_max_cols (ctxt->sheet)) { too_many_columns = TRUE; break; } else { gnm_float num = gnm_strto (comma+1, NULL); GnmValue *v = NULL; if (!dif_get_line (ctxt)) return FALSE; if (0 == strcmp (ctxt->line, "V")) { /* V value */ v = value_new_float (num); } else if (0 == strcmp (ctxt->line, "NA")) { /* NA not available res must be O */ v = value_new_error_NA (NULL); } else if (0 == strcmp (ctxt->line, "TRUE")) { /* TRUE bool T res must be 1 */ v = value_new_bool (TRUE); } else if (0 == strcmp (ctxt->line, "FALSE")) { /* FALSE bool F res must be O */ v = value_new_bool (TRUE); } else if (0 == strcmp (ctxt->line, "ERROR")) { /* ERROR err res must be O */ go_io_warning (ctxt->io_context, _("Unknown value type '%s' at line %d. Ignoring."), ctxt->line, ctxt->line_no); } if (NULL != v) { cell = sheet_cell_fetch (ctxt->sheet, col, row); gnm_cell_set_value (cell, v); } col++; } } else if (val_type == 1) { if (!dif_get_line (ctxt)) return FALSE; if (col > gnm_sheet_get_max_cols (ctxt->sheet)) { too_many_columns = TRUE; continue; } cell = sheet_cell_fetch (ctxt->sheet, col, row); if (ctxt->line_len >= 2 && ctxt->line[0] == '"' && ctxt->line[ctxt->line_len - 1] == '"') { ctxt->line[ctxt->line_len - 1] = '\0'; gnm_cell_set_text (cell, ctxt->line + 1); } else gnm_cell_set_text (cell, ctxt->line); col++; } else if (val_type == -1) { if (!dif_get_line (ctxt)) return FALSE; if (strcmp (ctxt->line, "BOT") == 0) { col = 0; row++; if (row > gnm_sheet_get_max_rows (ctxt->sheet)) { too_many_rows = TRUE; break; } } else if (strcmp (ctxt->line, "EOD") == 0) { break; } else { msg = g_strdup_printf ( _("Unknown data value \"%s\" at line %d. Ignoring."), ctxt->line, ctxt->line_no); g_warning ("%s", msg); g_free (msg); } } else { msg = g_strdup_printf ( _("Unknown value type %d at line %d. Ignoring."), val_type, ctxt->line_no); g_warning ("%s", msg); g_free (msg); (void) dif_get_line (ctxt); } } if (too_many_rows) { g_warning (_("DIF file has more than the maximum number of rows %d. " "Ignoring remaining rows."), gnm_sheet_get_max_rows (ctxt->sheet)); } if (too_many_columns) { g_warning (_("DIF file has more than the maximum number of columns %d. " "Ignoring remaining columns."), gnm_sheet_get_max_cols (ctxt->sheet)); } return TRUE; }
static GtkWidget * fcombo_create_list (SheetObject *so, GtkTreePath **clip, GtkTreePath **select, gboolean *make_buttons) { GnmFilterCombo *fcombo = GNM_FILTER_COMBO (so); GnmFilter const *filter = fcombo->filter; GnmRange r = filter->r; Sheet *filtered_sheet; UniqueCollection uc; GtkTreeIter iter; GtkListStore *model; GtkWidget *list; GPtrArray *sorted = g_ptr_array_new (); unsigned i, field_num = gnm_filter_combo_index (fcombo); gboolean is_custom = FALSE; GnmValue const *v; GnmValue const *cur_val = NULL; model = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, gnm_value_get_type ()); gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, 0, _("(All)"), 1, NULL, 2, 1, -1); if (fcombo->cond == NULL || fcombo->cond->op[0] == GNM_FILTER_UNUSED) *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, 0, _("(Top 10...)"), 1, NULL, 2, 10,-1); if (fcombo->cond != NULL && (GNM_FILTER_OP_TYPE_MASK & fcombo->cond->op[0]) == GNM_FILTER_OP_TOP_N) *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); /* default to this we can easily revamp later */ gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, 0, _("(Custom...)"), 1, NULL, 2, 2, -1); if (*select == NULL) { is_custom = TRUE; *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); } r.start.row++; /* r.end.row = XL actually extend to the first non-empty element in the list */ r.end.col = r.start.col += field_num; uc.has_blank = FALSE; uc.hash = g_hash_table_new_full ((GHashFunc)value_hash, (GEqualFunc)formatted_value_equal, (GDestroyNotify)value_release, (GDestroyNotify)g_free); uc.src_sheet = filter->sheet; uc.date_conv = sheet_date_conv (uc.src_sheet); /* We do not want to show items that are filtered by _other_ fields. * The cleanest way to do that is to create a temporary sheet, apply * all of the other conditions to it and use that as the source of visibility. */ if (filter->fields->len > 1) { Workbook *wb = uc.src_sheet->workbook; char *name = workbook_sheet_get_free_name (wb, "DummyFilterPopulate", FALSE, FALSE); filtered_sheet = sheet_new (wb, name, gnm_sheet_get_max_cols (uc.src_sheet), gnm_sheet_get_max_rows (uc.src_sheet)); g_free (name); for (i = 0 ; i < filter->fields->len ; i++) if (i != field_num) gnm_filter_combo_apply (g_ptr_array_index (filter->fields, i), filtered_sheet); sheet_foreach_cell_in_range (filtered_sheet, CELL_ITER_IGNORE_HIDDEN, &r, (CellIterFunc)&cb_collect_content, &uc); g_object_unref (filtered_sheet); } else sheet_foreach_cell_in_range (filter->sheet, CELL_ITER_ALL, &r, (CellIterFunc)&cb_collect_content, &uc); g_hash_table_foreach (uc.hash, (GHFunc)cb_hash_domain, sorted); g_ptr_array_sort (sorted, value_cmp); if (fcombo->cond != NULL && fcombo->cond->op[0] == GNM_FILTER_OP_EQUAL && fcombo->cond->op[1] == GNM_FILTER_UNUSED) { cur_val = fcombo->cond->value[0]; } for (i = 0; i < sorted->len ; i++) { char *label = NULL; unsigned const max = 50; char const *str = g_hash_table_lookup (uc.hash, (v = g_ptr_array_index (sorted, i))); gsize len = g_utf8_strlen (str, -1); if (len > max + 3) { label = g_strdup (str); strcpy (g_utf8_offset_to_pointer (label, max), "..."); } gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, 0, label ? label : str, /* Menu text */ 1, str, /* Actual string selected on. */ 2, 0, 3, v, -1); g_free (label); if (i == 10) *clip = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); if (cur_val != NULL && v != NULL && value_equal (cur_val, v)) { gtk_tree_path_free (*select); *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); } } if (uc.has_blank) { gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, 0, _("(Blanks...)"), 1, NULL, 2, 3, -1); if (fcombo->cond != NULL && fcombo->cond->op[0] == GNM_FILTER_OP_BLANKS) *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, 0, _("(Non Blanks...)"), 1, NULL, 2, 4, -1); if (fcombo->cond != NULL && fcombo->cond->op[0] == GNM_FILTER_OP_NON_BLANKS) *select = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); } else if (is_custom && fcombo->cond != NULL && (GNM_FILTER_OP_TYPE_MASK & fcombo->cond->op[0]) == GNM_FILTER_OP_BLANKS) { gtk_tree_path_free (*select); *select = NULL; } g_hash_table_destroy (uc.hash); g_ptr_array_free (sorted, TRUE); list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model)); g_object_unref (model); gtk_tree_view_append_column (GTK_TREE_VIEW (list), gtk_tree_view_column_new_with_attributes ("ID", gtk_cell_renderer_text_new (), "text", 0, NULL)); return list; }
static int item_grid_button_pressed (GocItem *item, int button, double x_, double y_) { GnmItemGrid *ig = GNM_ITEM_GRID (item); GocCanvas *canvas = item->canvas; GnmPane *pane = GNM_PANE (canvas); SheetControlGUI *scg = ig->scg; WBCGtk *wbcg = scg_wbcg (scg); SheetControl *sc = (SheetControl *)scg; SheetView *sv = sc_view (sc); Sheet *sheet = sv_sheet (sv); GnmCellPos pos; gboolean edit_showed_dialog; gboolean already_selected; GdkEvent *event = goc_canvas_get_cur_event (item->canvas); gint64 x = x_ * canvas->pixels_per_unit, y = y_ * canvas->pixels_per_unit; gnm_pane_slide_stop (pane); pos.col = gnm_pane_find_col (pane, x, NULL); pos.row = gnm_pane_find_row (pane, y, NULL); /* GnmRange check first */ if (pos.col >= gnm_sheet_get_max_cols (sheet)) return TRUE; if (pos.row >= gnm_sheet_get_max_rows (sheet)) return TRUE; /* A new object is ready to be realized and inserted */ if (wbcg->new_object != NULL) return ig_obj_create_begin (ig, button, x, y); /* If we are not configuring an object then clicking on the sheet * ends the edit. */ if (scg->selected_objects == NULL) wbcg_focus_cur_scg (wbcg); else if (wbc_gtk_get_guru (wbcg) == NULL) scg_mode_edit (scg); /* If we were already selecting a range of cells for a formula, * reset the location to a new place, or extend the selection. */ if (button == 1 && scg->rangesel.active) { ig->selecting = GNM_ITEM_GRID_SELECTING_FORMULA_RANGE; if (event->button.state & GDK_SHIFT_MASK) scg_rangesel_extend_to (scg, pos.col, pos.row); else scg_rangesel_bound (scg, pos.col, pos.row, pos.col, pos.row); gnm_pane_slide_init (pane); gnm_simple_canvas_grab (item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, NULL, gdk_event_get_time (event)); return TRUE; } /* If the user is editing a formula (wbcg_rangesel_possible) then we * enable the dynamic cell selection mode. */ if (button == 1 && wbcg_rangesel_possible (wbcg)) { scg_rangesel_start (scg, pos.col, pos.row, pos.col, pos.row); ig->selecting = GNM_ITEM_GRID_SELECTING_FORMULA_RANGE; gnm_pane_slide_init (pane); gnm_simple_canvas_grab (item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, NULL, gdk_event_get_time (event)); return TRUE; } /* While a guru is up ignore clicks */ if (wbc_gtk_get_guru (wbcg) != NULL) return TRUE; /* This was a regular click on a cell on the spreadsheet. Select it. * but only if the entered expression is valid */ if (!wbcg_edit_finish (wbcg, WBC_EDIT_ACCEPT, &edit_showed_dialog)) return TRUE; if (button == 1 && !sheet_selection_is_allowed (sheet, &pos)) return TRUE; /* Button == 1 is used to trigger hyperlinks (and possibly similar */ /* special cases. Otherwise button == 2 should behave exactly like */ /* button == 1. See bug #700792 */ /* buttons 1 and 2 will always change the selection, the other buttons will * only effect things if the target is not already selected. */ already_selected = sv_is_pos_selected (sv, pos.col, pos.row); if (button == 1 || button == 2 || !already_selected) { if (!(event->button.state & (GDK_CONTROL_MASK|GDK_SHIFT_MASK))) sv_selection_reset (sv); if ((event->button.button != 1 && event->button.button != 2) || !(event->button.state & GDK_SHIFT_MASK) || sv->selections == NULL) { sv_selection_add_pos (sv, pos.col, pos.row, (already_selected && (event->button.state & GDK_CONTROL_MASK)) ? GNM_SELECTION_MODE_REMOVE : GNM_SELECTION_MODE_ADD); sv_make_cell_visible (sv, pos.col, pos.row, FALSE); } else sv_selection_extend_to (sv, pos.col, pos.row); sheet_update (sheet); } if (edit_showed_dialog) return TRUE; /* we already ignored the button release */ switch (button) { case 1: case 2: { guint32 double_click_time; /* * If the second click is on a different cell than the * first one this cannot be a double-click */ if (already_selected) { g_object_get (gtk_widget_get_settings (GTK_WIDGET (canvas)), "gtk-double-click-time", &double_click_time, NULL); if ((ig->last_click_time + double_click_time) > gdk_event_get_time (event) && wbcg_edit_start (wbcg, FALSE, FALSE)) { break; } } ig->last_click_time = gdk_event_get_time (event); ig->selecting = GNM_ITEM_GRID_SELECTING_CELL_RANGE; gnm_pane_slide_init (pane); gnm_simple_canvas_grab (item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, NULL, gdk_event_get_time (event)); break; } case 3: scg_context_menu (scg, event, FALSE, FALSE); break; default : break; } return TRUE; }
static void cb_merge_merge_clicked (G_GNUC_UNUSED GtkWidget *ignore, MergeState *state) { GtkTreeIter this_iter; gint n = 0; char *data_string = NULL, *field_string = NULL; GSList *data_list = NULL, *field_list = NULL; GnmValue *v_zone; gint field_problems = 0; gint min_length = gnm_sheet_get_max_rows (state->sheet); gint max_length = 0; v_zone = gnm_expr_entry_parse_as_value (state->zone, state->sheet); g_return_if_fail (v_zone != NULL); while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (state->model), &this_iter, NULL, n)) { GnmValue *v_data, *v_field; gtk_tree_model_get (GTK_TREE_MODEL (state->model), &this_iter, DATA_RANGE, &data_string, FIELD_LOCATION, &field_string, -1); v_data = value_new_cellrange_str (state->sheet, data_string); v_field = value_new_cellrange_str (state->sheet, field_string); g_free (data_string); g_free (field_string); g_return_if_fail (v_data != NULL && v_field != NULL); if (!global_range_contained (state->sheet, v_field, v_zone)) field_problems++; data_list = g_slist_prepend (data_list, v_data); field_list = g_slist_prepend (field_list, v_field); n++; } if (field_problems > 0) { char *text; if (field_problems == 1) text = g_strdup (_("One field is not part of the merge zone!")); else text = g_strdup_printf (_("%i fields are not part of the merge zone!"), field_problems); go_gtk_notice_nonmodal_dialog ((GtkWindow *) state->dialog, &(state->warning_dialog), GTK_MESSAGE_ERROR, "%s", text); g_free (text); value_release (v_zone); range_list_destroy (data_list); range_list_destroy (field_list); return; } g_slist_foreach (data_list, cb_merge_find_shortest_column, &min_length); g_slist_foreach (data_list, cb_merge_find_longest_column, &max_length); if (min_length < max_length) { char *text = g_strdup_printf (_("The data columns range in length from " "%i to %i. Shall we trim the lengths to " "%i and proceed?"), min_length, max_length, min_length); if (go_gtk_query_yes_no (GTK_WINDOW (state->dialog), TRUE, "%s", text)) { g_slist_foreach (data_list, cb_merge_trim_data, &min_length); g_free (text); } else { g_free (text); value_release (v_zone); range_list_destroy (data_list); range_list_destroy (field_list); return; } } if (!cmd_merge_data (WORKBOOK_CONTROL (state->wbcg), state->sheet, v_zone, field_list, data_list)) gtk_widget_destroy (state->dialog); }
GString * cellregion_to_string (GnmCellRegion const *cr, gboolean only_visible, GODateConventions const *date_conv) { GString *all, *line; GnmCellCopy const *cc; int col, row, next_col_check, next_row_check; GnmRange extent; ColRowStateList const *col_state = NULL, *row_state = NULL; ColRowRLEState const *rle; int ncells, i; GnmStyle const *style; GOFormat const *fmt; g_return_val_if_fail (cr != NULL, NULL); g_return_val_if_fail (cr->rows >= 0, NULL); g_return_val_if_fail (cr->cols >= 0, NULL); /* pre-allocate rough approximation of buffer */ ncells = cr->cell_content ? g_hash_table_size (cr->cell_content) : 0; all = g_string_sized_new (20 * ncells + 1); line = g_string_new (NULL); cellregion_extent (cr, &extent); if (only_visible && NULL != (row_state = cr->row_state)) { next_row_check = i = 0; while ((i += ((ColRowRLEState *)(row_state->data))->length) <= extent.start.row) { if (NULL == (row_state = row_state->next)) { next_row_check = gnm_sheet_get_max_rows (cr->origin_sheet); break; } next_row_check = i; } } else next_row_check = gnm_sheet_get_max_rows (cr->origin_sheet); for (row = extent.start.row; row <= extent.end.row;) { if (row >= next_row_check) { rle = row_state->data; row_state = row_state->next; next_row_check += rle->length; if (!rle->state.visible) { row = next_row_check; continue; } } g_string_assign (line, ""); if (only_visible && NULL != (col_state = cr->col_state)) { next_col_check = i = 0; while ((i += ((ColRowRLEState *)(col_state->data))->length) <= extent.start.col) { if (NULL == (col_state = col_state->next)) { next_col_check = gnm_sheet_get_max_cols (cr->origin_sheet); break; } next_col_check = i; } } else next_col_check = gnm_sheet_get_max_cols (cr->origin_sheet); for (col = extent.start.col; col <= extent.end.col;) { if (col == next_col_check) { rle = col_state->data; col_state = col_state->next; next_col_check += rle->length; if (!rle->state.visible) { col = next_col_check; continue; } } cc = cellregion_get_content (cr, col, row); if (cc) { style = style_list_get_style (cr->styles, col, row); fmt = gnm_style_get_format (style); if (go_format_is_general (fmt) && VALUE_FMT (cc->val)) fmt = VALUE_FMT (cc->val); format_value_gstring (line, fmt, cc->val, -1, date_conv); } if (++col <= extent.end.col) g_string_append_c (line, '\t'); } g_string_append_len (all, line->str, line->len); if (++row <= extent.end.row) g_string_append_c (all, '\n'); } g_string_free (line, TRUE); return all; }