/** * sv_is_full_colrow_selected * @sv : * @is_cols : * @index : * * Returns TRUE if all of the selected cols/rows in the selection * are fully selected and the selection contains the specified col. **/ gboolean sv_is_full_colrow_selected (SheetView const *sv, gboolean is_cols, int index) { GSList *l; gboolean found = FALSE; g_return_val_if_fail (IS_SHEET_VIEW (sv), FALSE); for (l = sv->selections; l != NULL; l = l->next){ GnmRange const *r = l->data; if (is_cols) { if (r->start.row > 0 || r->end.row < gnm_sheet_get_last_row (sv->sheet)) return FALSE; if (r->start.col <= index && index <= r->end.col) found = TRUE; } else { if (r->start.col > 0 || r->end.col < gnm_sheet_get_last_col (sv->sheet)) return FALSE; if (r->start.row <= index && index <= r->end.row) found = TRUE; } } return found; }
static gboolean sheet_cell_or_one_below_is_not_empty (Sheet *sheet, int col, int row) { return !sheet_is_cell_empty (sheet, col, row) || (row < gnm_sheet_get_last_row (sheet) && !sheet_is_cell_empty (sheet, col, row+1)); }
/** * sv_selection_col_type : * @sv : * @col : * * Returns How much of column @col is selected in @sv. **/ ColRowSelectionType sv_selection_col_type (SheetView const *sv, int col) { GSList *ptr; GnmRange const *sr; int ret = COL_ROW_NO_SELECTION; g_return_val_if_fail (IS_SHEET_VIEW (sv), COL_ROW_NO_SELECTION); if (sv->selections == NULL) return COL_ROW_NO_SELECTION; for (ptr = sv->selections; ptr != NULL; ptr = ptr->next) { sr = ptr->data; if (sr->start.col > col || sr->end.col < col) continue; if (sr->start.row == 0 && sr->end.row == gnm_sheet_get_last_row (sv->sheet)) return COL_ROW_FULL_SELECTION; ret = COL_ROW_PARTIAL_SELECTION; } return ret; }
/** * range_ensure_sanity : * @range : the range to check * @sheet : the sheet in which @range lives * * Silently clip a range to ensure that it does not contain areas * outside the valid bounds. Does NOT fix inverted ranges. **/ void range_ensure_sanity (GnmRange *range, Sheet const *sheet) { range->start.col = MAX (0, range->start.col); range->end.col = MIN (range->end.col, gnm_sheet_get_last_col (sheet)); range->start.row = MAX (0, range->start.row); range->end.row = MIN (range->end.row, gnm_sheet_get_last_row (sheet)); }
GnmRange * range_init_cols (GnmRange *r, Sheet const *sheet, int start_col, int end_col) { r->start.col = start_col; r->start.row = 0; r->end.col = end_col; r->end.row = gnm_sheet_get_last_row (sheet); return r; }
GnmRange * range_init_full_sheet (GnmRange *r, Sheet const *sheet) { r->start.col = 0; r->start.row = 0; r->end.col = gnm_sheet_get_last_col (sheet); r->end.row = gnm_sheet_get_last_row (sheet); return r; }
/** * range_is_full : * @r : the range. * @sheet : the sheet in which @r lives * @horiz : TRUE to check for a horizontal full ref (_cols_ [0..MAX)) * * This determines whether @r completely spans a sheet * in the dimension specified by @horiz. * * Return value: TRUE if it is infinite else FALSE **/ gboolean range_is_full (GnmRange const *r, Sheet const *sheet, gboolean horiz) { if (horiz) return (r->start.col <= 0 && r->end.col >= gnm_sheet_get_last_col (sheet)); else return (r->start.row <= 0 && r->end.row >= gnm_sheet_get_last_row (sheet)); }
void colrow_autofit_col (Sheet *sheet, GnmRange *r) { colrow_autofit (sheet, r, TRUE, TRUE, TRUE, FALSE, NULL, NULL); sheet_foreach_cell_in_range (sheet, CELL_ITER_IGNORE_BLANK, r->start.col, 0, r->end.col, gnm_sheet_get_last_row (sheet), (CellIterFunc) &cb_clear_variable_width_content, NULL); }
/** * sv_select_cur_col: * @sv: The sheet * * Selects an entire column */ void sv_select_cur_col (SheetView *sv) { GnmRange const *sel = selection_first_range (sv, NULL, NULL); if (sel != NULL) { GnmRange r = *sel; sv_selection_reset (sv); sv_selection_add_full (sv, sv->edit_pos.col, sv->edit_pos.row, r.start.col, 0, r.end.col, gnm_sheet_get_last_row (sv->sheet)); sheet_update (sv->sheet); } }
void filter_show_all (WorkbookControl *wbc) { Sheet *sheet = wb_control_cur_sheet (wbc); /* FIXME: This is slow. We should probably have a linked list * containing the filtered rows in the sheet structure. */ colrow_foreach (&sheet->rows, 0, gnm_sheet_get_last_row (sheet), (ColRowHandler) cb_show_all, sheet); sheet->has_filtered_rows = FALSE; sheet_redraw_all (sheet, TRUE); wb_control_menu_state_update (wbc, MS_FILTER_STATE_CHANGED); }
/* * sv_is_colrow_selected : * @sv : containing the selection * @colrow: The column or row number we are interested in. * @is_col: A flag indicating whether this it is a column or a row. * * Searches the selection list to see whether the entire col/row specified is * contained by the section regions. Since the selection is stored as the set * overlapping user specifed regions we can safely search for the range directly. * * Eventually to be completely correct and deal with the case of someone manually * selection an entire col/row, in separate chunks, we will need to do something * more advanced. */ gboolean sv_is_colrow_selected (SheetView const *sv, int colrow, gboolean is_col) { GSList *l; for (l = sv->selections; l != NULL; l = l->next) { GnmRange const *ss = l->data; if (is_col) { if (ss->start.row == 0 && ss->end.row >= gnm_sheet_get_last_row (sv->sheet) && ss->start.col <= colrow && colrow <= ss->end.col) return TRUE; } else { if (ss->start.col == 0 && ss->end.col >= gnm_sheet_get_last_col (sv->sheet) && ss->start.row <= colrow && colrow <= ss->end.row) return TRUE; } } return FALSE; }
/* * colrow_set_visibility_list : * * This is the high level command that is wrapped by undo and redo. * It should not be called by other commands. */ void colrow_set_visibility_list (Sheet *sheet, gboolean is_cols, gboolean visible, ColRowVisList *list) { ColRowVisList *ptr; ColRowIndex *info; for (ptr = list; ptr != NULL ; ptr = ptr->next) { info = ptr->data; colrow_set_visibility (sheet, is_cols, visible, info->first, info->last); } if (visible) sheet_colrow_optimize (sheet); if (is_cols) sheet_queue_respan (sheet, 0, gnm_sheet_get_last_row (sheet)); if (list != NULL) sheet_redraw_all (sheet, TRUE); }
/** * 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); }
/** * cmd_shift_cols: * @wbc: The error context. * @sheet: the sheet * @start_col: first column * @end_col: end column * @row: row marking the start of the shift * @count: numbers of rows to shift. a negative numbers will * delete count rows, positive number will insert * count rows. * * Takes the cells in the region (start_col,row):(end_col,MAX_ROW) * and copies them @count units (possibly negative) downwards. */ void cmd_shift_cols (WorkbookControl *wbc, Sheet *sheet, int start_col, int end_col, int row, int count) { GnmExprRelocateInfo rinfo; char *desc; rinfo.reloc_type = GNM_EXPR_RELOCATE_MOVE_RANGE; rinfo.col_offset = 0; rinfo.row_offset = count; rinfo.origin_sheet = rinfo.target_sheet = sheet; rinfo.origin.start.col = start_col; rinfo.origin.start.row = row; rinfo.origin.end.col = end_col; rinfo.origin.end.row = gnm_sheet_get_last_row (sheet); if (count > 0) rinfo.origin.end.row -= count; desc = g_strdup_printf ((start_col != end_col) ? _("Shift columns %s") : _("Shift column %s"), cols_name (start_col, end_col)); cmd_paste_cut (wbc, &rinfo, FALSE, desc); }
void colrow_restore_state_group (Sheet *sheet, gboolean is_cols, ColRowIndexList *selection, ColRowStateGroup *state_groups) { ColRowStateGroup *ptr = state_groups; /* Cycle to end, we have to traverse the selections * in parallel with the state_groups */ selection = g_list_last (selection); for (; selection != NULL && ptr != NULL ; ptr = ptr->next) { ColRowIndex const *index = selection->data; ColRowStateList *list = ptr->data; ColRowRLEState const *rles = list->data; /* MAGIC : the -1 was set above to flag this */ if (rles->length == -1) { if (is_cols) sheet_col_set_default_size_pts (sheet, rles->state.size_pts); else sheet_row_set_default_size_pts (sheet, rles->state.size_pts); /* we are guaranteed to have at least 1 more record */ ptr = ptr->next; } colrow_set_states (sheet, is_cols, index->first, ptr->data); /* force a re-render of cells with expanding formats */ if (is_cols) sheet_foreach_cell_in_range (sheet, CELL_ITER_IGNORE_BLANK, index->first, 0, index->last, gnm_sheet_get_last_row (sheet), (CellIterFunc) &cb_clear_variable_width_content, NULL); selection = selection->prev; } }
static void resize_columns (Sheet *sheet) { GnmRange r; if (gnm_debug_flag ("stf")) g_printerr ("Auto-fitting columns...\n"); /* If we have lots of rows, auto-fitting will take a very long time. It is probably better to look at only, say, 1000 rows of data. */ range_init_full_sheet (&r, sheet); r.end.row = MIN (r.end.row, 1000); colrow_autofit (sheet, &r, TRUE, TRUE, /* Ignore strings */ TRUE, /* Don't shrink */ TRUE, /* Don't shrink */ NULL, NULL); if (gnm_debug_flag ("stf")) g_printerr ("Auto-fitting columns... done\n"); sheet_queue_respan (sheet, 0, gnm_sheet_get_last_row (sheet)); }
/** * colrow_set_sizes: * @sheet: #Sheet * @is_cols: * @src: * @new_size: * @from: * @to: * * Returns: (transfer full): **/ ColRowStateGroup * colrow_set_sizes (Sheet *sheet, gboolean is_cols, ColRowIndexList *src, int new_size, int from, int to) /* from & to are used to restrict fitting to that range. Pass 0, -1 if you want to use the */ /* whole row/column */ { int i; ColRowStateGroup *res = NULL; ColRowIndexList *ptr; for (ptr = src; ptr != NULL ; ptr = ptr->next) { ColRowIndex const *index = ptr->data; res = g_slist_prepend (res, colrow_get_states (sheet, is_cols, index->first, index->last)); /* FIXME : * If we are changing the size of more than half of the rows/col to * something specific (not autosize) we should change the default * row/col size instead. However, it is unclear how to handle * hard sizing. * * we need better management of rows/cols. Currently if they are all * defined calculation speed grinds to a halt. */ if (new_size > 0 && index->first == 0 && (index->last+1) >= colrow_max (is_cols, sheet)) { struct resize_closure closure; ColRowRLEState *rles = g_new0 (ColRowRLEState, 1); rles->length = -1; /* Flag as changing the default */ closure.sheet = sheet; closure.new_size = new_size; closure.is_cols = is_cols; if (is_cols) { rles->state.size_pts = sheet_col_get_default_size_pts (sheet); sheet_col_set_default_size_pixels (sheet, new_size); colrow_foreach (&sheet->cols, 0, gnm_sheet_get_last_col (sheet), &cb_set_colrow_size, &closure); } else { rles->state.size_pts = sheet_row_get_default_size_pts (sheet); sheet_row_set_default_size_pixels (sheet, new_size); colrow_foreach (&sheet->rows, 0, gnm_sheet_get_last_row (sheet), &cb_set_colrow_size, &closure); } /* force a re-render of cells with expanding formats */ if (is_cols) sheet_foreach_cell_in_range (sheet, CELL_ITER_IGNORE_BLANK, 0, 0, gnm_sheet_get_last_col (sheet), gnm_sheet_get_last_row (sheet), (CellIterFunc) &cb_clear_variable_width_content, NULL); /* Result is a magic 'default' record + >= 1 normal */ return g_slist_prepend (res, g_slist_append (NULL, rles)); } if (is_cols) { /* force a re-render of cells with expanding formats */ sheet_foreach_cell_in_range (sheet, CELL_ITER_IGNORE_BLANK, index->first, 0, index->last, gnm_sheet_get_last_row (sheet), (CellIterFunc) &cb_clear_variable_width_content, NULL); /* In order to properly reposition cell comments in * merged cells that cross the boundary we need to do * everything. Remove this when comments are handled * properly */ sheet->priv->reposition_objects.col = 0; } for (i = index->first ; i <= index->last ; ++i) { int tmp = new_size; if (tmp < 0) { int max = is_cols ? gnm_sheet_get_last_row (sheet) : gnm_sheet_get_last_col (sheet); if (from < 0) from = 0; if (to < 0 || to > max) to = max; if (from > max) from = to; /* Fall back to assigning the default if it is empty */ tmp = (is_cols) ? sheet_col_size_fit_pixels (sheet, i, from, to, FALSE) : sheet_row_size_fit_pixels (sheet, i, from, to, FALSE); } if (tmp > 0) { if (is_cols) sheet_col_set_size_pixels (sheet, i, tmp, new_size > 0); else sheet_row_set_size_pixels (sheet, i, tmp, new_size > 0); } else if (sheet_colrow_get (sheet, i, is_cols) != NULL) { if (is_cols) sheet_col_set_size_pixels (sheet, i, sheet_col_get_default_size_pixels (sheet), FALSE); else sheet_row_set_size_pixels (sheet, i, sheet_row_get_default_size_pixels (sheet), FALSE); } } } return res; }
/** * range_transpose: * @range: The range. * @sheet : the sheet in which @range lives * @boundary: The box to transpose inside * * Effectively mirrors the ranges in 'boundary' around a * leading diagonal projected from offset. * * Return value: whether we clipped the range. **/ gboolean range_transpose (GnmRange *range, Sheet const *sheet, GnmCellPos const *origin) { gboolean clipped = FALSE; GnmRange src; int t; int last_col = gnm_sheet_get_last_col (sheet); int last_row = gnm_sheet_get_last_row (sheet); g_return_val_if_fail (range != NULL, TRUE); src = *range; /* Start col */ t = origin->col + (src.start.row - origin->row); if (t > last_col) { clipped = TRUE; range->start.col = last_col; } else if (t < 0) { clipped = TRUE; range->start.col = 0; } range->start.col = t; /* Start row */ t = origin->row + (src.start.col - origin->col); if (t > last_row) { clipped = TRUE; range->start.row = last_row; } else if (t < 0) { clipped = TRUE; range->start.row = 0; } range->start.row = t; /* End col */ t = origin->col + (src.end.row - origin->row); if (t > last_col) { clipped = TRUE; range->end.col = last_col; } else if (t < 0) { clipped = TRUE; range->end.col = 0; } range->end.col = t; /* End row */ t = origin->row + (src.end.col - origin->col); if (t > last_row) { clipped = TRUE; range->end.row = last_row; } else if (t < 0) { clipped = TRUE; range->end.row = 0; } range->end.row = t; g_assert (range_valid (range)); return clipped; }