Whitespace.
[gnumeric.git] / src / sheet-object-cell-comment.c
blob365bc70a43c84e356d5413d68a2184192e418e38
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /*
4 * sheet-object-cell-comment.c: A SheetObject to support cell comments.
6 * Copyright (C) 2000-2004 Jody Goldberg (jody@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 "sheet-object-cell-comment.h"
27 #include "gnm-pane-impl.h"
28 #include "sheet-object-impl.h"
29 #include "sheet.h"
30 #include "sheet-view.h"
31 #include "sheet-merge.h"
32 #include "sheet-control-gui-priv.h"
33 #include "dialogs.h"
34 #include "gui-util.h"
35 #include <goffice/goffice.h>
37 #include <string.h>
38 #include <libxml/globals.h>
39 #include <gsf/gsf-impl-utils.h>
41 struct _GnmComment {
42 SheetObject base;
44 char *author, *text;
45 PangoAttrList *markup;
47 typedef SheetObjectClass GnmCommentClass;
48 static GObjectClass *cell_comment_parent_class;
49 enum {
50 CC_PROP_0,
51 CC_PROP_TEXT,
52 CC_PROP_AUTHOR,
53 CC_PROP_MARKUP
56 typedef struct {
57 SheetObjectView base;
59 GdkRGBA comment_indicator_color;
60 int comment_indicator_size;
61 } CommentView;
62 typedef SheetObjectViewClass CommentViewClass;
63 static GocItemClass *comment_view_parent_class;
65 static void
66 comment_view_reload_style (CommentView *cv)
68 GocItem *item = GOC_ITEM (cv);
69 GnmPane *pane = GNM_PANE (item->canvas);
70 GtkStyleContext *context;
72 context = goc_item_get_style_context (item);
73 gnm_style_context_get_color (context, GTK_STATE_FLAG_NORMAL,
74 &cv->comment_indicator_color);
76 context = gtk_widget_get_style_context (GTK_WIDGET (pane));
77 gtk_widget_style_get (GTK_WIDGET (pane),
78 "comment-indicator-size",
79 &cv->comment_indicator_size,
80 NULL);
83 static void
84 comment_view_set_bounds (SheetObjectView *sov, double const *coords, gboolean visible)
86 CommentView *cv = (CommentView *)sov;
87 GocPoints *points = goc_points_new (3);
88 GocItem *item = GOC_ITEM (GOC_GROUP (sov)->children->data);
89 if (visible) {
90 SheetObject *so = sheet_object_view_get_so (sov);
91 SheetControlGUI const *scg = GNM_SIMPLE_CANVAS (item->canvas)->scg;
92 double scale;
93 gint64 x, y, dx;
94 int far_col;
95 GnmRange const *r = gnm_sheet_merge_is_corner (so->sheet,
96 &so->anchor.cell_bound.start);
98 scale = 1. / item->canvas->pixels_per_unit;
100 if (r != NULL)
101 far_col = 1 + r->end.col;
102 else
103 far_col = 1 + so->anchor.cell_bound.start.col;
105 /* TODO : This could be optimized using the offsets associated with the visible region */
106 /* Add 1 to y because we measure from start, x is measured from end, so
107 * it does not need it */
108 y = scg_colrow_distance_get (scg, FALSE, 0, so->anchor.cell_bound.start.row)+ 1;
109 points->points[0].y = scale * y;
110 points->points[1].y = scale * y;
111 points->points[2].y = scale * y + cv->comment_indicator_size;
113 dx = cv->comment_indicator_size;
114 x = scg_colrow_distance_get (scg, TRUE, 0, far_col);
115 points->points[0].x = scale * x - dx;
116 points->points[1].x = scale * x;
117 points->points[2].x = scale * x;
119 goc_item_set (item, "points", points, NULL);
120 goc_points_unref (points);
121 goc_item_show (GOC_ITEM (sov));
122 } else
123 goc_item_hide (GOC_ITEM (sov));
126 static gboolean
127 comment_view_button_released (GocItem *item, int button, double x, double y)
129 SheetObject *so;
130 int ix, iy;
132 if (button != 1)
133 return FALSE;
135 gnm_canvas_get_screen_position (item->canvas, x, y, &ix, &iy);
136 so = sheet_object_view_get_so (GNM_SO_VIEW (item));
137 scg_comment_display (GNM_PANE (item->canvas)->simple.scg,
138 GNM_CELL_COMMENT (so),
139 ix, iy);
141 return TRUE;
144 static gboolean
145 comment_view_button_pressed (GocItem *item, int button, double x, double y)
147 return TRUE;
150 static gboolean
151 comment_view_button2_pressed (GocItem *item, int button, double x, double y)
153 SheetObject *so;
154 GnmRange const *r;
155 SheetControlGUI *scg;
156 if (button !=1)
157 return FALSE;
159 scg = GNM_PANE (item->canvas)->simple.scg;
160 so = sheet_object_view_get_so (GNM_SO_VIEW (item));
161 r = sheet_object_get_range (so);
162 dialog_cell_comment (scg->wbcg, so->sheet, &r->start);
163 return TRUE;
166 static gboolean
167 comment_view_enter_notify (GocItem *item, double x, double y)
169 int ix, iy;
170 SheetObject *so;
172 gnm_widget_set_cursor_type (GTK_WIDGET (item->canvas), GDK_ARROW);
174 gnm_canvas_get_screen_position (item->canvas, x, y, &ix, &iy);
175 so = sheet_object_view_get_so (GNM_SO_VIEW (item));
177 scg_comment_select (GNM_PANE (item->canvas)->simple.scg,
178 GNM_CELL_COMMENT (so),
179 ix, iy);
180 return TRUE;
183 static gboolean
184 comment_view_leave_notify (GocItem *item, double x, double y)
186 scg_comment_unselect (GNM_PANE (item->canvas)->simple.scg,
187 GNM_CELL_COMMENT (sheet_object_view_get_so (GNM_SO_VIEW (item))));
188 return TRUE;
191 static void
192 comment_view_class_init (SheetObjectViewClass *sov_klass)
194 GocItemClass *item_klass = (GocItemClass *) sov_klass;
196 comment_view_parent_class = g_type_class_peek_parent (sov_klass);
198 sov_klass->set_bounds = comment_view_set_bounds;
200 item_klass->button_pressed = comment_view_button_pressed;
201 item_klass->button_released = comment_view_button_released;
202 item_klass->button2_pressed = comment_view_button2_pressed;
203 item_klass->enter_notify = comment_view_enter_notify;
204 item_klass->leave_notify = comment_view_leave_notify;
207 static GSF_CLASS (CommentView, comment_view,
208 comment_view_class_init, NULL,
209 GNM_SO_VIEW_TYPE)
211 static void
212 cell_comment_finalize (GObject *object)
214 GnmComment *cc = GNM_CELL_COMMENT (object);
216 g_return_if_fail (cc != NULL);
218 /* If this comment is being displayed we shut down nicely */
219 if (cc->base.sheet != NULL) {
220 SHEET_FOREACH_CONTROL (cc->base.sheet, view, control,
221 scg_comment_unselect ((SheetControlGUI *) control, cc););
224 g_free (cc->author);
225 cc->author = NULL;
226 g_free (cc->text);
227 cc->text = NULL;
229 if (NULL != cc->markup) {
230 pango_attr_list_unref (cc->markup);
231 cc->markup = NULL;
234 cell_comment_parent_class->finalize (object);
237 static void
238 cell_comment_set_property (GObject *obj, guint param_id,
239 GValue const *value, GParamSpec *pspec)
241 GnmComment *cc = GNM_CELL_COMMENT (obj);
243 switch (param_id) {
244 case CC_PROP_TEXT:
245 g_free (cc->text);
246 cc->text = g_value_dup_string (value);
247 break;
248 case CC_PROP_AUTHOR:
249 g_free (cc->author);
250 cc->author = g_value_dup_string (value);
251 break;
252 case CC_PROP_MARKUP:
253 if (cc->markup != NULL)
254 pango_attr_list_unref (cc->markup);
255 cc->markup = g_value_peek_pointer (value);
256 if (cc->markup != NULL)
257 pango_attr_list_ref (cc->markup);
258 break;
260 default:
261 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
262 return;
266 static void
267 cell_comment_get_property (GObject *obj, guint param_id,
268 GValue *value, GParamSpec *pspec)
270 GnmComment *cc = GNM_CELL_COMMENT (obj);
271 switch (param_id) {
272 case CC_PROP_TEXT:
273 g_value_set_string (value, cc->text);
274 break;
275 case CC_PROP_AUTHOR:
276 g_value_set_string (value, cc->author);
277 break;
278 case CC_PROP_MARKUP:
279 g_value_set_boxed (value, cc->markup);
280 break;
281 default:
282 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
283 break;
287 static SheetObjectView *
288 cell_comment_new_view (SheetObject *so, SheetObjectViewContainer *container)
290 GnmPane *pane = GNM_PANE (container);
291 GocItem *view = goc_item_new (pane->grid_items,
292 comment_view_get_type (),
293 NULL);
294 CommentView *cv = (CommentView *)view;
295 GOStyle *style = go_styled_object_get_style (
296 GO_STYLED_OBJECT (goc_item_new (GOC_GROUP (view),
297 GOC_TYPE_POLYGON, NULL)));
299 comment_view_reload_style (cv);
301 style->line.dash_type = GO_LINE_NONE;
302 style->fill.pattern.back = go_color_from_gdk_rgba (&cv->comment_indicator_color, NULL);
303 return gnm_pane_object_register (so, view, FALSE);
306 static void
307 cell_comment_write_xml_sax (SheetObject const *so, GsfXMLOut *output,
308 GnmConventions const *convs)
310 GnmComment const *cc = GNM_CELL_COMMENT (so);
311 if (NULL != cc->author)
312 gsf_xml_out_add_cstr (output, "Author", cc->author);
313 if (NULL != cc->text) {
314 gsf_xml_out_add_cstr (output, "Text", cc->text);
315 if (NULL != cc->markup) {
316 GOFormat *fmt = go_format_new_markup (cc->markup, TRUE);
317 gsf_xml_out_add_cstr (output, "TextFormat",
318 go_format_as_XL (fmt));
319 go_format_unref (fmt);
324 static void
325 cell_comment_prep_sax_parser (SheetObject *so, GsfXMLIn *xin,
326 xmlChar const **attrs,
327 GnmConventions const *convs)
329 GnmComment *cc = GNM_CELL_COMMENT (so);
331 for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
332 if (!strcmp (attrs[0], "Text"))
333 cc->text = g_strdup (attrs[1]);
334 else if (!strcmp (attrs[0], "Author"))
335 cc->author = g_strdup (attrs[1]);
336 else if (!strcmp (attrs[0], "TextFormat")) {
337 GOFormat * fmt = go_format_new_from_XL (attrs[1]);
338 if (go_format_is_markup (fmt))
339 g_object_set (G_OBJECT (cc),
340 "markup", go_format_get_markup (fmt),
341 NULL);
342 go_format_unref (fmt);
347 static void
348 cell_comment_copy (SheetObject *dst, SheetObject const *src)
350 GnmComment const *comment = GNM_CELL_COMMENT (src);
351 GnmComment *new_comment = GNM_CELL_COMMENT (dst);
352 new_comment->author = g_strdup (comment->author);
353 new_comment->text = g_strdup (comment->text);
354 new_comment->markup = comment->markup;
355 pango_attr_list_ref (new_comment->markup);
358 static void
359 cell_comment_class_init (GObjectClass *gobject_class)
361 SheetObjectClass *sheet_object_class = GNM_SO_CLASS (gobject_class);
363 cell_comment_parent_class = g_type_class_peek_parent (gobject_class);
365 /* Object class method overrides */
366 gobject_class->finalize = cell_comment_finalize;
367 gobject_class->set_property = cell_comment_set_property;
368 gobject_class->get_property = cell_comment_get_property;
369 g_object_class_install_property (gobject_class, CC_PROP_TEXT,
370 g_param_spec_string ("text", NULL, NULL, NULL,
371 GSF_PARAM_STATIC | G_PARAM_READWRITE));
372 g_object_class_install_property (gobject_class, CC_PROP_AUTHOR,
373 g_param_spec_string ("author", NULL, NULL, NULL,
374 GSF_PARAM_STATIC | G_PARAM_READWRITE));
375 g_object_class_install_property (gobject_class, CC_PROP_MARKUP,
376 g_param_spec_boxed ("markup", NULL, NULL,
377 PANGO_TYPE_ATTR_LIST,
378 GSF_PARAM_STATIC | G_PARAM_READWRITE));
380 /* SheetObject class method overrides */
381 sheet_object_class->new_view = &cell_comment_new_view;
382 sheet_object_class->write_xml_sax = &cell_comment_write_xml_sax;
383 sheet_object_class->prep_sax_parser = &cell_comment_prep_sax_parser;
384 sheet_object_class->copy = &cell_comment_copy;
385 sheet_object_class->xml_export_name = "CellComment";
388 static void
389 cell_comment_init (GnmComment *cc)
391 cc->markup = NULL;
394 GSF_CLASS (GnmComment, cell_comment,
395 cell_comment_class_init, cell_comment_init, GNM_SO_TYPE)
397 char const *
398 cell_comment_author_get (GnmComment const *cc)
400 g_return_val_if_fail (GNM_IS_CELL_COMMENT (cc), NULL);
401 return cc->author;
404 void
405 cell_comment_author_set (GnmComment *cc, char const *author)
407 char *tmp;
408 g_return_if_fail (GNM_IS_CELL_COMMENT (cc));
410 tmp = g_strdup (author);
411 g_free (cc->author);
412 cc->author = tmp;
415 char const *
416 cell_comment_text_get (GnmComment const *cc)
418 g_return_val_if_fail (GNM_IS_CELL_COMMENT (cc), NULL);
419 return cc->text;
422 void
423 cell_comment_text_set (GnmComment *cc, char const *text)
425 char *tmp;
426 g_return_if_fail (GNM_IS_CELL_COMMENT (cc));
428 tmp = g_strdup (text);
429 g_free (cc->text);
430 cc->text = tmp;
433 /* convenience routine */
434 void
435 cell_comment_set_pos (GnmComment *cc, GnmCellPos const *pos)
437 /* top right */
438 static double const a_offsets [4] = { 1., 0., 1., 0. };
439 SheetObjectAnchor anchor;
440 GnmRange r;
442 g_return_if_fail (GNM_IS_CELL_COMMENT (cc));
444 r.start = r.end = *pos;
445 sheet_object_anchor_init (&anchor, &r, a_offsets,
446 GOD_ANCHOR_DIR_DOWN_RIGHT, GNM_SO_ANCHOR_TWO_CELLS);
447 sheet_object_set_anchor (GNM_SO (cc), &anchor);
451 * cell_set_comment:
452 * @sheet: #Sheet.
453 * @pos: the position.
454 * @author: comment author.
455 * @text: comment text.
456 * @markup: comment markup.
458 * Returns: (transfer none): the newly allocated #GnmComment.
460 GnmComment *
461 cell_set_comment (Sheet *sheet, GnmCellPos const *pos,
462 char const *author, char const *text,
463 PangoAttrList *attr)
465 GnmComment *cc;
467 g_return_val_if_fail (IS_SHEET (sheet), NULL);
468 g_return_val_if_fail (pos != NULL, NULL);
470 cc = g_object_new (GNM_CELL_COMMENT_TYPE, NULL);
471 cc->author = g_strdup (author);
472 cc->text = g_strdup (text);
473 cc->markup = attr;
474 if (cc->markup != NULL)
475 pango_attr_list_ref (cc->markup);
477 cell_comment_set_pos (cc, pos);
479 sheet_object_set_sheet (GNM_SO (cc), sheet);
480 /* setting the sheet added a reference */
481 g_object_unref (cc);
483 return cc;