Update Spanish translation
[gnumeric.git] / src / position.c
blob81490ec76bdde9de62dc1e51b13b5dbfd0fd0a07
1 /*
2 * position.c: Utility routines for various types of positional
3 * coordinates.
5 * Copyright (C) 2000-2005 Jody Goldberg (jody@gnome.org)
6 * Copyright (C) 2006-2009 Morten Welinder (terra@gnome.org)
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
21 * USA
23 #include <gnumeric-config.h>
24 #include <gnumeric.h>
25 #include <libgnumeric.h>
26 #include <position.h>
28 #include <sheet.h>
29 #include <sheet-view.h>
30 #include <cell.h>
31 #include <value.h>
32 #include <ranges.h>
33 #include <string.h>
34 #include <workbook.h>
36 /* GnmCellPos made a boxed type */
37 static GnmCellPos *
38 gnm_cell_pos_dup (GnmCellPos *pos)
40 GnmCellPos *res = g_new (GnmCellPos, 1);
41 *res = *pos;
42 return res;
45 GType
46 gnm_cell_pos_get_type (void)
48 static GType t = 0;
50 if (t == 0) {
51 t = g_boxed_type_register_static ("GnmCellPos",
52 (GBoxedCopyFunc)gnm_cell_pos_dup,
53 (GBoxedFreeFunc)g_free);
55 return t;
58 /* GnmEvalPos made a boxed type */
59 static GnmEvalPos *
60 gnm_eval_pos_dup (GnmEvalPos *ep)
62 return g_memdup (ep, sizeof (*ep));
65 GType
66 gnm_eval_pos_get_type (void)
68 static GType t = 0;
70 if (t == 0) {
71 t = g_boxed_type_register_static ("GnmEvalPos",
72 (GBoxedCopyFunc)gnm_eval_pos_dup,
73 (GBoxedFreeFunc)g_free);
75 return t;
78 /**
79 * eval_pos_init:
80 * @ep: The position to init.
81 * @s: #Sheet
82 * @col: column.
83 * @row: row
85 * Returns: (skip) (transfer none): the initialized #GnmEvalPos (@ep).
86 **/
87 GnmEvalPos *
88 eval_pos_init (GnmEvalPos *ep, Sheet *sheet, int col, int row)
90 g_return_val_if_fail (ep != NULL, NULL);
91 g_return_val_if_fail (sheet != NULL, NULL);
93 ep->eval.col = col;
94 ep->eval.row = row;
95 ep->sheet = sheet;
96 ep->dep = NULL;
97 ep->array_texpr = NULL;
99 return ep;
103 * eval_pos_init_pos:
104 * @ep: The position to init.
105 * @s: #Sheet
106 * @pos: #GnmCellPos
108 * Returns: (skip) (transfer none): the initialized #GnmEvalPos (@ep).
110 GnmEvalPos *
111 eval_pos_init_pos (GnmEvalPos *ep, Sheet *sheet, GnmCellPos const *pos)
113 g_return_val_if_fail (ep != NULL, NULL);
114 g_return_val_if_fail (sheet != NULL, NULL);
115 g_return_val_if_fail (pos != NULL, NULL);
117 ep->eval = *pos;
118 ep->sheet = sheet;
119 ep->dep = NULL;
120 ep->array_texpr = NULL;
122 return ep;
126 * eval_pos_init_dep:
127 * @ep: The position to init.
128 * @dep:
130 * Returns: (skip) (transfer none): the initialized #GnmEvalPos (@ep).
132 GnmEvalPos *
133 eval_pos_init_dep (GnmEvalPos *ep, GnmDependent const *dep)
135 g_return_val_if_fail (ep != NULL, NULL);
136 g_return_val_if_fail (dep != NULL, NULL);
138 ep->eval = *dependent_pos (dep);
139 ep->sheet = dep->sheet;
140 ep->dep = (GnmDependent *)dep;
141 ep->array_texpr = NULL;
143 return ep;
147 * eval_pos_init_editpos:
148 * @ep: The position to init.
149 * @sv: @Sheetview
151 * The function initializes an evalpos with the edit position from the
152 * given sheetview.
153 * Returns: (skip) (transfer none): the initialized #GnmEvalPos (@ep).
155 GnmEvalPos *
156 eval_pos_init_editpos (GnmEvalPos *ep, SheetView const *sv)
158 g_return_val_if_fail (ep != NULL, NULL);
159 g_return_val_if_fail (GNM_IS_SHEET_VIEW (sv), NULL);
161 return eval_pos_init (ep, sv_sheet (sv),
162 sv->edit_pos.col, sv->edit_pos.row);
166 * eval_pos_init_cell:
167 * @ep: The position to init.
168 * @cell: A cell
170 * The function initializes an evalpos with the given cell
172 * Returns: (skip) (transfer none): the initialized #GnmEvalPos (@ep).
174 GnmEvalPos *
175 eval_pos_init_cell (GnmEvalPos *ep, GnmCell const *cell)
177 g_return_val_if_fail (ep != NULL, NULL);
178 g_return_val_if_fail (cell != NULL, NULL);
180 ep->eval = cell->pos;
181 ep->sheet = cell->base.sheet;
182 ep->dep = (GnmDependent *)GNM_CELL_TO_DEP (cell);
183 ep->array_texpr = NULL;
185 return ep;
189 * eval_pos_init_sheet:
190 * @ep: The position to init.
191 * @sheet: A sheet
193 * The function initializes an evalpos with the given sheet.
195 * Returns: (skip) (transfer none): the initialized #GnmEvalPos (@ep).
197 GnmEvalPos *
198 eval_pos_init_sheet (GnmEvalPos *ep, Sheet const *sheet)
200 g_return_val_if_fail (ep != NULL, NULL);
201 g_return_val_if_fail (IS_SHEET (sheet), NULL);
203 ep->eval.col = ep->eval.row = 0;
204 ep->sheet = (Sheet *)sheet;
205 ep->dep = NULL;
206 ep->array_texpr = NULL;
208 return ep;
211 gboolean
212 eval_pos_is_array_context (GnmEvalPos const *ep)
214 return ep->array_texpr != NULL;
218 static GnmParsePos *
219 gnm_parse_pos_dup (GnmParsePos *pp)
221 return g_memdup (pp, sizeof (*pp));
224 GType
225 gnm_parse_pos_get_type (void)
227 static GType t = 0;
229 if (t == 0) {
230 t = g_boxed_type_register_static ("GnmParsePos",
231 (GBoxedCopyFunc)gnm_parse_pos_dup,
232 (GBoxedFreeFunc)g_free);
234 return t;
238 * parse_pos_init:
239 * @pp: The position to init.
240 * @sheet: The sheet being selected
241 * @wb: The workbook being selected.
242 * @row:
243 * @col:
245 * Use either a sheet (preferred) or a workbook to initialize the supplied
246 * ParsePosition.
247 * Returns: (skip) (transfer none): the initialized #GnmParsePos (@pp).
249 GnmParsePos *
250 parse_pos_init (GnmParsePos *pp, Workbook *wb, Sheet const *sheet,
251 int col, int row)
253 /* Global */
254 if (wb == NULL && sheet == NULL)
255 return NULL;
257 g_return_val_if_fail (pp != NULL, NULL);
259 pp->sheet = (Sheet *)sheet;
260 pp->wb = sheet ? sheet->workbook : wb;
261 pp->eval.col = col;
262 pp->eval.row = row;
264 return pp;
268 * parse_pos_init_dep:
269 * @pp: The position to init.
270 * @dep: The dependent
272 * Returns: (skip) (transfer none): the initialized #GnmParsePos (@pp).
274 GnmParsePos *
275 parse_pos_init_dep (GnmParsePos *pp, GnmDependent const *dep)
277 g_return_val_if_fail (pp != NULL, NULL);
279 pp->sheet = dep->sheet;
280 pp->wb = dep->sheet ? dep->sheet->workbook : NULL;
281 pp->eval = *dependent_pos (dep);
283 return pp;
287 * parse_pos_init_cell:
288 * @pp: The position to init.
289 * @cell: The cell
291 * Returns: (skip) (transfer none): the initialized #GnmParsePos (@pp).
293 GnmParsePos *
294 parse_pos_init_cell (GnmParsePos *pp, GnmCell const *cell)
296 g_return_val_if_fail (cell != NULL, NULL);
297 g_return_val_if_fail (IS_SHEET (cell->base.sheet), NULL);
298 g_return_val_if_fail (cell->base.sheet->workbook != NULL, NULL);
300 return parse_pos_init (pp, NULL, cell->base.sheet,
301 cell->pos.col, cell->pos.row);
305 * parse_pos_init_evalpos:
306 * @pp: The position to init.
307 * @pos: #GnmEvalPos
309 * Returns: (skip) (transfer none): the initialized #GnmParsePos (@pp).
311 GnmParsePos *
312 parse_pos_init_evalpos (GnmParsePos *pp, GnmEvalPos const *ep)
314 g_return_val_if_fail (ep != NULL, NULL);
316 return parse_pos_init (pp, NULL, ep->sheet, ep->eval.col, ep->eval.row);
320 * parse_pos_init_editpos:
321 * @pp: The position to init.
322 * @sv: sheet view
324 * Returns: (skip) (transfer none): the initialized #GnmParsePos (@pp).
326 GnmParsePos *
327 parse_pos_init_editpos (GnmParsePos *pp, SheetView const *sv)
329 g_return_val_if_fail (GNM_IS_SHEET_VIEW (sv), NULL);
331 return parse_pos_init (pp, NULL, sv_sheet (sv),
332 sv->edit_pos.col, sv->edit_pos.row);
336 * parse_pos_init_sheet:
337 * @pp: The position to init.
338 * @sheet: The sheet
340 * Returns: (skip) (transfer none): the initialized #GnmParsePos (@pp).
342 GnmParsePos *
343 parse_pos_init_sheet (GnmParsePos *pp, Sheet const *sheet)
345 g_return_val_if_fail (pp != NULL, NULL);
346 g_return_val_if_fail (IS_SHEET (sheet), NULL);
347 return parse_pos_init (pp, NULL, sheet, 0, 0);
350 /********************************************************************************/
353 static GnmCellRef *
354 gnm_cellref_dup (GnmCellRef *cr)
356 return g_memdup (cr, sizeof (*cr));
359 GType
360 gnm_cellref_get_type (void)
362 static GType t = 0;
364 if (t == 0) {
365 t = g_boxed_type_register_static ("GnmCellRef",
366 (GBoxedCopyFunc)gnm_cellref_dup,
367 (GBoxedFreeFunc)g_free);
369 return t;
371 GnmCellRef *
372 gnm_cellref_init (GnmCellRef *ref, Sheet *sheet, int col, int row, gboolean relative)
374 ref->sheet = sheet;
375 ref->col = col;
376 ref->row = row;
377 ref->col_relative = ref->row_relative = relative;
379 return ref;
382 gboolean
383 gnm_cellref_equal (GnmCellRef const *a, GnmCellRef const *b)
385 return (a->col == b->col) &&
386 (a->col_relative == b->col_relative) &&
387 (a->row == b->row) &&
388 (a->row_relative == b->row_relative) &&
389 (a->sheet == b->sheet);
392 guint
393 gnm_cellref_hash (GnmCellRef const *cr)
395 guint h = cr->row;
396 h = (h << 16) | (h >> 16);
397 h ^= ((guint)cr->col << 2);
398 if (cr->col_relative) h ^= 1;
399 if (cr->row_relative) h ^= 2;
400 return h;
404 gnm_cellref_get_col (GnmCellRef const *ref, GnmEvalPos const *ep)
406 g_return_val_if_fail (ref != NULL, 0);
407 g_return_val_if_fail (ep != NULL, 0);
409 if (ref->col_relative) {
410 Sheet const *sheet = eval_sheet (ref->sheet, ep->sheet);
411 int res = (ep->eval.col + ref->col) % gnm_sheet_get_max_cols (sheet);
412 if (res < 0)
413 return res + gnm_sheet_get_max_cols (sheet);
414 return res;
416 return ref->col;
420 gnm_cellref_get_row (GnmCellRef const *ref, GnmEvalPos const *ep)
422 g_return_val_if_fail (ref != NULL, 0);
423 g_return_val_if_fail (ep != NULL, 0);
425 if (ref->row_relative) {
426 Sheet const *sheet = eval_sheet (ref->sheet, ep->sheet);
427 int res = (ep->eval.row + ref->row) % gnm_sheet_get_max_rows (sheet);
428 if (res < 0)
429 return res + gnm_sheet_get_max_rows (sheet);
430 return res;
432 return ref->row;
435 static int
436 modulo (int i, int max)
438 if (i < 0) {
439 i %= max;
440 if (i < 0)
441 i += max;
442 } else if (i >= max)
443 i %= max;
445 return i;
449 void
450 gnm_cellpos_init_cellref_ss (GnmCellPos *res, GnmCellRef const *cell_ref,
451 GnmCellPos const *pos, GnmSheetSize const *ss)
453 g_return_if_fail (cell_ref != NULL);
454 g_return_if_fail (res != NULL);
456 if (cell_ref->col_relative) {
457 int col = cell_ref->col + pos->col;
458 res->col = modulo (col, ss->max_cols);
459 } else
460 res->col = cell_ref->col;
462 if (cell_ref->row_relative) {
463 int row = cell_ref->row + pos->row;
464 res->row = modulo (row, ss->max_rows);
465 } else
466 res->row = cell_ref->row;
469 void
470 gnm_cellpos_init_cellref (GnmCellPos *res, GnmCellRef const *cell_ref,
471 GnmCellPos const *pos, Sheet const *base_sheet)
473 Sheet const *sheet = eval_sheet (cell_ref->sheet, base_sheet);
474 gnm_cellpos_init_cellref_ss (res, cell_ref, pos,
475 gnm_sheet_get_size (sheet));
478 void
479 gnm_cellref_make_abs (GnmCellRef *dest, GnmCellRef const *src, GnmEvalPos const *ep)
481 GnmCellPos pos;
483 g_return_if_fail (dest != NULL);
484 g_return_if_fail (src != NULL);
485 g_return_if_fail (ep != NULL);
487 gnm_cellpos_init_cellref (&pos, src, &ep->eval, ep->sheet);
489 dest->sheet = src->sheet;
490 dest->col = pos.col;
491 dest->row = pos.row;
492 dest->col_relative = FALSE;
493 dest->row_relative = FALSE;
496 void
497 gnm_cellref_set_col_ar (GnmCellRef *cr, GnmParsePos const *pp, gboolean abs_rel)
499 if (cr->col_relative ^ abs_rel) {
500 if (cr->col_relative)
501 cr->col += pp->eval.col;
502 else
503 cr->col -= pp->eval.col;
504 cr->col_relative = abs_rel;
508 void
509 gnm_cellref_set_row_ar (GnmCellRef *cr, GnmParsePos const *pp, gboolean abs_rel)
511 if (cr->row_relative ^ abs_rel) {
512 if (cr->row_relative)
513 cr->row += pp->eval.row;
514 else
515 cr->row -= pp->eval.row;
516 cr->row_relative = abs_rel;
520 gboolean
521 gnm_rangeref_equal (GnmRangeRef const *a, GnmRangeRef const *b)
523 return gnm_cellref_equal (&a->a, &b->a) &&
524 gnm_cellref_equal (&a->b, &b->b);
527 guint
528 gnm_rangeref_hash (GnmRangeRef const *rr)
530 guint h = gnm_cellref_hash (&rr->a);
531 h = (h << 16) | (h >> 16);
532 h ^= gnm_cellref_hash (&rr->b);
533 return h;
536 GnmRangeRef *
537 gnm_rangeref_dup (GnmRangeRef const *rr)
539 GnmRangeRef *res;
541 g_return_val_if_fail (rr != NULL, NULL);
543 res = g_new (GnmRangeRef, 1);
544 *res = *rr;
545 return res;
548 GType
549 gnm_rangeref_get_type (void)
551 static GType t = 0;
553 if (t == 0) {
554 t = g_boxed_type_register_static ("GnmRangeRef",
555 (GBoxedCopyFunc)gnm_rangeref_dup,
556 (GBoxedFreeFunc)g_free);
558 return t;
561 void
562 gnm_rangeref_normalize_pp (GnmRangeRef const *ref, GnmParsePos const *pp,
563 Sheet **start_sheet, Sheet **end_sheet,
564 GnmRange *dest)
566 GnmSheetSize const *ss;
568 g_return_if_fail (ref != NULL);
569 g_return_if_fail (pp != NULL);
571 *start_sheet = eval_sheet (ref->a.sheet, pp->sheet);
572 *end_sheet = eval_sheet (ref->b.sheet, *start_sheet);
574 ss = gnm_sheet_get_size2 (*start_sheet, pp->wb);
575 gnm_cellpos_init_cellref_ss (&dest->start, &ref->a, &pp->eval, ss);
577 ss = *end_sheet
578 ? gnm_sheet_get_size (*end_sheet)
579 : ss;
580 gnm_cellpos_init_cellref_ss (&dest->end, &ref->b, &pp->eval, ss);
582 range_normalize (dest);
586 * gnm_rangeref_normalize:
588 * Take a range_ref and normalize it by converting to absolute coords and
589 * handling inversions.
591 void
592 gnm_rangeref_normalize (GnmRangeRef const *ref, GnmEvalPos const *ep,
593 Sheet **start_sheet, Sheet **end_sheet, GnmRange *dest)
595 GnmParsePos pp;
597 parse_pos_init_evalpos (&pp, ep);
598 gnm_rangeref_normalize_pp (ref, &pp, start_sheet, end_sheet, dest);
601 guint
602 gnm_cellpos_hash (GnmCellPos const *key)
604 guint h = key->row;
605 h = (h << 16) | (h >> 16);
606 h ^= key->col;
607 return h;
610 gint
611 gnm_cellpos_equal (GnmCellPos const *a, GnmCellPos const *b)
613 return (a->row == b->row && a->col == b->col);