2 * this file is part of evince, a gnome document viewer
4 * Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
5 * Copyright (C) 2007 IƱigo Martinez <inigomartinez@gmail.com>
7 * Evince is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * Evince is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include "ev-annotation.h"
25 #include "ev-document-misc.h"
26 #include "ev-document-type-builtins.h"
28 struct _EvAnnotation {
31 EvAnnotationType type;
41 struct _EvAnnotationClass {
42 GObjectClass parent_class;
45 struct _EvAnnotationMarkupInterface {
46 GTypeInterface base_iface;
49 struct _EvAnnotationText {
53 EvAnnotationTextIcon icon;
56 struct _EvAnnotationTextClass {
57 EvAnnotationClass parent_class;
60 struct _EvAnnotationAttachment {
63 EvAttachment *attachment;
66 struct _EvAnnotationAttachmentClass {
67 EvAnnotationClass parent_class;
70 static void ev_annotation_markup_default_init (EvAnnotationMarkupInterface *iface);
71 static void ev_annotation_text_markup_iface_init (EvAnnotationMarkupInterface *iface);
72 static void ev_annotation_attachment_markup_iface_init (EvAnnotationMarkupInterface *iface);
84 /* EvAnnotationMarkup */
89 PROP_MARKUP_HAS_POPUP,
90 PROP_MARKUP_RECTANGLE,
91 PROP_MARKUP_POPUP_IS_OPEN
94 /* EvAnnotationText */
96 PROP_TEXT_ICON = PROP_MARKUP_POPUP_IS_OPEN + 1,
100 /* EvAnnotationAttachment */
102 PROP_ATTACHMENT_ATTACHMENT = PROP_MARKUP_POPUP_IS_OPEN + 1
105 G_DEFINE_ABSTRACT_TYPE (EvAnnotation, ev_annotation, G_TYPE_OBJECT)
106 G_DEFINE_INTERFACE (EvAnnotationMarkup, ev_annotation_markup, EV_TYPE_ANNOTATION)
107 G_DEFINE_TYPE_WITH_CODE (EvAnnotationText, ev_annotation_text, EV_TYPE_ANNOTATION,
109 G_IMPLEMENT_INTERFACE (EV_TYPE_ANNOTATION_MARKUP,
110 ev_annotation_text_markup_iface_init);
112 G_DEFINE_TYPE_WITH_CODE (EvAnnotationAttachment, ev_annotation_attachment, EV_TYPE_ANNOTATION,
114 G_IMPLEMENT_INTERFACE (EV_TYPE_ANNOTATION_MARKUP,
115 ev_annotation_attachment_markup_iface_init);
120 ev_annotation_finalize (GObject *object)
122 EvAnnotation *annot = EV_ANNOTATION (object);
125 g_object_unref (annot->page);
129 if (annot->contents) {
130 g_free (annot->contents);
131 annot->contents = NULL;
135 g_free (annot->name);
139 if (annot->modified) {
140 g_free (annot->modified);
141 annot->modified = NULL;
144 G_OBJECT_CLASS (ev_annotation_parent_class)->finalize (object);
148 ev_annotation_init (EvAnnotation *annot)
150 annot->type = EV_ANNOTATION_TYPE_UNKNOWN;
154 ev_annotation_set_property (GObject *object,
159 EvAnnotation *annot = EV_ANNOTATION (object);
162 case PROP_ANNOT_PAGE:
163 annot->page = g_value_dup_object (value);
165 case PROP_ANNOT_CONTENTS:
166 ev_annotation_set_contents (annot, g_value_get_string (value));
168 case PROP_ANNOT_NAME:
169 ev_annotation_set_name (annot, g_value_get_string (value));
171 case PROP_ANNOT_MODIFIED:
172 ev_annotation_set_modified (annot, g_value_get_string (value));
174 case PROP_ANNOT_COLOR:
175 ev_annotation_set_color (annot, g_value_get_pointer (value));
178 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
183 ev_annotation_get_property (GObject *object,
188 EvAnnotation *annot = EV_ANNOTATION (object);
191 case PROP_ANNOT_CONTENTS:
192 g_value_set_string (value, ev_annotation_get_contents (annot));
194 case PROP_ANNOT_NAME:
195 g_value_set_string (value, ev_annotation_get_name (annot));
197 case PROP_ANNOT_MODIFIED:
198 g_value_set_string (value, ev_annotation_get_modified (annot));
200 case PROP_ANNOT_COLOR:
201 g_value_set_pointer (value, &annot->color);
204 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
209 ev_annotation_class_init (EvAnnotationClass *klass)
211 GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
213 g_object_class->finalize = ev_annotation_finalize;
214 g_object_class->set_property = ev_annotation_set_property;
215 g_object_class->get_property = ev_annotation_get_property;
217 g_object_class_install_property (g_object_class,
219 g_param_spec_object ("page",
221 "The page wehere the annotation is",
223 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
224 g_object_class_install_property (g_object_class,
226 g_param_spec_string ("contents",
228 "The annotation contents",
231 g_object_class_install_property (g_object_class,
233 g_param_spec_string ("name",
235 "The annotation unique name",
238 g_object_class_install_property (g_object_class,
240 g_param_spec_string ("modified",
242 "Last modified date as string",
245 g_object_class_install_property (g_object_class,
247 g_param_spec_pointer ("color",
249 "The annotation color",
254 ev_annotation_get_annotation_type (EvAnnotation *annot)
256 g_return_val_if_fail (EV_IS_ANNOTATION (annot), 0);
262 ev_annotation_get_page (EvAnnotation *annot)
264 g_return_val_if_fail (EV_IS_ANNOTATION (annot), NULL);
270 ev_annotation_get_page_index (EvAnnotation *annot)
272 g_return_val_if_fail (EV_IS_ANNOTATION (annot), 0);
274 return annot->page->index;
278 ev_annotation_equal (EvAnnotation *annot,
281 g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
282 g_return_val_if_fail (EV_IS_ANNOTATION (other), FALSE);
284 return (annot == other || g_strcmp0 (annot->name, other->name) == 0);
288 ev_annotation_get_contents (EvAnnotation *annot)
290 g_return_val_if_fail (EV_IS_ANNOTATION (annot), NULL);
292 return annot->contents;
296 ev_annotation_set_contents (EvAnnotation *annot,
297 const gchar *contents)
299 g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
301 if (g_strcmp0 (annot->contents, contents) == 0)
305 g_free (annot->contents);
306 annot->contents = contents ? g_strdup (contents) : NULL;
308 g_object_notify (G_OBJECT (annot), "contents");
314 ev_annotation_get_name (EvAnnotation *annot)
316 g_return_val_if_fail (EV_IS_ANNOTATION (annot), NULL);
322 ev_annotation_set_name (EvAnnotation *annot,
325 g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
327 if (g_strcmp0 (annot->name, name) == 0)
331 g_free (annot->name);
332 annot->name = name ? g_strdup (name) : NULL;
334 g_object_notify (G_OBJECT (annot), "name");
340 ev_annotation_get_modified (EvAnnotation *annot)
342 g_return_val_if_fail (EV_IS_ANNOTATION (annot), NULL);
344 return annot->modified;
348 ev_annotation_set_modified (EvAnnotation *annot,
349 const gchar *modified)
351 g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
353 if (g_strcmp0 (annot->modified, modified) == 0)
357 g_free (annot->modified);
358 annot->modified = modified ? g_strdup (modified) : NULL;
360 g_object_notify (G_OBJECT (annot), "modified");
366 ev_annotation_set_modified_from_time (EvAnnotation *annot,
371 g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
373 modified = ev_document_misc_format_date (utime);
375 if (g_strcmp0 (annot->modified, modified) == 0) {
381 g_free (annot->modified);
382 annot->modified = modified;
384 g_object_notify (G_OBJECT (annot), "modified");
390 ev_annotation_get_color (EvAnnotation *annot,
393 g_return_if_fail (EV_IS_ANNOTATION (annot));
396 *color = annot->color;
400 ev_annotation_set_color (EvAnnotation *annot,
401 const GdkColor *color)
403 g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
405 if (annot->color.red == color->red &&
406 annot->color.green == color->green &&
407 annot->color.blue == color->blue)
411 annot->color = *color;
413 g_object_notify (G_OBJECT (annot), "color");
418 /* EvAnnotationMarkup */
423 gboolean popup_is_open;
424 EvRectangle rectangle;
425 } EvAnnotationMarkupProps;
428 ev_annotation_markup_default_init (EvAnnotationMarkupInterface *iface)
430 static gboolean initialized = FALSE;
433 g_object_interface_install_property (iface,
434 g_param_spec_string ("label",
436 "Label of the markup annotation",
439 g_object_interface_install_property (iface,
440 g_param_spec_double ("opacity",
442 "Opacity of the markup annotation",
447 g_object_interface_install_property (iface,
448 g_param_spec_boolean ("has_popup",
450 "Whether the markup annotation has "
451 "a popup window associated",
454 g_object_interface_install_property (iface,
455 g_param_spec_boxed ("rectangle",
457 "The Rectangle of the popup associated "
458 "to the markup annotation",
461 g_object_interface_install_property (iface,
462 g_param_spec_boolean ("popup_is_open",
464 "Whether the popup associated to "
465 "the markup annotation is open",
473 ev_annotation_markup_props_free (EvAnnotationMarkupProps *props)
475 g_free (props->label);
476 g_slice_free (EvAnnotationMarkupProps, props);
479 static EvAnnotationMarkupProps *
480 ev_annotation_markup_get_properties (EvAnnotationMarkup *markup)
482 EvAnnotationMarkupProps *props;
483 static GQuark props_key = 0;
486 props_key = g_quark_from_static_string ("ev-annotation-markup-props");
488 props = g_object_get_qdata (G_OBJECT (markup), props_key);
490 props = g_slice_new0 (EvAnnotationMarkupProps);
491 g_object_set_qdata_full (G_OBJECT (markup),
493 (GDestroyNotify) ev_annotation_markup_props_free);
500 ev_annotation_markup_set_property (GObject *object,
505 EvAnnotationMarkup *markup = EV_ANNOTATION_MARKUP (object);
508 case PROP_MARKUP_LABEL:
509 ev_annotation_markup_set_label (markup, g_value_get_string (value));
511 case PROP_MARKUP_OPACITY:
512 ev_annotation_markup_set_opacity (markup, g_value_get_double (value));
514 case PROP_MARKUP_HAS_POPUP:
515 ev_annotation_markup_set_has_popup (markup, g_value_get_boolean (value));
517 case PROP_MARKUP_RECTANGLE:
518 ev_annotation_markup_set_rectangle (markup, g_value_get_boxed (value));
520 case PROP_MARKUP_POPUP_IS_OPEN:
521 ev_annotation_markup_set_popup_is_open (markup, g_value_get_boolean (value));
524 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
529 ev_annotation_markup_get_property (GObject *object,
534 EvAnnotationMarkupProps *props;
536 props = ev_annotation_markup_get_properties (EV_ANNOTATION_MARKUP (object));
539 case PROP_MARKUP_LABEL:
540 g_value_set_string (value, props->label);
542 case PROP_MARKUP_OPACITY:
543 g_value_set_double (value, props->opacity);
545 case PROP_MARKUP_HAS_POPUP:
546 g_value_set_boolean (value, props->has_popup);
548 case PROP_MARKUP_RECTANGLE:
549 g_value_set_boxed (value, &props->rectangle);
551 case PROP_MARKUP_POPUP_IS_OPEN:
552 g_value_set_boolean (value, props->popup_is_open);
555 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
560 ev_annotation_markup_class_install_properties (GObjectClass *klass)
562 klass->set_property = ev_annotation_markup_set_property;
563 klass->get_property = ev_annotation_markup_get_property;
565 g_object_class_override_property (klass, PROP_MARKUP_LABEL, "label");
566 g_object_class_override_property (klass, PROP_MARKUP_OPACITY, "opacity");
567 g_object_class_override_property (klass, PROP_MARKUP_HAS_POPUP, "has_popup");
568 g_object_class_override_property (klass, PROP_MARKUP_RECTANGLE, "rectangle");
569 g_object_class_override_property (klass, PROP_MARKUP_POPUP_IS_OPEN, "popup_is_open");
573 ev_annotation_markup_get_label (EvAnnotationMarkup *markup)
575 EvAnnotationMarkupProps *props;
577 g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), NULL);
579 props = ev_annotation_markup_get_properties (markup);
584 ev_annotation_markup_set_label (EvAnnotationMarkup *markup,
587 EvAnnotationMarkupProps *props;
589 g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
590 g_return_val_if_fail (label != NULL, FALSE);
592 props = ev_annotation_markup_get_properties (markup);
593 if (g_strcmp0 (props->label, label) == 0)
597 g_free (props->label);
598 props->label = g_strdup (label);
600 g_object_notify (G_OBJECT (markup), "label");
606 ev_annotation_markup_get_opacity (EvAnnotationMarkup *markup)
608 EvAnnotationMarkupProps *props;
610 g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), 1.0);
612 props = ev_annotation_markup_get_properties (markup);
613 return props->opacity;
617 ev_annotation_markup_set_opacity (EvAnnotationMarkup *markup,
620 EvAnnotationMarkupProps *props;
622 g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
624 props = ev_annotation_markup_get_properties (markup);
625 if (props->opacity == opacity)
628 props->opacity = opacity;
630 g_object_notify (G_OBJECT (markup), "opacity");
636 ev_annotation_markup_has_popup (EvAnnotationMarkup *markup)
638 EvAnnotationMarkupProps *props;
640 g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
642 props = ev_annotation_markup_get_properties (markup);
643 return props->has_popup;
647 ev_annotation_markup_set_has_popup (EvAnnotationMarkup *markup,
650 EvAnnotationMarkupProps *props;
652 g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
654 props = ev_annotation_markup_get_properties (markup);
655 if (props->has_popup == has_popup)
658 props->has_popup = has_popup;
660 g_object_notify (G_OBJECT (markup), "has-popup");
666 ev_annotation_markup_get_rectangle (EvAnnotationMarkup *markup,
667 EvRectangle *ev_rect)
669 EvAnnotationMarkupProps *props;
671 g_return_if_fail (EV_IS_ANNOTATION_MARKUP (markup));
672 g_return_if_fail (ev_rect != NULL);
674 props = ev_annotation_markup_get_properties (markup);
675 *ev_rect = props->rectangle;
679 ev_annotation_markup_set_rectangle (EvAnnotationMarkup *markup,
680 const EvRectangle *ev_rect)
682 EvAnnotationMarkupProps *props;
684 g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
685 g_return_val_if_fail (ev_rect != NULL, FALSE);
687 props = ev_annotation_markup_get_properties (markup);
688 if (props->rectangle.x1 == ev_rect->x1 &&
689 props->rectangle.y1 == ev_rect->y1 &&
690 props->rectangle.x2 == ev_rect->x2 &&
691 props->rectangle.y2 == ev_rect->y2)
694 props->rectangle = *ev_rect;
696 g_object_notify (G_OBJECT (markup), "rectangle");
702 ev_annotation_markup_get_popup_is_open (EvAnnotationMarkup *markup)
704 EvAnnotationMarkupProps *props;
706 g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
708 props = ev_annotation_markup_get_properties (markup);
709 return props->popup_is_open;
713 ev_annotation_markup_set_popup_is_open (EvAnnotationMarkup *markup,
716 EvAnnotationMarkupProps *props;
718 g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
720 props = ev_annotation_markup_get_properties (markup);
721 if (props->popup_is_open == is_open)
724 props->popup_is_open = is_open;
726 g_object_notify (G_OBJECT (markup), "popup_is_open");
731 /* EvAnnotationText */
733 ev_annotation_text_init (EvAnnotationText *annot)
735 EV_ANNOTATION (annot)->type = EV_ANNOTATION_TYPE_TEXT;
739 ev_annotation_text_set_property (GObject *object,
744 EvAnnotationText *annot = EV_ANNOTATION_TEXT (object);
746 if (prop_id < PROP_ATTACHMENT_ATTACHMENT) {
747 ev_annotation_markup_set_property (object, prop_id, value, pspec);
753 ev_annotation_text_set_icon (annot, g_value_get_enum (value));
755 case PROP_TEXT_IS_OPEN:
756 ev_annotation_text_set_is_open (annot, g_value_get_boolean (value));
759 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
764 ev_annotation_text_get_property (GObject *object,
769 EvAnnotationText *annot = EV_ANNOTATION_TEXT (object);
771 if (prop_id < PROP_ATTACHMENT_ATTACHMENT) {
772 ev_annotation_markup_get_property (object, prop_id, value, pspec);
778 g_value_set_enum (value, annot->icon);
780 case PROP_TEXT_IS_OPEN:
781 g_value_set_boolean (value, annot->is_open);
784 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
789 ev_annotation_text_class_init (EvAnnotationTextClass *klass)
791 GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
793 ev_annotation_markup_class_install_properties (g_object_class);
795 g_object_class->set_property = ev_annotation_text_set_property;
796 g_object_class->get_property = ev_annotation_text_get_property;
798 g_object_class_install_property (g_object_class,
800 g_param_spec_enum ("icon",
802 "The icon fo the text annotation",
803 EV_TYPE_ANNOTATION_TEXT_ICON,
804 EV_ANNOTATION_TEXT_ICON_NOTE,
806 g_object_class_install_property (g_object_class,
808 g_param_spec_boolean ("is_open",
810 "Whether text annot is initially open",
816 ev_annotation_text_markup_iface_init (EvAnnotationMarkupInterface *iface)
821 ev_annotation_text_new (EvPage *page)
823 return EV_ANNOTATION (g_object_new (EV_TYPE_ANNOTATION_TEXT,
829 ev_annotation_text_get_icon (EvAnnotationText *text)
831 g_return_val_if_fail (EV_IS_ANNOTATION_TEXT (text), 0);
837 ev_annotation_text_set_icon (EvAnnotationText *text,
838 EvAnnotationTextIcon icon)
840 g_return_val_if_fail (EV_IS_ANNOTATION_TEXT (text), FALSE);
842 if (text->icon == icon)
847 g_object_notify (G_OBJECT (text), "icon");
853 ev_annotation_text_get_is_open (EvAnnotationText *text)
855 g_return_val_if_fail (EV_IS_ANNOTATION_TEXT (text), FALSE);
857 return text->is_open;
861 ev_annotation_text_set_is_open (EvAnnotationText *text,
864 g_return_val_if_fail (EV_IS_ANNOTATION_TEXT (text), FALSE);
866 if (text->is_open == is_open)
869 text->is_open = is_open;
871 g_object_notify (G_OBJECT (text), "is_open");
876 /* EvAnnotationAttachment */
878 ev_annotation_attachment_finalize (GObject *object)
880 EvAnnotationAttachment *annot = EV_ANNOTATION_ATTACHMENT (object);
882 if (annot->attachment) {
883 g_object_unref (annot->attachment);
884 annot->attachment = NULL;
887 G_OBJECT_CLASS (ev_annotation_attachment_parent_class)->finalize (object);
891 ev_annotation_attachment_init (EvAnnotationAttachment *annot)
893 EV_ANNOTATION (annot)->type = EV_ANNOTATION_TYPE_ATTACHMENT;
897 ev_annotation_attachment_set_property (GObject *object,
902 EvAnnotationAttachment *annot = EV_ANNOTATION_ATTACHMENT (object);
904 if (prop_id < PROP_ATTACHMENT_ATTACHMENT) {
905 ev_annotation_markup_set_property (object, prop_id, value, pspec);
910 case PROP_ATTACHMENT_ATTACHMENT:
911 ev_annotation_attachment_set_attachment (annot, g_value_get_object (value));
914 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
919 ev_annotation_attachment_get_property (GObject *object,
924 EvAnnotationAttachment *annot = EV_ANNOTATION_ATTACHMENT (object);
926 if (prop_id < PROP_ATTACHMENT_ATTACHMENT) {
927 ev_annotation_markup_get_property (object, prop_id, value, pspec);
932 case PROP_ATTACHMENT_ATTACHMENT:
933 g_value_set_object (value, annot->attachment);
936 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
941 ev_annotation_attachment_class_init (EvAnnotationAttachmentClass *klass)
943 GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
945 ev_annotation_markup_class_install_properties (g_object_class);
947 g_object_class->set_property = ev_annotation_attachment_set_property;
948 g_object_class->get_property = ev_annotation_attachment_get_property;
949 g_object_class->finalize = ev_annotation_attachment_finalize;
951 g_object_class_install_property (g_object_class,
952 PROP_ATTACHMENT_ATTACHMENT,
953 g_param_spec_object ("attachment",
955 "The attachment of the annotation",
962 ev_annotation_attachment_markup_iface_init (EvAnnotationMarkupInterface *iface)
967 ev_annotation_attachment_new (EvPage *page,
968 EvAttachment *attachment)
970 g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL);
972 return EV_ANNOTATION (g_object_new (EV_TYPE_ANNOTATION_ATTACHMENT,
974 "attachment", attachment,
979 ev_annotation_attachment_get_attachment (EvAnnotationAttachment *annot)
981 g_return_val_if_fail (EV_IS_ANNOTATION_ATTACHMENT (annot), NULL);
983 return annot->attachment;
987 ev_annotation_attachment_set_attachment (EvAnnotationAttachment *annot,
988 EvAttachment *attachment)
990 g_return_val_if_fail (EV_IS_ANNOTATION_ATTACHMENT (annot), FALSE);
992 if (annot->attachment == attachment)
995 if (annot->attachment)
996 g_object_unref (annot->attachment);
997 annot->attachment = attachment ? g_object_ref (attachment) : NULL;
999 g_object_notify (G_OBJECT (annot), "attachment");