]> www.fi.muni.cz Git - evince.git/commitdiff
Preliminary support for adding new annotations
authorCarlos Garcia Campos <carlosgc@gnome.org>
Tue, 20 Jul 2010 15:01:56 +0000 (17:01 +0200)
committerCarlos Garcia Campos <carlosgc@gnome.org>
Tue, 20 Jul 2010 15:07:40 +0000 (17:07 +0200)
At the moment only Text annotations can be added. See bug #168304.

21 files changed:
backend/pdf/ev-poppler.cc
configure.ac
data/evince-ui.xml
libdocument/ev-annotation.c
libdocument/ev-annotation.h
libdocument/ev-document-annotations.c
libdocument/ev-document-annotations.h
libview/ev-annotation-window.c
libview/ev-annotation-window.h
libview/ev-view-cursor.c
libview/ev-view-cursor.h
libview/ev-view-private.h
libview/ev-view.c
libview/ev-view.h
po/POTFILES.in
shell/Makefile.am
shell/ev-annotation-properties-dialog.c [new file with mode: 0644]
shell/ev-annotation-properties-dialog.h [new file with mode: 0644]
shell/ev-sidebar-annotations.c
shell/ev-sidebar-annotations.h
shell/ev-window.c

index f457d64e2822a229371dde15119b02806a2609dc..5943a6d73d4d2f0ce081b0e3c5a40875761106db 100644 (file)
@@ -2543,6 +2543,69 @@ poppler_annot_color_to_gdk_color (PopplerAnnot *poppler_annot,
        } /* TODO: else use a default color */
 }
 
+static EvAnnotationTextIcon
+get_annot_text_icon (PopplerAnnotText *poppler_annot)
+{
+       gchar *icon = poppler_annot_text_get_icon (poppler_annot);
+       EvAnnotationTextIcon retval;
+
+       if (!icon)
+               return EV_ANNOTATION_TEXT_ICON_UNKNOWN;
+
+       if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_NOTE) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_NOTE;
+       else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_COMMENT) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_COMMENT;
+       else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_KEY) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_KEY;
+       else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_HELP) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_HELP;
+       else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_NEW_PARAGRAPH) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_NEW_PARAGRAPH;
+       else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_PARAGRAPH) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_PARAGRAPH;
+       else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_INSERT) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_INSERT;
+       else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_CROSS) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_CROSS;
+       else if (strcmp (icon, POPPLER_ANNOT_TEXT_ICON_CIRCLE) == 0)
+               retval = EV_ANNOTATION_TEXT_ICON_CIRCLE;
+       else
+               retval = EV_ANNOTATION_TEXT_ICON_UNKNOWN;
+
+       g_free (icon);
+
+       return retval;
+}
+
+static const gchar *
+get_poppler_annot_text_icon (EvAnnotationTextIcon icon)
+{
+       switch (icon) {
+       case EV_ANNOTATION_TEXT_ICON_NOTE:
+               return POPPLER_ANNOT_TEXT_ICON_NOTE;
+       case EV_ANNOTATION_TEXT_ICON_COMMENT:
+               return POPPLER_ANNOT_TEXT_ICON_COMMENT;
+       case EV_ANNOTATION_TEXT_ICON_KEY:
+               return POPPLER_ANNOT_TEXT_ICON_KEY;
+       case EV_ANNOTATION_TEXT_ICON_HELP:
+               return POPPLER_ANNOT_TEXT_ICON_HELP;
+       case EV_ANNOTATION_TEXT_ICON_NEW_PARAGRAPH:
+               return POPPLER_ANNOT_TEXT_ICON_NEW_PARAGRAPH;
+       case EV_ANNOTATION_TEXT_ICON_PARAGRAPH:
+               return POPPLER_ANNOT_TEXT_ICON_PARAGRAPH;
+       case EV_ANNOTATION_TEXT_ICON_INSERT:
+               return POPPLER_ANNOT_TEXT_ICON_INSERT;
+       case EV_ANNOTATION_TEXT_ICON_CROSS:
+               return POPPLER_ANNOT_TEXT_ICON_CROSS;
+       case EV_ANNOTATION_TEXT_ICON_CIRCLE:
+               return POPPLER_ANNOT_TEXT_ICON_CIRCLE;
+       case EV_ANNOTATION_TEXT_ICON_UNKNOWN:
+       default:
+               return POPPLER_ANNOT_TEXT_ICON_NOTE;
+       }
+}
+
 static EvAnnotation *
 ev_annot_from_poppler_annot (PopplerAnnot *poppler_annot,
                             EvPage       *page)
@@ -2560,7 +2623,9 @@ ev_annot_from_poppler_annot (PopplerAnnot *poppler_annot,
                        ev_annot = ev_annotation_text_new (page);
 
                        ev_annot_text = EV_ANNOTATION_TEXT (ev_annot);
-                       ev_annot_text->is_open = poppler_annot_text_get_is_open (poppler_text);
+                       ev_annotation_text_set_is_open (ev_annot_text,
+                                                       poppler_annot_text_get_is_open (poppler_text));
+                       ev_annotation_text_set_icon (ev_annot_text, get_annot_text_icon (poppler_text));
                }
                        break;
                case POPPLER_ANNOT_FILE_ATTACHMENT: {
@@ -2615,19 +2680,34 @@ ev_annot_from_poppler_annot (PopplerAnnot *poppler_annot,
        }
 
        if (ev_annot) {
-               time_t utime;
-               gchar *modified;
+               time_t   utime;
+               gchar   *modified;
+               gchar   *contents;
+               gchar   *name;
+               GdkColor color;
+
+               contents = poppler_annot_get_contents (poppler_annot);
+               if (contents) {
+                       ev_annotation_set_contents (ev_annot, contents);
+                       g_free (contents);
+               }
+
+               name = poppler_annot_get_name (poppler_annot);
+               if (name) {
+                       ev_annotation_set_name (ev_annot, name);
+                       g_free (name);
+               }
 
-               ev_annot->contents = poppler_annot_get_contents (poppler_annot);
-               ev_annot->name = poppler_annot_get_name (poppler_annot);
                modified = poppler_annot_get_modified (poppler_annot);
                if (poppler_date_parse (modified, &utime)) {
-                       ev_annot->modified = ev_document_misc_format_date (utime);
-                       g_free (modified);
+                       ev_annotation_set_modified_from_time (ev_annot, utime);
                } else {
-                       ev_annot->modified = modified;
+                       ev_annotation_set_modified (ev_annot, modified);
                }
-               poppler_annot_color_to_gdk_color (poppler_annot, &ev_annot->color);
+               g_free (modified);
+
+               poppler_annot_color_to_gdk_color (poppler_annot, &color);
+               ev_annotation_set_color (ev_annot, &color);
 
                if (POPPLER_IS_ANNOT_MARKUP (poppler_annot)) {
                        PopplerAnnotMarkup *markup;
@@ -2653,13 +2733,10 @@ ev_annot_from_poppler_annot (PopplerAnnot *poppler_annot,
 
                                g_object_set (ev_annot,
                                              "rectangle", &ev_rect,
-                                             "is_open", is_open,
+                                             "popup_is_open", is_open,
                                              "has_popup", TRUE,
                                              NULL);
                        } else {
-                               /* FIXME: Use poppler_annot_markup_has_popup() when
-                                * new poppler is released.
-                                */
                                g_object_set (ev_annot,
                                              "has_popup", FALSE,
                                              NULL);
@@ -2708,7 +2785,7 @@ pdf_document_annotations_get_annotations (EvDocumentAnnotations *document_annota
 
        for (list = annots; list; list = list->next) {
                PopplerAnnotMapping *mapping;
-               EvMapping *annot_mapping;
+               EvMapping           *annot_mapping;
                EvAnnotation        *ev_annot;
 
                mapping = (PopplerAnnotMapping *)list->data;
@@ -2720,8 +2797,12 @@ pdf_document_annotations_get_annotations (EvDocumentAnnotations *document_annota
                i++;
 
                /* Make sure annot has a unique name */
-               if (!ev_annot->name)
-                       ev_annot->name = g_strdup_printf ("annot-%d-%d", page->index, i);
+               if (!ev_annotation_get_name (ev_annot)) {
+                       gchar *name = g_strdup_printf ("annot-%d-%d", page->index, i);
+
+                       ev_annotation_set_name (ev_annot, name);
+                       g_free (name);
+               }
 
                annot_mapping = g_new (EvMapping, 1);
                annot_mapping->area.x1 = mapping->area.x1;
@@ -2758,10 +2839,115 @@ pdf_document_annotations_get_annotations (EvDocumentAnnotations *document_annota
        return mapping_list;
 }
 
+#ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
 static void
-pdf_document_annotations_annotation_set_contents (EvDocumentAnnotations *document,
-                                                 EvAnnotation          *annot,
-                                                 const gchar           *contents)
+pdf_document_annotations_add_annotation (EvDocumentAnnotations *document_annotations,
+                                        EvAnnotation          *annot,
+                                        EvRectangle           *rect)
+{
+       PopplerAnnot    *poppler_annot;
+       PdfDocument     *pdf_document;
+       EvPage          *page;
+       PopplerPage     *poppler_page;
+       GList           *list = NULL;
+       EvMappingList   *mapping_list;
+       EvMapping       *annot_mapping;
+       PopplerRectangle poppler_rect;
+       gdouble          height;
+       PopplerColor     poppler_color;
+       GdkColor         color;
+       time_t           utime;
+       gchar           *modified;
+       gchar           *name;
+
+       pdf_document = PDF_DOCUMENT (document_annotations);
+       page = ev_annotation_get_page (annot);
+       poppler_page = POPPLER_PAGE (page->backend_page);
+
+       poppler_page_get_size (poppler_page, NULL, &height);
+       poppler_rect.x1 = rect->x1;
+       poppler_rect.x2 = rect->x2;
+       poppler_rect.y1 = height - rect->y2;
+       poppler_rect.y2 = height - rect->y1;
+       poppler_annot = poppler_annot_text_new (pdf_document->document, &poppler_rect);
+
+       ev_annotation_get_color (annot, &color);
+       poppler_color.red = color.red;
+       poppler_color.green = color.green;
+       poppler_color.blue = color.blue;
+       poppler_annot_set_color (poppler_annot, &poppler_color);
+
+       if (EV_IS_ANNOTATION_MARKUP (annot)) {
+               EvAnnotationMarkup *markup = EV_ANNOTATION_MARKUP (annot);
+               const gchar *label;
+
+               if (ev_annotation_markup_has_popup (markup)) {
+                       EvRectangle popup_rect;
+
+                       ev_annotation_markup_get_rectangle (markup, &popup_rect);
+                       poppler_rect.x1 = popup_rect.x1;
+                       poppler_rect.x2 = popup_rect.x2;
+                       poppler_rect.y1 = height - popup_rect.y2;
+                       poppler_rect.y2 = height - popup_rect.y1;
+                       poppler_annot_markup_set_popup (POPPLER_ANNOT_MARKUP (poppler_annot), &poppler_rect);
+                       poppler_annot_markup_set_popup_is_open (POPPLER_ANNOT_MARKUP (poppler_annot),
+                                                               ev_annotation_markup_get_popup_is_open (markup));
+               }
+
+               label = ev_annotation_markup_get_label (markup);
+               if (label)
+                       poppler_annot_markup_set_label (POPPLER_ANNOT_MARKUP (poppler_annot), label);
+       }
+
+       if (EV_IS_ANNOTATION_TEXT (annot)) {
+               EvAnnotationText    *text = EV_ANNOTATION_TEXT (annot);
+               EvAnnotationTextIcon icon;
+
+               icon = ev_annotation_text_get_icon (text);
+               poppler_annot_text_set_icon (POPPLER_ANNOT_TEXT (poppler_annot),
+                                            get_poppler_annot_text_icon (icon));
+       }
+       poppler_page_add_annot (poppler_page, poppler_annot);
+
+       annot_mapping = g_new (EvMapping, 1);
+       annot_mapping->area = *rect;
+       annot_mapping->data = annot;
+       g_object_set_data_full (G_OBJECT (annot),
+                               "poppler-annot",
+                               g_object_ref (poppler_annot),
+                               (GDestroyNotify) g_object_unref);
+
+       if (pdf_document->annots) {
+               mapping_list = (EvMappingList *)g_hash_table_lookup (pdf_document->annots,
+                                                                    GINT_TO_POINTER (page->index));
+               list = ev_mapping_list_get_list (mapping_list);
+               name = g_strdup_printf ("annot-%d-%d", page->index, g_list_length (list) + 1);
+               ev_annotation_set_name (annot, name);
+               g_free (name);
+               list = g_list_append (list, annot_mapping);
+       } else {
+               pdf_document->annots = g_hash_table_new_full (g_direct_hash,
+                                                             g_direct_equal,
+                                                             (GDestroyNotify)NULL,
+                                                             (GDestroyNotify)ev_mapping_list_unref);
+               name = g_strdup_printf ("annot-%d-0", page->index);
+               ev_annotation_set_name (annot, name);
+               g_free (name);
+               list = g_list_append (list, annot_mapping);
+               mapping_list = ev_mapping_list_new (page->index, list, (GDestroyNotify)g_object_unref);
+               g_hash_table_insert (pdf_document->annots,
+                                    GINT_TO_POINTER (page->index),
+                                    ev_mapping_list_ref (mapping_list));
+       }
+
+       pdf_document->modified = TRUE;
+}
+#endif /* HAVE_POPPLER_PAGE_ADD_ANNOT */
+
+static void
+pdf_document_annotations_save_annotation (EvDocumentAnnotations *document_annotations,
+                                         EvAnnotation          *annot,
+                                         EvAnnotationsSaveMask  mask)
 {
        PopplerAnnot *poppler_annot;
 
@@ -2769,15 +2955,61 @@ pdf_document_annotations_annotation_set_contents (EvDocumentAnnotations *documen
        if (!poppler_annot)
                return;
 
-       poppler_annot_set_contents (poppler_annot, contents);
-       PDF_DOCUMENT (document)->modified = TRUE;
+       if (mask & EV_ANNOTATIONS_SAVE_CONTENTS)
+               poppler_annot_set_contents (poppler_annot,
+                                           ev_annotation_get_contents (annot));
+
+#ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
+       if (mask & EV_ANNOTATIONS_SAVE_COLOR) {
+               PopplerColor color;
+               GdkColor     ev_color;
+
+               ev_annotation_get_color (annot, &ev_color);
+               color.red = ev_color.red;
+               color.green = ev_color.green;
+               color.blue = ev_color.blue;
+               poppler_annot_set_color (poppler_annot, &color);
+       }
+
+       if (EV_IS_ANNOTATION_MARKUP (annot)) {
+               EvAnnotationMarkup *ev_markup = EV_ANNOTATION_MARKUP (annot);
+               PopplerAnnotMarkup *markup = POPPLER_ANNOT_MARKUP (poppler_annot);
+
+               if (mask & EV_ANNOTATIONS_SAVE_LABEL)
+                       poppler_annot_markup_set_label (markup, ev_annotation_markup_get_label (ev_markup));
+               if (mask & EV_ANNOTATIONS_SAVE_OPACITY)
+                       poppler_annot_markup_set_opacity (markup, ev_annotation_markup_get_opacity (ev_markup));
+               if (mask & EV_ANNOTATIONS_SAVE_POPUP_IS_OPEN)
+                       poppler_annot_markup_set_popup_is_open (markup, ev_annotation_markup_get_popup_is_open (ev_markup));
+       }
+
+       if (EV_IS_ANNOTATION_TEXT (annot)) {
+               EvAnnotationText *ev_text = EV_ANNOTATION_TEXT (annot);
+               PopplerAnnotText *text = POPPLER_ANNOT_TEXT (poppler_annot);
+
+               if (mask & EV_ANNOTATIONS_SAVE_TEXT_IS_OPEN) {
+                       poppler_annot_text_set_is_open (text,
+                                                       ev_annotation_text_get_is_open (ev_text));
+               }
+               if (mask & EV_ANNOTATIONS_SAVE_TEXT_ICON) {
+                       EvAnnotationTextIcon icon;
+
+                       icon = ev_annotation_text_get_icon (ev_text);
+                       poppler_annot_text_set_icon (text, get_poppler_annot_text_icon (icon));
+               }
+       }
+#endif /* HAVE_POPPLER_PAGE_ADD_ANNOT */
+       PDF_DOCUMENT (document_annotations)->modified = TRUE;
 }
 
 static void
 pdf_document_document_annotations_iface_init (EvDocumentAnnotationsInterface *iface)
 {
        iface->get_annotations = pdf_document_annotations_get_annotations;
-       iface->annotation_set_contents = pdf_document_annotations_annotation_set_contents;
+#ifdef HAVE_POPPLER_PAGE_ADD_ANNOT
+       iface->add_annotation = pdf_document_annotations_add_annotation;
+#endif
+       iface->save_annotation = pdf_document_annotations_save_annotation;
 }
 
 /* Attachments */
index 6e9d965abc56089a52d2356d454c74a346dff04a..3c015e11f4d96f6d81f9515830edc07c2cb754cf 100644 (file)
@@ -482,6 +482,7 @@ if test "x$enable_pdf" = "xyes"; then
            LIBS="$LIBS $POPPLER_LIBS"
            AC_CHECK_FUNCS(poppler_page_get_text_layout)
            AC_CHECK_FUNCS(poppler_page_get_selected_text)
+           AC_CHECK_FUNCS(poppler_page_add_annot)
            LIBS=$evince_save_LIBS
            PKG_CHECK_MODULES(CAIRO_PDF, cairo-pdf, enable_cairo_pdf=yes, enable_cairo_pdf=no)
            if test x$enable_cairo_pdf = xyes; then
index 962e8b26b488a5c0cd1a553d7b4e12695dadf43c..0d15aabcab70a42b1d930065ea984e2ad7fd1ddf 100644 (file)
@@ -82,6 +82,8 @@
     <separator/>
     <menuitem name="OpenAttachment" action="OpenAttachment"/>
     <menuitem name="SaveAttachmentAs" action="SaveAttachmentAs"/>
+    <separator/>
+    <menuitem name="AnnotProperties" action="AnnotProperties"/>
   </popup>
 
   <popup name="AttachmentPopup" action="AttachmentPopupAction">
index 21ffc0a138ea618783cb74281fd4d2cfc0d32117..f7acc0bfec50542bed7cdf5d26f7d94da1060985 100644 (file)
 #include "config.h"
 
 #include "ev-annotation.h"
+#include "ev-document-misc.h"
+#include "ev-document-type-builtins.h"
 
+struct _EvAnnotation {
+       GObject          parent;
+
+       EvAnnotationType type;
+       EvPage          *page;
+
+       gchar           *contents;
+       gchar           *name;
+       gchar           *modified;
+       GdkColor         color;
+
+};
+
+struct _EvAnnotationClass {
+       GObjectClass parent_class;
+};
+
+struct _EvAnnotationMarkupInterface {
+       GTypeInterface base_iface;
+};
+
+struct _EvAnnotationText {
+       EvAnnotation parent;
+
+       gboolean             is_open : 1;
+       EvAnnotationTextIcon icon;
+};
+
+struct _EvAnnotationTextClass {
+       EvAnnotationClass parent_class;
+};
+
+struct _EvAnnotationAttachment {
+       EvAnnotation parent;
+
+       EvAttachment *attachment;
+};
+
+struct _EvAnnotationAttachmentClass {
+       EvAnnotationClass parent_class;
+};
 
 static void ev_annotation_markup_default_init          (EvAnnotationMarkupInterface *iface);
 static void ev_annotation_text_markup_iface_init       (EvAnnotationMarkupInterface *iface);
 static void ev_annotation_attachment_markup_iface_init (EvAnnotationMarkupInterface *iface);
 
+/* EvAnnotation */
+enum {
+       PROP_ANNOT_0,
+       PROP_ANNOT_PAGE,
+       PROP_ANNOT_CONTENTS,
+       PROP_ANNOT_NAME,
+       PROP_ANNOT_MODIFIED,
+       PROP_ANNOT_COLOR
+};
+
+/* EvAnnotationMarkup */
+enum {
+       PROP_MARKUP_0,
+       PROP_MARKUP_LABEL,
+       PROP_MARKUP_OPACITY,
+       PROP_MARKUP_HAS_POPUP,
+       PROP_MARKUP_RECTANGLE,
+       PROP_MARKUP_POPUP_IS_OPEN
+};
+
+/* EvAnnotationText */
 enum {
-       PROP_0,
-       PROP_LABEL,
-       PROP_OPACITY,
-       PROP_HAS_POPUP,
-       PROP_RECTANGLE,
-       PROP_IS_OPEN
+       PROP_TEXT_0,
+       PROP_TEXT_ICON,
+       PROP_TEXT_IS_OPEN
+};
+
+/* EvAnnotationAttachment */
+enum {
+       PROP_ATTACHMENT_0,
+       PROP_ATTACHMENT_ATTACHMENT
 };
 
 G_DEFINE_ABSTRACT_TYPE (EvAnnotation, ev_annotation, G_TYPE_OBJECT)
@@ -82,6 +149,62 @@ ev_annotation_finalize (GObject *object)
 static void
 ev_annotation_init (EvAnnotation *annot)
 {
+       annot->type = EV_ANNOTATION_TYPE_UNKNOWN;
+}
+
+static void
+ev_annotation_set_property (GObject      *object,
+                           guint         prop_id,
+                           const GValue *value,
+                           GParamSpec   *pspec)
+{
+       EvAnnotation *annot = EV_ANNOTATION (object);
+
+       switch (prop_id) {
+       case PROP_ANNOT_PAGE:
+               annot->page = g_value_dup_object (value);
+               break;
+       case PROP_ANNOT_CONTENTS:
+               ev_annotation_set_contents (annot, g_value_get_string (value));
+               break;
+       case PROP_ANNOT_NAME:
+               ev_annotation_set_name (annot, g_value_get_string (value));
+               break;
+       case PROP_ANNOT_MODIFIED:
+               ev_annotation_set_modified (annot, g_value_get_string (value));
+               break;
+       case PROP_ANNOT_COLOR:
+               ev_annotation_set_color (annot, g_value_get_pointer (value));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
+}
+
+static void
+ev_annotation_get_property (GObject    *object,
+                           guint       prop_id,
+                           GValue     *value,
+                           GParamSpec *pspec)
+{
+       EvAnnotation *annot = EV_ANNOTATION (object);
+
+       switch (prop_id) {
+       case PROP_ANNOT_CONTENTS:
+               g_value_set_string (value, ev_annotation_get_contents (annot));
+               break;
+       case PROP_ANNOT_NAME:
+               g_value_set_string (value, ev_annotation_get_name (annot));
+               break;
+       case PROP_ANNOT_MODIFIED:
+               g_value_set_string (value, ev_annotation_get_modified (annot));
+               break;
+       case PROP_ANNOT_COLOR:
+               g_value_set_pointer (value, &annot->color);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
 }
 
 static void
@@ -90,6 +213,208 @@ ev_annotation_class_init (EvAnnotationClass *klass)
        GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
 
        g_object_class->finalize = ev_annotation_finalize;
+       g_object_class->set_property = ev_annotation_set_property;
+       g_object_class->get_property = ev_annotation_get_property;
+
+       g_object_class_install_property (g_object_class,
+                                        PROP_ANNOT_PAGE,
+                                        g_param_spec_object ("page",
+                                                             "Page",
+                                                             "The page wehere the annotation is",
+                                                             EV_TYPE_PAGE,
+                                                             G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+       g_object_class_install_property (g_object_class,
+                                        PROP_ANNOT_CONTENTS,
+                                        g_param_spec_string ("contents",
+                                                             "Contents",
+                                                             "The annotation contents",
+                                                             NULL,
+                                                             G_PARAM_READWRITE));
+       g_object_class_install_property (g_object_class,
+                                        PROP_ANNOT_NAME,
+                                        g_param_spec_string ("name",
+                                                             "Name",
+                                                             "The annotation unique name",
+                                                             NULL,
+                                                             G_PARAM_READWRITE));
+       g_object_class_install_property (g_object_class,
+                                        PROP_ANNOT_MODIFIED,
+                                        g_param_spec_string ("modified",
+                                                             "Modified",
+                                                             "Last modified date as string",
+                                                             NULL,
+                                                             G_PARAM_READWRITE));
+       g_object_class_install_property (g_object_class,
+                                        PROP_ANNOT_COLOR,
+                                        g_param_spec_pointer ("color",
+                                                              "Color",
+                                                              "The annotation color",
+                                                              G_PARAM_READWRITE));
+}
+
+EvAnnotationType
+ev_annotation_get_annotation_type (EvAnnotation *annot)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), 0);
+
+       return annot->type;
+}
+
+EvPage *
+ev_annotation_get_page (EvAnnotation *annot)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), NULL);
+
+       return annot->page;
+}
+
+guint
+ev_annotation_get_page_index (EvAnnotation *annot)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), 0);
+
+       return annot->page->index;
+}
+
+gboolean
+ev_annotation_equal (EvAnnotation *annot,
+                    EvAnnotation *other)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
+       g_return_val_if_fail (EV_IS_ANNOTATION (other), FALSE);
+
+       return (annot == other || g_strcmp0 (annot->name, other->name) == 0);
+}
+
+const gchar *
+ev_annotation_get_contents (EvAnnotation *annot)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), NULL);
+
+       return annot->contents;
+}
+
+gboolean
+ev_annotation_set_contents (EvAnnotation *annot,
+                           const gchar  *contents)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
+
+       if (g_strcmp0 (annot->contents, contents) == 0)
+               return FALSE;
+
+       if (annot->contents)
+               g_free (annot->contents);
+       annot->contents = contents ? g_strdup (contents) : NULL;
+
+       g_object_notify (G_OBJECT (annot), "contents");
+
+       return TRUE;
+}
+
+const gchar *
+ev_annotation_get_name (EvAnnotation *annot)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), NULL);
+
+       return annot->name;
+}
+
+gboolean
+ev_annotation_set_name (EvAnnotation *annot,
+                       const gchar  *name)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
+
+       if (g_strcmp0 (annot->name, name) == 0)
+               return FALSE;
+
+       if (annot->name)
+               g_free (annot->name);
+       annot->name = name ? g_strdup (name) : NULL;
+
+       g_object_notify (G_OBJECT (annot), "name");
+
+       return TRUE;
+}
+
+const gchar *
+ev_annotation_get_modified (EvAnnotation *annot)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), NULL);
+
+       return annot->modified;
+}
+
+gboolean
+ev_annotation_set_modified (EvAnnotation *annot,
+                           const gchar  *modified)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
+
+       if (g_strcmp0 (annot->modified, modified) == 0)
+               return FALSE;
+
+       if (annot->modified)
+               g_free (annot->modified);
+       annot->modified = modified ? g_strdup (modified) : NULL;
+
+       g_object_notify (G_OBJECT (annot), "modified");
+
+       return TRUE;
+}
+
+gboolean
+ev_annotation_set_modified_from_time (EvAnnotation *annot,
+                                     GTime         utime)
+{
+       gchar *modified;
+
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
+
+       modified = ev_document_misc_format_date (utime);
+
+       if (g_strcmp0 (annot->modified, modified) == 0) {
+               g_free (modified);
+               return FALSE;
+       }
+
+       if (annot->modified)
+               g_free (annot->modified);
+       annot->modified = modified;
+
+       g_object_notify (G_OBJECT (annot), "modified");
+
+       return TRUE;
+}
+
+void
+ev_annotation_get_color (EvAnnotation *annot,
+                        GdkColor     *color)
+{
+       g_return_if_fail (EV_IS_ANNOTATION (annot));
+
+       if (color)
+               *color = annot->color;
+}
+
+gboolean
+ev_annotation_set_color (EvAnnotation   *annot,
+                        const GdkColor *color)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION (annot), FALSE);
+
+       if (annot->color.red == color->red &&
+           annot->color.green == color->green &&
+           annot->color.blue == color->blue)
+               return FALSE;
+
+       if (color)
+               annot->color = *color;
+
+       g_object_notify (G_OBJECT (annot), "color");
+
+       return TRUE;
 }
 
 /* EvAnnotationMarkup */
@@ -97,8 +422,8 @@ typedef struct {
        gchar   *label;
        gdouble  opacity;
        gboolean has_popup;
-       gboolean is_open;
-       EvRectangle *rectangle;
+       gboolean popup_is_open;
+       EvRectangle rectangle;
 } EvAnnotationMarkupProps;
 
 static void
@@ -119,7 +444,7 @@ ev_annotation_markup_default_init (EvAnnotationMarkupInterface *iface)
                                                                          "Opacity of the markup annotation",
                                                                          0,
                                                                          G_MAXDOUBLE,
-                                                                         0,
+                                                                         1.,
                                                                          G_PARAM_READWRITE));
                g_object_interface_install_property (iface,
                                                     g_param_spec_boolean ("has_popup",
@@ -136,8 +461,8 @@ ev_annotation_markup_default_init (EvAnnotationMarkupInterface *iface)
                                                                         EV_TYPE_RECTANGLE,
                                                                         G_PARAM_READWRITE));
                g_object_interface_install_property (iface,
-                                                    g_param_spec_boolean ("is_open",
-                                                                          "Is open",
+                                                    g_param_spec_boolean ("popup_is_open",
+                                                                          "PopupIsOpen",
                                                                           "Whether the popup associated to "
                                                                           "the markup annotation is open",
                                                                           FALSE,
@@ -150,7 +475,6 @@ static void
 ev_annotation_markup_props_free (EvAnnotationMarkupProps *props)
 {
        g_free (props->label);
-       ev_rectangle_free (props->rectangle);
        g_slice_free (EvAnnotationMarkupProps, props);
 }
 
@@ -180,27 +504,23 @@ ev_annotation_markup_set_property (GObject      *object,
                                   const GValue *value,
                                   GParamSpec   *pspec)
 {
-       EvAnnotationMarkupProps *props;
-
-       props = ev_annotation_markup_get_properties (EV_ANNOTATION_MARKUP (object));
+       EvAnnotationMarkup *markup = EV_ANNOTATION_MARKUP (object);
 
        switch (prop_id) {
-       case PROP_LABEL:
-               g_free (props->label);
-               props->label = g_value_dup_string (value);
+       case PROP_MARKUP_LABEL:
+               ev_annotation_markup_set_label (markup, g_value_get_string (value));
                break;
-       case PROP_OPACITY:
-               props->opacity = g_value_get_double (value);
+       case PROP_MARKUP_OPACITY:
+               ev_annotation_markup_set_opacity (markup, g_value_get_double (value));
                break;
-       case PROP_HAS_POPUP:
-               props->has_popup = g_value_get_boolean (value);
+       case PROP_MARKUP_HAS_POPUP:
+               ev_annotation_markup_set_has_popup (markup, g_value_get_boolean (value));
                break;
-       case PROP_RECTANGLE:
-               ev_rectangle_free (props->rectangle);
-               props->rectangle = g_value_dup_boxed (value);
+       case PROP_MARKUP_RECTANGLE:
+               ev_annotation_markup_set_rectangle (markup, g_value_get_boxed (value));
                break;
-       case PROP_IS_OPEN:
-               props->is_open = g_value_get_boolean (value);
+       case PROP_MARKUP_POPUP_IS_OPEN:
+               ev_annotation_markup_set_popup_is_open (markup, g_value_get_boolean (value));
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -218,20 +538,20 @@ ev_annotation_markup_get_property (GObject    *object,
        props = ev_annotation_markup_get_properties (EV_ANNOTATION_MARKUP (object));
 
        switch (prop_id) {
-       case PROP_LABEL:
+       case PROP_MARKUP_LABEL:
                g_value_set_string (value, props->label);
                break;
-       case PROP_OPACITY:
+       case PROP_MARKUP_OPACITY:
                g_value_set_double (value, props->opacity);
                break;
-       case PROP_HAS_POPUP:
+       case PROP_MARKUP_HAS_POPUP:
                g_value_set_boolean (value, props->has_popup);
                break;
-       case PROP_RECTANGLE:
-               g_value_set_boxed (value, props->rectangle);
+       case PROP_MARKUP_RECTANGLE:
+               g_value_set_boxed (value, &props->rectangle);
                break;
-       case PROP_IS_OPEN:
-               g_value_set_boolean (value, props->is_open);
+       case PROP_MARKUP_POPUP_IS_OPEN:
+               g_value_set_boolean (value, props->popup_is_open);
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -244,106 +564,217 @@ ev_annotation_markup_class_install_properties (GObjectClass *klass)
        klass->set_property = ev_annotation_markup_set_property;
        klass->get_property = ev_annotation_markup_get_property;
 
-       g_object_class_override_property (klass, PROP_LABEL, "label");
-       g_object_class_override_property (klass, PROP_OPACITY, "opacity");
-       g_object_class_override_property (klass, PROP_HAS_POPUP, "has_popup");
-       g_object_class_override_property (klass, PROP_RECTANGLE, "rectangle");
-       g_object_class_override_property (klass, PROP_IS_OPEN, "is_open");
+       g_object_class_override_property (klass, PROP_MARKUP_LABEL, "label");
+       g_object_class_override_property (klass, PROP_MARKUP_OPACITY, "opacity");
+       g_object_class_override_property (klass, PROP_MARKUP_HAS_POPUP, "has_popup");
+       g_object_class_override_property (klass, PROP_MARKUP_RECTANGLE, "rectangle");
+       g_object_class_override_property (klass, PROP_MARKUP_POPUP_IS_OPEN, "popup_is_open");
 }
 
-gchar *
+const gchar *
 ev_annotation_markup_get_label (EvAnnotationMarkup *markup)
 {
-       gchar *retval;
+       EvAnnotationMarkupProps *props;
 
        g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), NULL);
 
-       g_object_get (G_OBJECT (markup), "label", &retval, NULL);
-
-       return retval;
+       props = ev_annotation_markup_get_properties (markup);
+       return props->label;
 }
 
-void
+gboolean
 ev_annotation_markup_set_label (EvAnnotationMarkup *markup,
                                const gchar        *label)
 {
-       g_return_if_fail (EV_IS_ANNOTATION_MARKUP (markup));
-       g_return_if_fail (label != NULL);
+       EvAnnotationMarkupProps *props;
+
+       g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
+       g_return_val_if_fail (label != NULL, FALSE);
+
+       props = ev_annotation_markup_get_properties (markup);
+       if (g_strcmp0 (props->label, label) == 0)
+               return FALSE;
 
-       g_object_set (G_OBJECT (markup), "label", label, NULL);
+       if (props->label)
+               g_free (props->label);
+       props->label = g_strdup (label);
+
+       g_object_notify (G_OBJECT (markup), "label");
+
+       return TRUE;
 }
 
 gdouble
 ev_annotation_markup_get_opacity (EvAnnotationMarkup *markup)
 {
-       gdouble retval;
-
-       g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), 0.0);
+       EvAnnotationMarkupProps *props;
 
-       g_object_get (G_OBJECT (markup), "opacity", &retval, NULL);
+       g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), 1.0);
 
-       return retval;
+       props = ev_annotation_markup_get_properties (markup);
+       return props->opacity;
 }
 
-void
+gboolean
 ev_annotation_markup_set_opacity (EvAnnotationMarkup *markup,
                                  gdouble             opacity)
 {
-       g_return_if_fail (EV_IS_ANNOTATION_MARKUP (markup));
+       EvAnnotationMarkupProps *props;
 
-       g_object_set (G_OBJECT (markup), "opacity", opacity, NULL);
+       g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
+
+       props = ev_annotation_markup_get_properties (markup);
+       if (props->opacity == opacity)
+               return FALSE;
+
+       props->opacity = opacity;
+
+       g_object_notify (G_OBJECT (markup), "opacity");
+
+       return TRUE;
 }
 
 gboolean
 ev_annotation_markup_has_popup (EvAnnotationMarkup *markup)
 {
-       gboolean retval;
+       EvAnnotationMarkupProps *props;
 
        g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
 
-       g_object_get (G_OBJECT (markup), "has_popup", &retval, NULL);
+       props = ev_annotation_markup_get_properties (markup);
+       return props->has_popup;
+}
 
-       return retval;
+gboolean
+ev_annotation_markup_set_has_popup (EvAnnotationMarkup *markup,
+                                   gboolean            has_popup)
+{
+       EvAnnotationMarkupProps *props;
+
+       g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
+
+       props = ev_annotation_markup_get_properties (markup);
+       if (props->has_popup == has_popup)
+               return FALSE;
+
+       props->has_popup = has_popup;
+
+       g_object_notify (G_OBJECT (markup), "has-popup");
+
+       return TRUE;
 }
 
 void
 ev_annotation_markup_get_rectangle (EvAnnotationMarkup *markup,
                                    EvRectangle        *ev_rect)
 {
-       EvRectangle *r;
+       EvAnnotationMarkupProps *props;
 
        g_return_if_fail (EV_IS_ANNOTATION_MARKUP (markup));
        g_return_if_fail (ev_rect != NULL);
 
-       g_object_get (G_OBJECT (markup), "rectangle", &r, NULL);
-       *ev_rect = *r;
+       props = ev_annotation_markup_get_properties (markup);
+       *ev_rect = props->rectangle;
 }
 
 gboolean
-ev_annotation_markup_get_is_open (EvAnnotationMarkup *markup)
+ev_annotation_markup_set_rectangle (EvAnnotationMarkup *markup,
+                                   const EvRectangle  *ev_rect)
 {
-       gboolean retval;
+       EvAnnotationMarkupProps *props;
 
        g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
+       g_return_val_if_fail (ev_rect != NULL, FALSE);
+
+       props = ev_annotation_markup_get_properties (markup);
+       if (props->rectangle.x1 == ev_rect->x1 &&
+           props->rectangle.y1 == ev_rect->y1 &&
+           props->rectangle.x2 == ev_rect->x2 &&
+           props->rectangle.y2 == ev_rect->y2)
+               return FALSE;
+
+       props->rectangle = *ev_rect;
 
-       g_object_get (G_OBJECT (markup), "is_open", &retval, NULL);
+       g_object_notify (G_OBJECT (markup), "rectangle");
 
-       return retval;
+       return TRUE;
 }
 
-void
-ev_annotation_markup_set_is_open (EvAnnotationMarkup *markup,
-                                 gboolean            is_open)
+gboolean
+ev_annotation_markup_get_popup_is_open (EvAnnotationMarkup *markup)
 {
-       g_return_if_fail (EV_IS_ANNOTATION_MARKUP (markup));
+       EvAnnotationMarkupProps *props;
+
+       g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
 
-       g_object_set (G_OBJECT (markup), "is_open", is_open, NULL);
+       props = ev_annotation_markup_get_properties (markup);
+       return props->popup_is_open;
+}
+
+gboolean
+ev_annotation_markup_set_popup_is_open (EvAnnotationMarkup *markup,
+                                       gboolean            is_open)
+{
+       EvAnnotationMarkupProps *props;
+
+       g_return_val_if_fail (EV_IS_ANNOTATION_MARKUP (markup), FALSE);
+
+       props = ev_annotation_markup_get_properties (markup);
+       if (props->popup_is_open == is_open)
+               return FALSE;
+
+       props->popup_is_open = is_open;
+
+       g_object_notify (G_OBJECT (markup), "popup_is_open");
+
+       return TRUE;
 }
 
 /* EvAnnotationText */
 static void
 ev_annotation_text_init (EvAnnotationText *annot)
 {
+       EV_ANNOTATION (annot)->type = EV_ANNOTATION_TYPE_TEXT;
+}
+
+static void
+ev_annotation_text_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+       EvAnnotationText *annot = EV_ANNOTATION_TEXT (object);
+
+       switch (prop_id) {
+       case PROP_TEXT_ICON:
+               ev_annotation_text_set_icon (annot, g_value_get_enum (value));
+               break;
+       case PROP_TEXT_IS_OPEN:
+               ev_annotation_text_set_is_open (annot, g_value_get_boolean (value));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
+}
+
+static void
+ev_annotation_text_get_property (GObject    *object,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+       EvAnnotationText *annot = EV_ANNOTATION_TEXT (object);
+
+       switch (prop_id) {
+       case PROP_TEXT_ICON:
+               g_value_set_enum (value, annot->icon);
+               break;
+       case PROP_TEXT_IS_OPEN:
+               g_value_set_boolean (value, annot->is_open);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
 }
 
 static void
@@ -351,7 +782,26 @@ ev_annotation_text_class_init (EvAnnotationTextClass *klass)
 {
        GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
 
+       g_object_class->set_property = ev_annotation_text_set_property;
+       g_object_class->get_property = ev_annotation_text_get_property;
+
        ev_annotation_markup_class_install_properties (g_object_class);
+
+       g_object_class_install_property (g_object_class,
+                                        PROP_TEXT_ICON,
+                                        g_param_spec_enum ("icon",
+                                                           "Icon",
+                                                           "The icon fo the text annotation",
+                                                           EV_TYPE_ANNOTATION_TEXT_ICON,
+                                                           EV_ANNOTATION_TEXT_ICON_NOTE,
+                                                           G_PARAM_READWRITE));
+       g_object_class_install_property (g_object_class,
+                                        PROP_TEXT_IS_OPEN,
+                                        g_param_spec_boolean ("is_open",
+                                                              "IsOpen",
+                                                              "Whether text annot is initially open",
+                                                              FALSE,
+                                                              G_PARAM_READWRITE));
 }
 
 static void
@@ -362,12 +812,57 @@ ev_annotation_text_markup_iface_init (EvAnnotationMarkupInterface *iface)
 EvAnnotation *
 ev_annotation_text_new (EvPage *page)
 {
-       EvAnnotation *annot;
+       return EV_ANNOTATION (g_object_new (EV_TYPE_ANNOTATION_TEXT,
+                                           "page", page,
+                                           NULL));
+}
 
-       annot = EV_ANNOTATION (g_object_new (EV_TYPE_ANNOTATION_TEXT, NULL));
-       annot->page = g_object_ref (page);
+EvAnnotationTextIcon
+ev_annotation_text_get_icon (EvAnnotationText *text)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION_TEXT (text), 0);
 
-       return annot;
+       return text->icon;
+}
+
+gboolean
+ev_annotation_text_set_icon (EvAnnotationText    *text,
+                            EvAnnotationTextIcon icon)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION_TEXT (text), FALSE);
+
+       if (text->icon == icon)
+               return FALSE;
+
+       text->icon = icon;
+
+       g_object_notify (G_OBJECT (text), "icon");
+
+       return TRUE;
+}
+
+gboolean
+ev_annotation_text_get_is_open (EvAnnotationText *text)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION_TEXT (text), FALSE);
+
+       return text->is_open;
+}
+
+gboolean
+ev_annotation_text_set_is_open (EvAnnotationText *text,
+                               gboolean          is_open)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION_TEXT (text), FALSE);
+
+       if (text->is_open == is_open)
+               return FALSE;
+
+       text->is_open = is_open;
+
+       g_object_notify (G_OBJECT (text), "is_open");
+
+       return TRUE;
 }
 
 /* EvAnnotationAttachment */
@@ -387,6 +882,41 @@ ev_annotation_attachment_finalize (GObject *object)
 static void
 ev_annotation_attachment_init (EvAnnotationAttachment *annot)
 {
+       EV_ANNOTATION (annot)->type = EV_ANNOTATION_TYPE_ATTACHMENT;
+}
+
+static void
+ev_annotation_attachment_set_property (GObject      *object,
+                                      guint         prop_id,
+                                      const GValue *value,
+                                      GParamSpec   *pspec)
+{
+       EvAnnotationAttachment *annot = EV_ANNOTATION_ATTACHMENT (object);
+
+       switch (prop_id) {
+       case PROP_ATTACHMENT_ATTACHMENT:
+               ev_annotation_attachment_set_attachment (annot, g_value_get_object (value));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
+}
+
+static void
+ev_annotation_attachment_get_property (GObject    *object,
+                                      guint       prop_id,
+                                      GValue     *value,
+                                      GParamSpec *pspec)
+{
+       EvAnnotationAttachment *annot = EV_ANNOTATION_ATTACHMENT (object);
+
+       switch (prop_id) {
+       case PROP_ATTACHMENT_ATTACHMENT:
+               g_value_set_object (value, annot->attachment);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
 }
 
 static void
@@ -394,9 +924,20 @@ ev_annotation_attachment_class_init (EvAnnotationAttachmentClass *klass)
 {
        GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
 
+       g_object_class->set_property = ev_annotation_attachment_set_property;
+       g_object_class->get_property = ev_annotation_attachment_get_property;
+       g_object_class->finalize = ev_annotation_attachment_finalize;
+
        ev_annotation_markup_class_install_properties (g_object_class);
 
-       g_object_class->finalize = ev_annotation_attachment_finalize;
+       g_object_class_install_property (g_object_class,
+                                        PROP_ATTACHMENT_ATTACHMENT,
+                                        g_param_spec_object ("attachment",
+                                                             "Attachment",
+                                                             "The attachment of the annotation",
+                                                             EV_TYPE_ATTACHMENT,
+                                                             G_PARAM_CONSTRUCT |
+                                                             G_PARAM_READWRITE));
 }
 
 static void
@@ -408,13 +949,36 @@ EvAnnotation *
 ev_annotation_attachment_new (EvPage       *page,
                              EvAttachment *attachment)
 {
-       EvAnnotation *annot;
-
        g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL);
 
-       annot = EV_ANNOTATION (g_object_new (EV_TYPE_ANNOTATION_ATTACHMENT, NULL));
-       annot->page = g_object_ref (page);
-       EV_ANNOTATION_ATTACHMENT (annot)->attachment = g_object_ref (attachment);
+       return EV_ANNOTATION (g_object_new (EV_TYPE_ANNOTATION_ATTACHMENT,
+                                           "page", page,
+                                           "attachment", attachment,
+                                           NULL));
+}
+
+EvAttachment *
+ev_annotation_attachment_get_attachment (EvAnnotationAttachment *annot)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION_ATTACHMENT (annot), NULL);
+
+       return annot->attachment;
+}
+
+gboolean
+ev_annotation_attachment_set_attachment (EvAnnotationAttachment *annot,
+                                        EvAttachment           *attachment)
+{
+       g_return_val_if_fail (EV_IS_ANNOTATION_ATTACHMENT (annot), FALSE);
+
+       if (annot->attachment == attachment)
+               return FALSE;
+
+       if (annot->attachment)
+               g_object_unref (annot->attachment);
+       annot->attachment = attachment ? g_object_ref (attachment) : NULL;
+
+       g_object_notify (G_OBJECT (annot), "attachment");
 
-       return annot;
+       return TRUE;
 }
index de8736e200116da0ea43404dc173539c1f928f77..554523c15f37a7e63e242081c4d913f4eda2cff4 100644 (file)
@@ -77,80 +77,84 @@ typedef struct _EvAnnotationTextClass       EvAnnotationTextClass;
 typedef struct _EvAnnotationAttachment      EvAnnotationAttachment;
 typedef struct _EvAnnotationAttachmentClass EvAnnotationAttachmentClass;
 
-struct _EvAnnotation
-{
-       GObject parent;
-
-       EvPage  *page;
-       gboolean changed;
-
-       gchar   *contents;
-       gchar   *name;
-       gchar   *modified;
-       GdkColor color;
-
-};
-
-struct _EvAnnotationClass
-{
-       GObjectClass parent_class;
-};
-
-struct _EvAnnotationMarkupInterface
-{
-       GTypeInterface base_iface;
-};
-
-struct _EvAnnotationText
-{
-       EvAnnotation parent;
-
-       gboolean is_open : 1;
-};
-
-struct _EvAnnotationTextClass
-{
-       EvAnnotationClass parent_class;
-};
-
-struct _EvAnnotationAttachment
-{
-       EvAnnotation parent;
-
-       EvAttachment *attachment;
-};
-
-struct _EvAnnotationAttachmentClass
-{
-       EvAnnotationClass parent_class;
-};
+typedef enum {
+       EV_ANNOTATION_TYPE_UNKNOWN,
+       EV_ANNOTATION_TYPE_TEXT,
+       EV_ANNOTATION_TYPE_ATTACHMENT
+} EvAnnotationType;
+
+typedef enum {
+       EV_ANNOTATION_TEXT_ICON_NOTE,
+       EV_ANNOTATION_TEXT_ICON_COMMENT,
+       EV_ANNOTATION_TEXT_ICON_KEY,
+       EV_ANNOTATION_TEXT_ICON_HELP,
+       EV_ANNOTATION_TEXT_ICON_NEW_PARAGRAPH,
+       EV_ANNOTATION_TEXT_ICON_PARAGRAPH,
+       EV_ANNOTATION_TEXT_ICON_INSERT,
+       EV_ANNOTATION_TEXT_ICON_CROSS,
+       EV_ANNOTATION_TEXT_ICON_CIRCLE,
+       EV_ANNOTATION_TEXT_ICON_UNKNOWN
+} EvAnnotationTextIcon;
 
 /* EvAnnotation */
-GType         ev_annotation_get_type             (void) G_GNUC_CONST;
+GType                ev_annotation_get_type                  (void) G_GNUC_CONST;
+EvAnnotationType     ev_annotation_get_annotation_type       (EvAnnotation           *annot);
+EvPage              *ev_annotation_get_page                  (EvAnnotation           *annot);
+guint                ev_annotation_get_page_index            (EvAnnotation           *annot);
+gboolean             ev_annotation_equal                     (EvAnnotation           *annot,
+                                                             EvAnnotation           *other);
+const gchar         *ev_annotation_get_contents              (EvAnnotation           *annot);
+gboolean             ev_annotation_set_contents              (EvAnnotation           *annot,
+                                                             const gchar            *contents);
+const gchar         *ev_annotation_get_name                  (EvAnnotation           *annot);
+gboolean             ev_annotation_set_name                  (EvAnnotation           *annot,
+                                                             const gchar            *name);
+const gchar         *ev_annotation_get_modified              (EvAnnotation           *annot);
+gboolean             ev_annotation_set_modified              (EvAnnotation           *annot,
+                                                             const gchar            *modified);
+gboolean             ev_annotation_set_modified_from_time    (EvAnnotation           *annot,
+                                                             GTime                   utime);
+void                 ev_annotation_get_color                 (EvAnnotation           *annot,
+                                                             GdkColor               *color);
+gboolean             ev_annotation_set_color                 (EvAnnotation           *annot,
+                                                             const GdkColor         *color);
 
 /* EvAnnotationMarkup */
-GType         ev_annotation_markup_get_type      (void) G_GNUC_CONST;
-gchar        *ev_annotation_markup_get_label     (EvAnnotationMarkup *markup);
-void          ev_annotation_markup_set_label     (EvAnnotationMarkup *markup,
-                                                 const gchar        *label);
-gdouble       ev_annotation_markup_get_opacity   (EvAnnotationMarkup *markup);
-void          ev_annotation_markup_set_opacity   (EvAnnotationMarkup *markup,
-                                                 gdouble             opacity);
-gboolean      ev_annotation_markup_has_popup     (EvAnnotationMarkup *markup);
-void          ev_annotation_markup_get_rectangle (EvAnnotationMarkup *markup,
-                                                 EvRectangle        *ev_rect);
-gboolean      ev_annotation_markup_get_is_open   (EvAnnotationMarkup *markup);
-void          ev_annotation_markup_set_is_open   (EvAnnotationMarkup *markup,
-                                                 gboolean            is_open);
-
-/* EvAnnotationText */
-GType         ev_annotation_text_get_type        (void) G_GNUC_CONST;
-EvAnnotation *ev_annotation_text_new             (EvPage             *page);
+GType                ev_annotation_markup_get_type           (void) G_GNUC_CONST;
+const gchar         *ev_annotation_markup_get_label          (EvAnnotationMarkup     *markup);
+gboolean             ev_annotation_markup_set_label          (EvAnnotationMarkup     *markup,
+                                                             const gchar            *label);
+gdouble              ev_annotation_markup_get_opacity        (EvAnnotationMarkup     *markup);
+gboolean             ev_annotation_markup_set_opacity        (EvAnnotationMarkup     *markup,
+                                                             gdouble                 opacity);
+gboolean             ev_annotation_markup_has_popup          (EvAnnotationMarkup     *markup);
+gboolean             ev_annotation_markup_set_has_popup      (EvAnnotationMarkup     *markup,
+                                                             gboolean                has_popup);
+void                 ev_annotation_markup_get_rectangle      (EvAnnotationMarkup     *markup,
+                                                             EvRectangle            *ev_rect);
+gboolean             ev_annotation_markup_set_rectangle      (EvAnnotationMarkup     *markup,
+                                                             const EvRectangle      *ev_rect);
+gboolean             ev_annotation_markup_get_popup_is_open  (EvAnnotationMarkup     *markup);
+gboolean             ev_annotation_markup_set_popup_is_open  (EvAnnotationMarkup     *markup,
+                                                             gboolean                is_open);
 
 /* EvAnnotationText */
-GType         ev_annotation_attachment_get_type  (void) G_GNUC_CONST;
-EvAnnotation *ev_annotation_attachment_new       (EvPage             *page,
-                                                 EvAttachment       *attachment);
+GType                ev_annotation_text_get_type             (void) G_GNUC_CONST;
+EvAnnotation        *ev_annotation_text_new                  (EvPage                 *page);
+EvAnnotationTextIcon ev_annotation_text_get_icon             (EvAnnotationText       *text);
+gboolean             ev_annotation_text_set_icon             (EvAnnotationText       *text,
+                                                             EvAnnotationTextIcon    icon);
+gboolean             ev_annotation_text_get_is_open          (EvAnnotationText       *text);
+gboolean             ev_annotation_text_set_is_open          (EvAnnotationText       *text,
+                                                             gboolean                is_open);
+
+/* EvAnnotationAttachment */
+GType                ev_annotation_attachment_get_type       (void) G_GNUC_CONST;
+EvAnnotation        *ev_annotation_attachment_new            (EvPage                 *page,
+                                                             EvAttachment           *attachment);
+EvAttachment        *ev_annotation_attachment_get_attachment (EvAnnotationAttachment *annot);
+gboolean             ev_annotation_attachment_set_attachment (EvAnnotationAttachment *annot,
+                                                             EvAttachment           *attachment);
 
 G_END_DECLS
 
index 6ccdd57d1fb69f66233bb451e6491757f4b191d2..4bc039ebbdd26cc353a8b8ef29fc04da46e21fc6 100644 (file)
@@ -38,11 +38,30 @@ ev_document_annotations_get_annotations (EvDocumentAnnotations *document_annots,
 }
 
 void
-ev_document_annotations_annotation_set_contents (EvDocumentAnnotations *document_annots,
-                                                EvAnnotation          *annot,
-                                                const gchar           *contents)
+ev_document_annotations_save_annotation (EvDocumentAnnotations *document_annots,
+                                        EvAnnotation          *annot,
+                                        EvAnnotationsSaveMask  mask)
 {
        EvDocumentAnnotationsInterface *iface = EV_DOCUMENT_ANNOTATIONS_GET_IFACE (document_annots);
 
-       iface->annotation_set_contents (document_annots, annot, contents);
+       iface->save_annotation (document_annots, annot, mask);
+}
+
+void
+ev_document_annotations_add_annotation (EvDocumentAnnotations *document_annots,
+                                       EvAnnotation          *annot,
+                                       EvRectangle           *rect)
+{
+       EvDocumentAnnotationsInterface *iface = EV_DOCUMENT_ANNOTATIONS_GET_IFACE (document_annots);
+
+       if (iface->add_annotation)
+               iface->add_annotation (document_annots, annot, rect);
+}
+
+gboolean
+ev_document_annotations_can_add_annotation (EvDocumentAnnotations *document_annots)
+{
+       EvDocumentAnnotationsInterface *iface = EV_DOCUMENT_ANNOTATIONS_GET_IFACE (document_annots);
+
+       return iface->add_annotation != NULL;
 }
index 6da49d9567fb528209967bc250bacdbee0cbeca8..8eb2c7c276f284fd375e9a26a5751f5aa6ced9ce 100644 (file)
@@ -40,6 +40,28 @@ G_BEGIN_DECLS
 #define EV_IS_DOCUMENT_ANNOTATIONS_IFACE(k)     (G_TYPE_CHECK_CLASS_TYPE ((k), EV_TYPE_DOCUMENT_ANNOTATIONS))
 #define EV_DOCUMENT_ANNOTATIONS_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), EV_TYPE_DOCUMENT_ANNOTATIONS, EvDocumentAnnotationsInterface))
 
+typedef enum {
+       EV_ANNOTATIONS_SAVE_NONE          = 0,
+       EV_ANNOTATIONS_SAVE_CONTENTS      = 1 << 0,
+       EV_ANNOTATIONS_SAVE_COLOR         = 1 << 1,
+
+       /* Markup Annotations */
+       EV_ANNOTATIONS_SAVE_LABEL         = 1 << 2,
+       EV_ANNOTATIONS_SAVE_OPACITY       = 1 << 3,
+       EV_ANNOTATIONS_SAVE_POPUP_RECT    = 1 << 4,
+       EV_ANNOTATIONS_SAVE_POPUP_IS_OPEN = 1 << 5,
+
+       /* Text Annotations */
+       EV_ANNOTATIONS_SAVE_TEXT_IS_OPEN  = 1 << 6,
+       EV_ANNOTATIONS_SAVE_TEXT_ICON     = 1 << 7,
+
+       /* Attachment Annotations */
+       EV_ANNOTATIONS_SAVE_ATTACHMENT    = 1 << 8,
+
+       /* Save all */
+       EV_ANNOTATIONS_SAVE_ALL           = (1 << 9) - 1
+} EvAnnotationsSaveMask;
+
 typedef struct _EvDocumentAnnotations          EvDocumentAnnotations;
 typedef struct _EvDocumentAnnotationsInterface EvDocumentAnnotationsInterface;
 
@@ -48,20 +70,26 @@ struct _EvDocumentAnnotationsInterface
        GTypeInterface base_iface;
 
        /* Methods  */
-       EvMappingList *(* get_annotations)         (EvDocumentAnnotations *document_annots,
-                                                   EvPage                *page);
-       void           (* annotation_set_contents) (EvDocumentAnnotations *document_annots,
-                                                   EvAnnotation          *annot,
-                                                   const gchar           *contents);
+       EvMappingList *(* get_annotations) (EvDocumentAnnotations *document_annots,
+                                           EvPage                *page);
+       void           (* add_annotation)  (EvDocumentAnnotations *document_annots,
+                                           EvAnnotation          *annot,
+                                           EvRectangle           *rect);
+       void           (* save_annotation) (EvDocumentAnnotations *document_annots,
+                                           EvAnnotation          *annot,
+                                           EvAnnotationsSaveMask  mask);
 };
 
-GType          ev_document_annotations_get_type                (void) G_GNUC_CONST;
-EvMappingList *ev_document_annotations_get_annotations         (EvDocumentAnnotations *document_annots,
-                                                               EvPage                *page);
-
-void           ev_document_annotations_annotation_set_contents (EvDocumentAnnotations *document_annots,
-                                                               EvAnnotation          *annot,
-                                                               const gchar           *contents);
+GType          ev_document_annotations_get_type           (void) G_GNUC_CONST;
+EvMappingList *ev_document_annotations_get_annotations    (EvDocumentAnnotations *document_annots,
+                                                          EvPage                *page);
+void           ev_document_annotations_add_annotation     (EvDocumentAnnotations *document_annots,
+                                                          EvAnnotation          *annot,
+                                                          EvRectangle           *rect);
+void           ev_document_annotations_save_annotation    (EvDocumentAnnotations *document_annots,
+                                                          EvAnnotation          *annot,
+                                                          EvAnnotationsSaveMask  mask);
+gboolean       ev_document_annotations_can_add_annotation (EvDocumentAnnotations *document_annots);
 
 G_END_DECLS
 
index 559b879f5cf941cfe01dd4c6de9c001e69aa680a..749d1a012ad53d7132bca109a2769ea10660bfd3 100644 (file)
@@ -53,7 +53,7 @@ struct _EvAnnotationWindow {
        GtkWidget    *resize_sw;
 
        gboolean      is_open;
-       EvRectangle  *rect;
+       EvRectangle   rect;
 
        gboolean      in_move;
        gint          x;
@@ -116,7 +116,7 @@ ev_annotation_window_get_icon_size (void)
 }
 
 static void
-ev_annotation_window_check_contents_modified (EvAnnotationWindow *window)
+ev_annotation_window_sync_contents (EvAnnotationWindow *window)
 {
        gchar         *contents;
        GtkTextIter    start, end;
@@ -126,23 +126,8 @@ ev_annotation_window_check_contents_modified (EvAnnotationWindow *window)
        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->text_view));
        gtk_text_buffer_get_bounds (buffer, &start, &end);
        contents = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
-
-       if (contents && annot->contents) {
-               if (strcasecmp (contents, annot->contents) != 0) {
-                       g_free (annot->contents);
-                       annot->contents = contents;
-                       annot->changed = TRUE;
-               } else {
-                       g_free (contents);
-               }
-       } else if (annot->contents) {
-               g_free (annot->contents);
-               annot->contents = NULL;
-               annot->changed = TRUE;
-       } else if (contents) {
-               annot->contents = contents;
-               annot->changed = TRUE;
-       }
+       ev_annotation_set_contents (annot, contents);
+       g_free (contents);
 }
 
 static void
@@ -177,22 +162,39 @@ ev_annotation_window_set_color (EvAnnotationWindow *window,
        g_object_unref (rc_style);
 }
 
+static void
+ev_annotation_window_label_changed (EvAnnotationMarkup *annot,
+                                   GParamSpec         *pspec,
+                                   EvAnnotationWindow *window)
+{
+       const gchar *label = ev_annotation_markup_get_label (annot);
+
+       gtk_window_set_title (GTK_WINDOW (window), label);
+       gtk_label_set_text (GTK_LABEL (window->title), label);
+}
+
+static void
+ev_annotation_window_color_changed (EvAnnotation       *annot,
+                                   GParamSpec         *pspec,
+                                   EvAnnotationWindow *window)
+{
+       GdkColor color;
+
+       ev_annotation_get_color (annot, &color);
+       ev_annotation_window_set_color (window, &color);
+}
+
 static void
 ev_annotation_window_dispose (GObject *object)
 {
        EvAnnotationWindow *window = EV_ANNOTATION_WINDOW (object);
 
        if (window->annotation) {
-               ev_annotation_window_check_contents_modified (window);
+               ev_annotation_window_sync_contents (window);
                g_object_unref (window->annotation);
                window->annotation = NULL;
        }
 
-       if (window->rect) {
-               ev_rectangle_free (window->rect);
-               window->rect = NULL;
-       }
-
        (* G_OBJECT_CLASS (ev_annotation_window_parent_class)->dispose) (object);
 }
 
@@ -391,8 +393,10 @@ ev_annotation_window_constructor (GType                  type,
        GObject            *object;
        EvAnnotationWindow *window;
        EvAnnotation       *annot;
-       gchar              *label;
-       gdouble             opacity;
+       EvAnnotationMarkup *markup;
+       const gchar        *contents;
+       const gchar        *label;
+       GdkColor            color;
        EvRectangle        *rect;
        gdouble             scale;
 
@@ -401,37 +405,44 @@ ev_annotation_window_constructor (GType                  type,
                                                                                  construct_params);
        window = EV_ANNOTATION_WINDOW (object);
        annot = window->annotation;
+       markup = EV_ANNOTATION_MARKUP (annot);
 
        gtk_window_set_transient_for (GTK_WINDOW (window), window->parent);
        gtk_window_set_destroy_with_parent (GTK_WINDOW (window), FALSE);
 
-       g_object_get (annot,
-                     "label", &label,
-                     "opacity", &opacity,
-                     "is_open", &window->is_open,
-                     "rectangle", &window->rect,
-                     NULL);
-       rect = window->rect;
+       label = ev_annotation_markup_get_label (markup);
+       window->is_open = ev_annotation_markup_get_popup_is_open (markup);
+       ev_annotation_markup_get_rectangle (markup, &window->rect);
+
+       rect = &window->rect;
 
        /* Rectangle is at doc resolution (72.0) */
        scale = get_screen_dpi (window) / 72.0;
        gtk_window_resize (GTK_WINDOW (window),
                           (gint)((rect->x2 - rect->x1) * scale),
                           (gint)((rect->y2 - rect->y1) * scale));
-       ev_annotation_window_set_color (window, &annot->color);
-       gtk_widget_set_name (GTK_WIDGET (window), annot->name);
+
+       ev_annotation_get_color (annot, &color);
+       ev_annotation_window_set_color (window, &color);
+       gtk_widget_set_name (GTK_WIDGET (window), ev_annotation_get_name (annot));
        gtk_window_set_title (GTK_WINDOW (window), label);
        gtk_label_set_text (GTK_LABEL (window->title), label);
-       gtk_window_set_opacity (GTK_WINDOW (window), opacity);
-       g_free (label);
 
-       if (annot->contents) {
+       contents = ev_annotation_get_contents (annot);
+       if (contents) {
                GtkTextBuffer *buffer;
 
                buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->text_view));
-               gtk_text_buffer_set_text (buffer, annot->contents, -1);
+               gtk_text_buffer_set_text (buffer, contents, -1);
        }
 
+       g_signal_connect (annot, "notify::label",
+                         G_CALLBACK (ev_annotation_window_label_changed),
+                         window);
+       g_signal_connect (annot, "notify::color",
+                         G_CALLBACK (ev_annotation_window_color_changed),
+                         window);
+
        return object;
 }
 
@@ -497,6 +508,8 @@ ev_annotation_window_focus_out_event (GtkWidget     *widget,
                g_signal_emit (window, signals[MOVED], 0, window->x, window->y);
        }
 
+       ev_annotation_window_sync_contents (window);
+
        return FALSE;
 }
 
@@ -587,7 +600,7 @@ ev_annotation_window_set_annotation (EvAnnotationWindow *window,
 
        g_object_unref (window->annotation);
        window->annotation = g_object_ref (annot);
-       ev_annotation_window_check_contents_modified (window);
+       ev_annotation_window_sync_contents (window);
        g_object_notify (G_OBJECT (window), "annotation");
 }
 
@@ -599,22 +612,24 @@ ev_annotation_window_is_open (EvAnnotationWindow *window)
        return window->is_open;
 }
 
-const EvRectangle *
-ev_annotation_window_get_rectangle (EvAnnotationWindow *window)
+void
+ev_annotation_window_get_rectangle (EvAnnotationWindow *window,
+                                   EvRectangle        *rect)
 {
-       g_return_val_if_fail (EV_IS_ANNOTATION_WINDOW (window), NULL);
+       g_return_if_fail (EV_IS_ANNOTATION_WINDOW (window));
+       g_return_if_fail (rect != NULL);
 
-       return window->rect;
+       *rect = window->rect;
 }
 
 void
 ev_annotation_window_set_rectangle (EvAnnotationWindow *window,
-                                   EvRectangle        *rect)
+                                   const EvRectangle  *rect)
 {
        g_return_if_fail (EV_IS_ANNOTATION_WINDOW (window));
        g_return_if_fail (rect != NULL);
 
-       *window->rect = *rect;
+       window->rect = *rect;
 }
 
 void
@@ -637,5 +652,5 @@ ev_annotation_window_ungrab_focus (EvAnnotationWindow *window)
                send_focus_change (window->text_view, FALSE);
        }
 
-       ev_annotation_window_check_contents_modified (window);
+       ev_annotation_window_sync_contents (window);
 }
index 697574f784bbef8bd34f9db018b36c03fbc40719..b9ba4f128edd2033cc48aff7e7031dcdd7216392 100644 (file)
@@ -38,18 +38,19 @@ typedef struct _EvAnnotationWindowClass EvAnnotationWindowClass;
 #define EV_IS_ANNOTATION_WINDOW_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_ANNOTATION_WINDOW))
 #define EV_ANNOTATION_WINDOW_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_ANNOTATION_WINDOW, EvAnnotationWindowClass))
 
-GType              ev_annotation_window_get_type       (void) G_GNUC_CONST;
-GtkWidget         *ev_annotation_window_new            (EvAnnotation       *annot,
-                                                       GtkWindow          *parent);
-EvAnnotation      *ev_annotation_window_get_annotation (EvAnnotationWindow *window);
-void               ev_annotation_window_set_annotation (EvAnnotationWindow *window,
-                                                       EvAnnotation       *annot);
-gboolean           ev_annotation_window_is_open        (EvAnnotationWindow *window);
-const EvRectangle *ev_annotation_window_get_rectangle  (EvAnnotationWindow *window);
-void               ev_annotation_window_set_rectangle  (EvAnnotationWindow *window,
-                                                       EvRectangle        *rect);
-void               ev_annotation_window_grab_focus     (EvAnnotationWindow *window);
-void               ev_annotation_window_ungrab_focus   (EvAnnotationWindow *window);
+GType         ev_annotation_window_get_type       (void) G_GNUC_CONST;
+GtkWidget    *ev_annotation_window_new            (EvAnnotation       *annot,
+                                                  GtkWindow          *parent);
+EvAnnotation *ev_annotation_window_get_annotation (EvAnnotationWindow *window);
+void          ev_annotation_window_set_annotation (EvAnnotationWindow *window,
+                                                  EvAnnotation       *annot);
+gboolean      ev_annotation_window_is_open        (EvAnnotationWindow *window);
+void          ev_annotation_window_get_rectangle  (EvAnnotationWindow *window,
+                                                  EvRectangle        *rect);
+void          ev_annotation_window_set_rectangle  (EvAnnotationWindow *window,
+                                                  const EvRectangle  *rect);
+void          ev_annotation_window_grab_focus     (EvAnnotationWindow *window);
+void          ev_annotation_window_ungrab_focus   (EvAnnotationWindow *window);
 
 G_END_DECLS
 
index 6974d3f7cdcbe31d8a94256442e2039209035d82..67cacd73d6da714b7b8c81165b77aa80a4da7514 100644 (file)
@@ -58,6 +58,9 @@ ev_view_cursor_new (GdkDisplay  *display,
        case EV_VIEW_CURSOR_AUTOSCROLL:
                cursor = gdk_cursor_new_for_display (display, GDK_DOUBLE_ARROW);
                break;
+       case EV_VIEW_CURSOR_ADD:
+               cursor = gdk_cursor_new_for_display (display, GDK_PLUS);
+               break;
        }
 
        return cursor;
index 012d5a450da6ebc6b3d32cec2a6cf3338c73798e..220441c6088fd15e0c6c9346798a4c4fd949022a 100644 (file)
@@ -35,7 +35,8 @@ typedef enum {
        EV_VIEW_CURSOR_WAIT,
        EV_VIEW_CURSOR_HIDDEN,
        EV_VIEW_CURSOR_DRAG,
-       EV_VIEW_CURSOR_AUTOSCROLL
+       EV_VIEW_CURSOR_AUTOSCROLL,
+       EV_VIEW_CURSOR_ADD
 } EvViewCursor;
 
 GdkCursor *ev_view_cursor_new (GdkDisplay  *display,
index 57eea303bad316c4ced4cbb8c5337b723e3d7738..a3655072f576d140ba126d36e76eada3c1479ed2 100644 (file)
@@ -185,6 +185,8 @@ struct _EvView {
        GList             *window_children;
        EvViewWindowChild *window_child_focus;
        EvMapping         *focus_annotation;
+       gboolean           adding_annot;
+       EvAnnotationType   adding_annot_type;
 
        /* Synctex */
        EvMapping *synctex_result;
@@ -208,6 +210,8 @@ struct _EvViewClass {
        void    (*selection_changed)      (EvView         *view);
        void    (*sync_source)            (EvView         *view,
                                           EvSourceLink   *link);
+       void    (*annot_added)            (EvView         *view,
+                                          EvAnnotation   *annot);
 };
 
 void _get_page_size_for_scale_and_rotation (EvDocument *document,
index eee1b56331eb6366cdbc7d0426120e6293513be1..471c66ca81aeb7c178e286020469dec8b9292896 100644 (file)
@@ -55,6 +55,7 @@ enum {
        SIGNAL_POPUP_MENU,
        SIGNAL_SELECTION_CHANGED,
        SIGNAL_SYNC_SOURCE,
+       SIGNAL_ANNOT_ADDED,
        N_SIGNALS
 };
 
@@ -1832,6 +1833,12 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
        if (view->cursor == EV_VIEW_CURSOR_HIDDEN)
                return;
 
+       if (view->adding_annot) {
+               if (view->cursor != EV_VIEW_CURSOR_ADD)
+                       ev_view_set_cursor (view, EV_VIEW_CURSOR_ADD);
+               return;
+       }
+
        if (view->drag_info.in_drag) {
                if (view->cursor != EV_VIEW_CURSOR_DRAG)
                        ev_view_set_cursor (view, EV_VIEW_CURSOR_DRAG);
@@ -1866,7 +1873,8 @@ ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y)
                if (view->cursor == EV_VIEW_CURSOR_LINK ||
                    view->cursor == EV_VIEW_CURSOR_IBEAM ||
                    view->cursor == EV_VIEW_CURSOR_DRAG ||
-                   view->cursor == EV_VIEW_CURSOR_AUTOSCROLL)
+                   view->cursor == EV_VIEW_CURSOR_AUTOSCROLL ||
+                   view->cursor == EV_VIEW_CURSOR_ADD)
                        ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
        }
 
@@ -2494,7 +2502,7 @@ ev_view_find_window_child_for_annot (EvView       *view,
                        continue;
 
                wannot = ev_annotation_window_get_annotation (EV_ANNOTATION_WINDOW (child->window));
-               if (wannot == annot || strcmp (wannot->name, annot->name) == 0)
+               if (ev_annotation_equal (wannot, annot))
                        return child;
        }
 
@@ -2577,18 +2585,55 @@ annotation_window_moved (EvAnnotationWindow *window,
 }
 
 static void
-ev_view_annotation_save (EvView       *view,
-                        EvAnnotation *annot)
+ev_view_annotation_save_contents (EvView       *view,
+                                 GParamSpec   *pspec,
+                                 EvAnnotation *annot)
 {
        if (!view->document)
                return;
 
-       if (!annot->changed)
-               return;
+       ev_document_doc_mutex_lock ();
+       ev_document_annotations_save_annotation (EV_DOCUMENT_ANNOTATIONS (view->document),
+                                                annot, EV_ANNOTATIONS_SAVE_CONTENTS);
+       ev_document_doc_mutex_unlock ();
+}
 
-       ev_document_annotations_annotation_set_contents (EV_DOCUMENT_ANNOTATIONS (view->document),
-                                                        annot, annot->contents);
-       annot->changed = FALSE;
+static GtkWidget *
+ev_view_create_annotation_window (EvView       *view,
+                                 EvAnnotation *annot,
+                                 GtkWindow    *parent)
+{
+       GtkWidget   *window;
+       EvRectangle  doc_rect;
+       GdkRectangle view_rect;
+       guint        page;
+
+       window = ev_annotation_window_new (annot, parent);
+       g_signal_connect (window, "grab_focus",
+                         G_CALLBACK (annotation_window_grab_focus),
+                         view);
+       g_signal_connect (window, "closed",
+                         G_CALLBACK (annotation_window_closed),
+                         view);
+       g_signal_connect (window, "moved",
+                         G_CALLBACK (annotation_window_moved),
+                         view);
+       g_signal_connect_swapped (annot, "notify::contents",
+                                 G_CALLBACK (ev_view_annotation_save_contents),
+                                 view);
+       g_object_set_data (G_OBJECT (annot), "popup", window);
+
+       page = ev_annotation_get_page_index (annot);
+       ev_annotation_window_get_rectangle (EV_ANNOTATION_WINDOW (window), &doc_rect);
+       doc_rect_to_view_rect (view, page, &doc_rect, &view_rect);
+       view_rect.x -= view->scroll_x;
+       view_rect.y -= view->scroll_y;
+
+       ev_view_window_child_put (view, window, page,
+                                 view_rect.x, view_rect.y,
+                                 doc_rect.x1, doc_rect.y1);
+
+       return window;
 }
 
 static void
@@ -2607,8 +2652,6 @@ show_annotation_windows (EvView *view,
                EvAnnotation      *annot;
                EvViewWindowChild *child;
                GtkWidget         *window;
-               EvRectangle       *doc_rect;
-               GdkRectangle       view_rect;
 
                annot = ((EvMapping *)(l->data))->data;
 
@@ -2632,30 +2675,7 @@ show_annotation_windows (EvView *view,
                        g_object_set_data (G_OBJECT (annot), "popup", window);
                        ev_view_window_child_move_with_parent (view, window);
                } else {
-                       window = ev_annotation_window_new (annot, parent);
-                       g_signal_connect (window, "grab_focus",
-                                         G_CALLBACK (annotation_window_grab_focus),
-                                         view);
-                       g_signal_connect (window, "closed",
-                                         G_CALLBACK (annotation_window_closed),
-                                         view);
-                       g_signal_connect (window, "moved",
-                                         G_CALLBACK (annotation_window_moved),
-                                         view);
-                       g_object_set_data (G_OBJECT (annot), "popup", window);
-
-                       doc_rect = (EvRectangle *)ev_annotation_window_get_rectangle (EV_ANNOTATION_WINDOW (window));
-                       doc_rect_to_view_rect (view, page, doc_rect, &view_rect);
-                       view_rect.x -= view->scroll_x;
-                       view_rect.y -= view->scroll_y;
-
-                       ev_view_window_child_put (view, window, page,
-                                                 view_rect.x, view_rect.y,
-                                                 doc_rect->x1, doc_rect->y1);
-
-                       g_object_weak_ref (G_OBJECT (annot),
-                                          (GWeakNotify)ev_view_annotation_save,
-                                          view);
+                       ev_view_create_annotation_window (view, annot, parent);
                }
        }
 }
@@ -2707,6 +2727,23 @@ ev_view_get_annotation_at_location (EvView  *view,
                return NULL;
 }
 
+static void
+ev_view_annotation_show_popup_window (EvView    *view,
+                                     GtkWidget *window)
+{
+       EvViewWindowChild *child;
+
+       if (!window)
+               return;
+
+       child = ev_view_get_window_child (view, window);
+       if (!child->visible) {
+               child->visible = TRUE;
+               ev_view_window_child_move (view, child, child->x, child->y);
+               gtk_widget_show (window);
+       }
+}
+
 static void
 ev_view_handle_annotation (EvView       *view,
                           EvAnnotation *annot,
@@ -2718,21 +2755,13 @@ ev_view_handle_annotation (EvView       *view,
                GtkWidget *window;
 
                window = g_object_get_data (G_OBJECT (annot), "popup");
-               if (window) {
-                       EvViewWindowChild *child;
-
-                       child = ev_view_get_window_child (view, window);
-                       if (!child->visible) {
-                               child->visible = TRUE;
-                               ev_view_window_child_move (view, child, child->x, child->y);
-                               gtk_widget_show (window);
-                       }
-               }
+               ev_view_annotation_show_popup_window (view, window);
        }
 
        if (EV_IS_ANNOTATION_ATTACHMENT (annot)) {
-               EvAttachment *attachment = EV_ANNOTATION_ATTACHMENT (annot)->attachment;
+               EvAttachment *attachment;
 
+               attachment = ev_annotation_attachment_get_attachment (EV_ANNOTATION_ATTACHMENT (annot));
                if (attachment) {
                        GError *error = NULL;
 
@@ -2749,12 +2778,97 @@ ev_view_handle_annotation (EvView       *view,
        }
 }
 
+static void
+ev_view_create_annotation (EvView          *view,
+                          EvAnnotationType annot_type,
+                          gint             x,
+                          gint             y)
+{
+       EvAnnotation   *annot;
+       GdkPoint        point;
+       GdkRectangle    page_area;
+       GtkBorder       border;
+       EvRectangle     doc_rect, popup_rect;
+       EvPage         *page;
+       GdkColor        color = { 0, 65535, 65535, 0 };
+       GdkRectangle    view_rect;
+       cairo_region_t *region;
+
+       point.x = x;
+       point.y = y;
+       ev_view_get_page_extents (view, view->current_page, &page_area, &border);
+       view_point_to_doc_point (view, &point, &page_area,
+                                &doc_rect.x1, &doc_rect.y1);
+       doc_rect.x2 = doc_rect.x1 + 24;
+       doc_rect.y2 = doc_rect.y1 + 24;
+
+       ev_document_doc_mutex_lock ();
+       page = ev_document_get_page (view->document, view->current_page);
+       switch (annot_type) {
+       case EV_ANNOTATION_TYPE_TEXT:
+               annot = ev_annotation_text_new (page);
+               break;
+       case EV_ANNOTATION_TYPE_ATTACHMENT:
+               /* TODO */
+               g_object_unref (page);
+               ev_document_doc_mutex_unlock ();
+               return;
+       default:
+               g_assert_not_reached ();
+       }
+       g_object_unref (page);
+
+       ev_annotation_set_color (annot, &color);
+
+       if (EV_IS_ANNOTATION_MARKUP (annot)) {
+               popup_rect.x1 = doc_rect.x2;
+               popup_rect.x2 = popup_rect.x1 + 200;
+               popup_rect.y1 = doc_rect.y2;
+               popup_rect.y2 = popup_rect.y1 + 150;
+               g_object_set (annot,
+                             "rectangle", &popup_rect,
+                             "has_popup", TRUE,
+                             "popup_is_open", FALSE,
+                             "label", g_get_real_name (),
+                             "opacity", 1.0,
+                             NULL);
+       }
+       ev_document_annotations_add_annotation (EV_DOCUMENT_ANNOTATIONS (view->document),
+                                               annot, &doc_rect);
+       ev_document_doc_mutex_unlock ();
+
+       /* If the page didn't have annots, mark the cache as dirty */
+       if (!ev_page_cache_get_annot_mapping (view->page_cache, view->current_page))
+               ev_page_cache_mark_dirty (view->page_cache, view->current_page);
+
+       if (EV_IS_ANNOTATION_MARKUP (annot)) {
+               GtkWindow *parent;
+               GtkWidget *window;
+
+               parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view)));
+               window = ev_view_create_annotation_window (view, annot, parent);
+
+               /* Show the annot window the first time */
+               ev_view_annotation_show_popup_window (view, window);
+       }
+
+       doc_rect_to_view_rect (view, view->current_page, &doc_rect, &view_rect);
+       view_rect.x -= view->scroll_x;
+       view_rect.y -= view->scroll_y;
+       region = cairo_region_create_rectangle (&view_rect);
+       ev_view_reload_page (view, view->current_page, region);
+       cairo_region_destroy (region);
+
+       g_signal_emit (view, signals[SIGNAL_ANNOT_ADDED], 0, annot);
+}
+
 void
 ev_view_focus_annotation (EvView    *view,
                          EvMapping *annot_mapping)
 {
        GdkRectangle  view_rect;
        EvAnnotation *annot;
+       guint         page;
 
        if (!EV_IS_DOCUMENT_ANNOTATIONS (view->document))
                return;
@@ -2765,14 +2879,43 @@ ev_view_focus_annotation (EvView    *view,
        view->focus_annotation = annot_mapping;
        annot = (EvAnnotation *)annot_mapping->data;
 
-       ev_document_model_set_page (view->model, annot->page->index);
+       page = ev_annotation_get_page_index (annot);
+       ev_document_model_set_page (view->model, page);
 
-       doc_rect_to_view_rect (view, annot->page->index,
+       doc_rect_to_view_rect (view, page,
                               &annot_mapping->area, &view_rect);
        ensure_rectangle_is_visible (view, &view_rect);
        gtk_widget_queue_draw (GTK_WIDGET (view));
 }
 
+void
+ev_view_begin_add_annotation (EvView          *view,
+                             EvAnnotationType annot_type)
+{
+       if (annot_type == EV_ANNOTATION_TYPE_UNKNOWN)
+               return;
+
+       if (view->adding_annot)
+               return;
+
+       view->adding_annot = TRUE;
+       view->adding_annot_type = annot_type;
+       ev_view_set_cursor (view, EV_VIEW_CURSOR_ADD);
+}
+
+void
+ev_view_cancel_add_annotation (EvView *view)
+{
+       gint x, y;
+
+       if (!view->adding_annot)
+               return;
+
+       view->adding_annot = FALSE;
+       gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
+       ev_view_handle_cursor_over_xy (view, x, y);
+}
+
 static gboolean
 ev_view_synctex_backward_search (EvView *view,
                                 gdouble x,
@@ -3040,7 +3183,7 @@ ev_view_size_allocate (GtkWidget      *widget,
 
                child = (EvViewWindowChild *)l->data;
 
-               doc_rect = *ev_annotation_window_get_rectangle (EV_ANNOTATION_WINDOW (child->window));
+               ev_annotation_window_get_rectangle (EV_ANNOTATION_WINDOW (child->window), &doc_rect);
                if (child->moved) {
                        doc_rect.x1 = child->orig_x;
                        doc_rect.y1 = child->orig_y;
@@ -3311,14 +3454,18 @@ ev_view_query_tooltip (GtkWidget  *widget,
        gchar        *text;
 
        annot = ev_view_get_annotation_at_location (view, x, y);
-       if (annot && annot->contents) {
-               GdkRectangle annot_area;
+       if (annot) {
+               const gchar *contents;
 
-               get_annot_area (view, x, y, annot, &annot_area);
-               gtk_tooltip_set_text (tooltip, annot->contents);
-               gtk_tooltip_set_tip_area (tooltip, &annot_area);
+               if ((contents = ev_annotation_get_contents (annot))) {
+                       GdkRectangle annot_area;
 
-               return TRUE;
+                       get_annot_area (view, x, y, annot, &annot_area);
+                       gtk_tooltip_set_text (tooltip, contents);
+                       gtk_tooltip_set_tip_area (tooltip, &annot_area);
+
+                       return TRUE;
+               }
        }
 
        link = ev_view_get_link_at_location (view, x, y);
@@ -3386,13 +3533,15 @@ ev_view_button_press_event (GtkWidget      *widget,
                window = EV_ANNOTATION_WINDOW (view->window_child_focus->window);
                annot = ev_annotation_window_get_annotation (window);
                ev_annotation_window_ungrab_focus (window);
-               ev_view_annotation_save (view, annot);
                view->window_child_focus = NULL;
        }
        
        view->pressed_button = event->button;
        view->selection_info.in_drag = FALSE;
 
+       if (view->adding_annot)
+               return FALSE;
+
        if (view->scroll_info.autoscrolling)
                return TRUE;
        
@@ -3861,6 +4010,19 @@ ev_view_button_release_event (GtkWidget      *widget,
 
        view->drag_info.in_drag = FALSE;
 
+       if (view->adding_annot && view->pressed_button == 1) {
+               view->adding_annot = FALSE;
+               ev_view_handle_cursor_over_xy (view, event->x, event->y);
+               view->pressed_button = -1;
+
+               ev_view_create_annotation (view,
+                                          view->adding_annot_type,
+                                          event->x + view->scroll_x,
+                                          event->y + view->scroll_y);
+
+               return FALSE;
+       }
+
        if (view->pressed_button == 2) {
                ev_view_handle_cursor_over_xy (view, event->x, event->y);
        }
@@ -4094,7 +4256,7 @@ focus_annotation (EvView       *view,
        EvMapping    *mapping = view->focus_annotation;
        EvAnnotation *annot = (EvAnnotation *)mapping->data;
 
-       if (annot->page->index != page)
+       if (ev_annotation_get_page_index (annot) != page)
                return;
 
        doc_rect_to_view_rect (view, page, &mapping->area, &rect);
@@ -4505,6 +4667,14 @@ ev_view_class_init (EvViewClass *class)
                         g_cclosure_marshal_VOID__POINTER,
                         G_TYPE_NONE, 1,
                         G_TYPE_POINTER);
+       signals[SIGNAL_ANNOT_ADDED] = g_signal_new ("annot-added",
+                        G_TYPE_FROM_CLASS (object_class),
+                        G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                        G_STRUCT_OFFSET (EvViewClass, annot_added),
+                        NULL, NULL,
+                        g_cclosure_marshal_VOID__OBJECT,
+                        G_TYPE_NONE, 1,
+                        EV_TYPE_ANNOTATION);
 
        binding_set = gtk_binding_set_by_class (class);
 
index 712d5546c339e65307f8aa4d3d528f4d5baf2a1b..06f5b30d550c50cdaddc143dedf9a0c1692155bb 100644 (file)
@@ -103,9 +103,12 @@ gboolean       ev_view_get_page_extents   (EvView       *view,
                                            gint          page,
                                            GdkRectangle *page_area,
                                            GtkBorder    *border);
-
-void           ev_view_focus_annotation   (EvView       *view,
-                                          EvMapping    *annot_mapping);
+/* Annotations */
+void           ev_view_focus_annotation      (EvView          *view,
+                                             EvMapping       *annot_mapping);
+void           ev_view_begin_add_annotation  (EvView          *view,
+                                             EvAnnotationType annot_type);
+void           ev_view_cancel_add_annotation (EvView          *view);
 
 G_END_DECLS
 
index b2eac5e198e8555669971c711c6ea75de9ce6ecd..c93d309f7411e946d0e28138c0b0b533676666da 100644 (file)
@@ -38,6 +38,7 @@ libview/ev-view-accessible.c
 libview/ev-view-presentation.c
 libview/ev-view.c
 shell/eggfindbar.c
+shell/ev-annotation-properties-dialog.c
 shell/ev-application.c
 shell/ev-history.c
 shell/ev-keyring.c
index 523d299fb94a632929109f805024b6f9a92837dd..8336230f007890869122b807d56b3a1b4231fc3b 100644 (file)
@@ -32,6 +32,8 @@ endif
 evince_SOURCES=                                \
        eggfindbar.c                    \
        eggfindbar.h                    \
+       ev-annotation-properties-dialog.h \
+       ev-annotation-properties-dialog.c \
        ev-application.c                \
        ev-application.h                \
        ev-file-monitor.h               \
diff --git a/shell/ev-annotation-properties-dialog.c b/shell/ev-annotation-properties-dialog.c
new file mode 100644 (file)
index 0000000..0f5c6e1
--- /dev/null
@@ -0,0 +1,327 @@
+/* ev-annotation-properties-dialog.c
+ *  this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2010 Carlos Garcia Campos  <carlosgc@gnome.org>
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <glib/gi18n.h>
+
+#include "ev-annotation-properties-dialog.h"
+
+enum {
+       PROP_0,
+       PROP_ANNOT_TYPE
+};
+
+struct _EvAnnotationPropertiesDialog {
+       GtkDialog        base_instance;
+
+       EvAnnotationType annot_type;
+       EvAnnotation    *annot;
+
+       GtkWidget       *table;
+
+       GtkWidget       *author;
+       GtkWidget       *color;
+       GtkWidget       *opacity;
+       GtkWidget       *popup_state;
+
+       /* Text Annotations */
+       GtkWidget       *icon;
+};
+
+struct _EvAnnotationPropertiesDialogClass {
+       GtkDialogClass base_class;
+};
+
+G_DEFINE_TYPE (EvAnnotationPropertiesDialog, ev_annotation_properties_dialog, GTK_TYPE_DIALOG)
+
+static void
+ev_annotation_properties_dialog_dispose (GObject *object)
+{
+       EvAnnotationPropertiesDialog *dialog = EV_ANNOTATION_PROPERTIES_DIALOG (object);
+
+       if (dialog->annot) {
+               g_object_unref (dialog->annot);
+               dialog->annot = NULL;
+       }
+
+       G_OBJECT_CLASS (ev_annotation_properties_dialog_parent_class)->dispose (object);
+}
+
+static void
+ev_annotation_properties_dialog_set_property (GObject      *object,
+                                             guint         prop_id,
+                                             const GValue *value,
+                                             GParamSpec   *pspec)
+{
+       EvAnnotationPropertiesDialog *dialog = EV_ANNOTATION_PROPERTIES_DIALOG (object);
+
+       switch (prop_id) {
+       case PROP_ANNOT_TYPE:
+               dialog->annot_type = g_value_get_enum (value);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
+}
+
+static void
+ev_annotation_properties_dialog_constructed (GObject *object)
+{
+       EvAnnotationPropertiesDialog *dialog = EV_ANNOTATION_PROPERTIES_DIALOG (object);
+       GtkWidget *contant_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+       GtkWidget *table = dialog->table;
+       GtkWidget *label;
+
+       contant_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+       switch (dialog->annot_type) {
+       case EV_ANNOTATION_TYPE_TEXT:
+               label = gtk_label_new (_("Icon:"));
+               gtk_misc_set_alignment (GTK_MISC (label), 0., 0.5);
+               gtk_table_attach (GTK_TABLE (table), label, 0, 1, 5, 6,
+                                 GTK_FILL, GTK_FILL, 0, 0);
+               gtk_widget_show (label);
+
+               dialog->icon = gtk_combo_box_new_text ();
+               gtk_combo_box_append_text (GTK_COMBO_BOX (dialog->icon), _("Note"));
+               gtk_combo_box_append_text (GTK_COMBO_BOX (dialog->icon), _("Comment"));
+               gtk_combo_box_append_text (GTK_COMBO_BOX (dialog->icon), _("Key"));
+               gtk_combo_box_append_text (GTK_COMBO_BOX (dialog->icon), _("Help"));
+               gtk_combo_box_append_text (GTK_COMBO_BOX (dialog->icon), _("New Paragraph"));
+               gtk_combo_box_append_text (GTK_COMBO_BOX (dialog->icon), _("Paragraph"));
+               gtk_combo_box_append_text (GTK_COMBO_BOX (dialog->icon), _("Insert"));
+               gtk_combo_box_append_text (GTK_COMBO_BOX (dialog->icon), _("Cross"));
+               gtk_combo_box_append_text (GTK_COMBO_BOX (dialog->icon), _("Circle"));
+               gtk_combo_box_append_text (GTK_COMBO_BOX (dialog->icon), _("Unknown"));
+               gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->icon), 0);
+               gtk_table_attach (GTK_TABLE (table), dialog->icon,
+                                 1, 2, 5, 6,
+                                 GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
+               gtk_widget_show (dialog->icon);
+
+               break;
+       case EV_ANNOTATION_TYPE_ATTACHMENT:
+               /* TODO */
+       default:
+               break;
+       }
+}
+
+static void
+ev_annotation_properties_dialog_init (EvAnnotationPropertiesDialog *annot_dialog)
+{
+       GtkDialog *dialog = GTK_DIALOG (annot_dialog);
+       GtkWidget *content_area;
+       GtkWidget *label;
+       GtkWidget *table;
+       GtkWidget *hbox;
+       gchar     *markup;
+       GdkColor   color = { 0, 65535, 65535, 0 };
+
+       gtk_window_set_title (GTK_WINDOW (annot_dialog), _("Annotation Properties"));
+       gtk_window_set_destroy_with_parent (GTK_WINDOW (annot_dialog), TRUE);
+       gtk_container_set_border_width (GTK_CONTAINER (annot_dialog), 5);
+       gtk_dialog_set_has_separator (dialog, FALSE);
+       gtk_dialog_add_buttons (dialog,
+                               GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+                               GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
+                               NULL);
+       gtk_dialog_set_default_response (dialog, GTK_RESPONSE_APPLY);
+
+       content_area = gtk_dialog_get_content_area (dialog);
+       gtk_box_set_spacing (GTK_BOX (content_area), 2);
+
+       table = gtk_table_new (5, 2, FALSE);
+       annot_dialog->table = table;
+       gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+       gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+       gtk_container_set_border_width (GTK_CONTAINER (table), 12);
+       gtk_box_pack_start (GTK_BOX (content_area), table, FALSE, FALSE, 0);
+       gtk_widget_show (table);
+
+       label = gtk_label_new (_("Author:"));
+       gtk_misc_set_alignment (GTK_MISC (label), 0., 0.5);
+       gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
+                         GTK_FILL, GTK_FILL, 0, 0);
+       gtk_widget_show (label);
+
+       annot_dialog->author = gtk_entry_new ();
+       gtk_entry_set_text (GTK_ENTRY (annot_dialog->author), g_get_real_name ());
+       gtk_table_attach (GTK_TABLE (table), annot_dialog->author,
+                         1, 2, 0, 1,
+                         GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
+       gtk_widget_show (annot_dialog->author);
+
+       label = gtk_label_new (_("Color:"));
+       gtk_misc_set_alignment (GTK_MISC (label), 0., 0.5);
+       gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
+                         GTK_FILL, GTK_FILL, 0, 0);
+       gtk_widget_show (label);
+
+       annot_dialog->color = gtk_color_button_new_with_color (&color);
+       gtk_table_attach (GTK_TABLE (table), annot_dialog->color,
+                         1, 2, 1, 2,
+                         GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
+       gtk_widget_show (annot_dialog->color);
+
+       label = gtk_label_new (_("Style:"));
+       gtk_misc_set_alignment (GTK_MISC (label), 0., 0.5);
+       gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
+                         GTK_FILL, GTK_FILL, 0, 0);
+       gtk_widget_show (label);
+
+       annot_dialog->opacity = gtk_hscale_new_with_range (0, 100, 5);
+       gtk_range_set_value (GTK_RANGE (annot_dialog->opacity), 100);
+       gtk_table_attach (GTK_TABLE (table), annot_dialog->opacity,
+                         1, 2, 2, 3,
+                         GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
+       gtk_widget_show (annot_dialog->opacity);
+
+       hbox = gtk_hbox_new (FALSE, 6);
+
+       label = gtk_label_new (NULL);
+       markup = g_strdup_printf ("<small>%s</small>", _("Transparent"));
+       gtk_label_set_markup (GTK_LABEL (label), markup);
+       g_free (markup);
+       gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+       gtk_widget_show (label);
+
+       label = gtk_label_new (NULL);
+       markup = g_strdup_printf ("<small>%s</small>", _("Opaque"));
+       gtk_label_set_markup (GTK_LABEL (label), markup);
+       g_free (markup);
+       gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+       gtk_widget_show (label);
+
+       gtk_table_attach (GTK_TABLE (table), hbox,
+                         1, 2, 3, 4,
+                         GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
+       gtk_widget_show (hbox);
+
+       label = gtk_label_new (_("Initial window state:"));
+       gtk_misc_set_alignment (GTK_MISC (label), 0., 0.5);
+       gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5,
+                         GTK_FILL, GTK_FILL, 0, 0);
+       gtk_widget_show (label);
+
+       annot_dialog->popup_state = gtk_combo_box_new_text ();
+       gtk_combo_box_append_text (GTK_COMBO_BOX (annot_dialog->popup_state), _("Open"));
+       gtk_combo_box_append_text (GTK_COMBO_BOX (annot_dialog->popup_state), _("Close"));
+       gtk_combo_box_set_active (GTK_COMBO_BOX (annot_dialog->popup_state), 1);
+       gtk_table_attach (GTK_TABLE (table), annot_dialog->popup_state,
+                         1, 2, 4, 5,
+                         GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
+       gtk_widget_show (annot_dialog->popup_state);
+}
+
+static void
+ev_annotation_properties_dialog_class_init (EvAnnotationPropertiesDialogClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->dispose = ev_annotation_properties_dialog_dispose;
+       object_class->constructed = ev_annotation_properties_dialog_constructed;
+       object_class->set_property = ev_annotation_properties_dialog_set_property;
+
+       g_object_class_install_property (object_class,
+                                        PROP_ANNOT_TYPE,
+                                        g_param_spec_enum ("annot-type",
+                                                           "AnnotType",
+                                                           "The type of annotation",
+                                                           EV_TYPE_ANNOTATION_TYPE,
+                                                           EV_ANNOTATION_TYPE_TEXT,
+                                                           G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+GtkWidget *
+ev_annotation_properties_dialog_new (EvAnnotationType annot_type)
+{
+       return GTK_WIDGET (g_object_new (EV_TYPE_ANNOTATION_PROPERTIES_DIALOG,
+                                        "annot-type", annot_type,
+                                        NULL));
+}
+
+GtkWidget *
+ev_annotation_properties_dialog_new_with_annotation (EvAnnotation *annot)
+{
+       EvAnnotationPropertiesDialog *dialog;
+       const gchar                  *label;
+       gdouble                       opacity;
+       gboolean                      is_open;
+       GdkColor                      color;
+
+       dialog = (EvAnnotationPropertiesDialog *)ev_annotation_properties_dialog_new (ev_annotation_get_annotation_type (annot));
+       dialog->annot = g_object_ref (annot);
+
+       label = ev_annotation_markup_get_label (EV_ANNOTATION_MARKUP (annot));
+       if (label)
+               gtk_entry_set_text (GTK_ENTRY (dialog->author), label);
+
+       ev_annotation_get_color (annot, &color);
+       gtk_color_button_set_color (GTK_COLOR_BUTTON (dialog->color), &color);
+
+       opacity = ev_annotation_markup_get_opacity (EV_ANNOTATION_MARKUP (annot));
+       gtk_range_set_value (GTK_RANGE (dialog->opacity), opacity * 100);
+
+       is_open = ev_annotation_markup_get_popup_is_open (EV_ANNOTATION_MARKUP (annot));
+       gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->popup_state),
+                                 is_open ? 0 : 1);
+
+       if (EV_IS_ANNOTATION_TEXT (annot)) {
+               EvAnnotationText *annot_text = EV_ANNOTATION_TEXT (annot);
+
+               gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->icon),
+                                         ev_annotation_text_get_icon (annot_text));
+       }
+
+       return GTK_WIDGET (dialog);
+}
+
+const gchar *
+ev_annotation_properties_dialog_get_author (EvAnnotationPropertiesDialog *dialog)
+{
+       return gtk_entry_get_text (GTK_ENTRY (dialog->author));
+}
+
+void
+ev_annotation_properties_dialog_get_color (EvAnnotationPropertiesDialog *dialog,
+                                          GdkColor                     *color)
+{
+       gtk_color_button_get_color (GTK_COLOR_BUTTON (dialog->color), color);
+}
+
+gdouble
+ev_annotation_properties_dialog_get_opacity (EvAnnotationPropertiesDialog *dialog)
+{
+       return gtk_range_get_value (GTK_RANGE (dialog->opacity)) / 100;
+}
+
+gboolean
+ev_annotation_properties_dialog_get_popup_is_open (EvAnnotationPropertiesDialog *dialog)
+{
+       return gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->popup_state)) == 0;
+}
+
+EvAnnotationTextIcon
+ev_annotation_properties_dialog_get_text_icon (EvAnnotationPropertiesDialog *dialog)
+{
+       return gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->icon));
+}
diff --git a/shell/ev-annotation-properties-dialog.h b/shell/ev-annotation-properties-dialog.h
new file mode 100644 (file)
index 0000000..e21a883
--- /dev/null
@@ -0,0 +1,54 @@
+/* ev-annotation-properties-dialog.h
+ *  this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2010 Carlos Garcia Campos  <carlosgc@gnome.org>
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EV_ANNOTATION_PROPERTIES_DIALOG_H__
+#define __EV_ANNOTATION_PROPERTIES_DIALOG_H__
+
+#include <gtk/gtk.h>
+#include <glib-object.h>
+
+#include <evince-document.h>
+
+G_BEGIN_DECLS
+
+#define EV_TYPE_ANNOTATION_PROPERTIES_DIALOG         (ev_annotation_properties_dialog_get_type())
+#define EV_ANNOTATION_PROPERTIES_DIALOG(o)           (G_TYPE_CHECK_INSTANCE_CAST((o), EV_TYPE_ANNOTATION_PROPERTIES_DIALOG, EvAnnotationPropertiesDialog))
+#define EV_ANNOTATION_PROPERTIES_DIALOG_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), EV_TYPE_ANNOTATION_PROPERTIES_DIALOG, EvAnnotationPropertiesDialogClass))
+#define EV_IS_ANNOTATION_PROPERTIES_DIALOG(o)        (G_TYPE_CHECK_INSTANCE_TYPE((o), EV_TYPE_ANNOTATION_PROPERTIES_DIALOG))
+#define EV_IS_ANNOTATION_PROPERTIES_DIALOG_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE((k), EV_TYPE_ANNOTATION_PROPERTIES_DIALOG))
+#define EV_ANNOTATION_PROPERTIES_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), EV_TYPE_ANNOTATION_PROPERTIES_DIALOG, EvAnnotationPropertiesDialogClass))
+
+typedef struct _EvAnnotationPropertiesDialog      EvAnnotationPropertiesDialog;
+typedef struct _EvAnnotationPropertiesDialogClass EvAnnotationPropertiesDialogClass;
+
+GType                ev_annotation_properties_dialog_get_type            (void) G_GNUC_CONST;
+GtkWidget           *ev_annotation_properties_dialog_new                 (EvAnnotationType              annot_type);
+GtkWidget           *ev_annotation_properties_dialog_new_with_annotation (EvAnnotation                 *annot);
+
+const gchar         *ev_annotation_properties_dialog_get_author          (EvAnnotationPropertiesDialog *dialog);
+void                 ev_annotation_properties_dialog_get_color           (EvAnnotationPropertiesDialog *dialog,
+                                                                         GdkColor                     *color);
+gdouble              ev_annotation_properties_dialog_get_opacity         (EvAnnotationPropertiesDialog *dialog);
+gboolean             ev_annotation_properties_dialog_get_popup_is_open   (EvAnnotationPropertiesDialog *dialog);
+EvAnnotationTextIcon ev_annotation_properties_dialog_get_text_icon       (EvAnnotationPropertiesDialog *dialog);
+
+G_END_DECLS
+
+#endif /* __EV_ANNOTATION_PROPERTIES_DIALOG_H__ */
index b1f084821851b12265fc9b723b00f1d7cedfbf05..ec544fa57368ea62ae80b958d25b48d66df791ed 100644 (file)
@@ -43,18 +43,25 @@ enum {
 
 enum {
        ANNOT_ACTIVATED,
+       BEGIN_ANNOT_ADD,
+       ANNOT_ADD_CANCELLED,
        N_SIGNALS
 };
 
 struct _EvSidebarAnnotationsPrivate {
-       GtkWidget  *notebook;
-       GtkWidget  *tree_view;
+       EvDocument  *document;
 
-       EvJob      *job;
-       guint       selection_changed_id;
+       GtkWidget   *notebook;
+       GtkWidget   *tree_view;
+       GtkWidget   *palette;
+       GtkToolItem *annot_text_item;
+
+       EvJob       *job;
+       guint        selection_changed_id;
 };
 
 static void ev_sidebar_annotations_page_iface_init (EvSidebarPageInterface *iface);
+static void ev_sidebar_annotations_load            (EvSidebarAnnotations   *sidebar_annots);
 
 static guint signals[N_SIGNALS];
 
@@ -68,6 +75,20 @@ G_DEFINE_TYPE_EXTENDED (EvSidebarAnnotations,
 #define EV_SIDEBAR_ANNOTATIONS_GET_PRIVATE(object) \
        (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR_ANNOTATIONS, EvSidebarAnnotationsPrivate))
 
+static void
+ev_sidebar_annotations_dispose (GObject *object)
+{
+       EvSidebarAnnotations *sidebar_annots = EV_SIDEBAR_ANNOTATIONS (object);
+       EvSidebarAnnotationsPrivate *priv = sidebar_annots->priv;
+
+       if (priv->document) {
+               g_object_unref (priv->document);
+               priv->document = NULL;
+       }
+
+       G_OBJECT_CLASS (ev_sidebar_annotations_parent_class)->dispose (object);
+}
+
 static GtkTreeModel *
 ev_sidebar_annotations_create_simple_model (const gchar *message)
 {
@@ -100,6 +121,7 @@ ev_sidebar_annotations_add_annots_list (EvSidebarAnnotations *ev_annots)
        GtkCellRenderer   *renderer;
        GtkTreeViewColumn *column;
        GtkTreeSelection  *selection;
+       GtkWidget         *label;
 
        swindow = gtk_scrolled_window_new (NULL, NULL);
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
@@ -136,8 +158,71 @@ ev_sidebar_annotations_add_annots_list (EvSidebarAnnotations *ev_annots)
        gtk_container_add (GTK_CONTAINER (swindow), ev_annots->priv->tree_view);
        gtk_widget_show (ev_annots->priv->tree_view);
 
+       label = gtk_label_new (_("List"));
+       gtk_notebook_append_page (GTK_NOTEBOOK (ev_annots->priv->notebook),
+                                 swindow, label);
+       gtk_widget_show (label);
+
+       gtk_widget_show (swindow);
+}
+
+static void
+ev_sidebar_annotations_text_annot_button_toggled (GtkToggleToolButton  *toolbutton,
+                                                 EvSidebarAnnotations *sidebar_annots)
+{
+       EvAnnotationType annot_type;
+
+       if (!gtk_toggle_tool_button_get_active (toolbutton)) {
+               g_signal_emit (sidebar_annots, signals[ANNOT_ADD_CANCELLED], 0, NULL);
+               return;
+       }
+
+       if (GTK_TOOL_ITEM (toolbutton) == sidebar_annots->priv->annot_text_item)
+               annot_type = EV_ANNOTATION_TYPE_TEXT;
+       else
+               annot_type = EV_ANNOTATION_TYPE_UNKNOWN;
+
+       g_signal_emit (sidebar_annots, signals[BEGIN_ANNOT_ADD], 0, annot_type);
+}
+
+static void
+ev_sidebar_annotations_add_annots_palette (EvSidebarAnnotations *ev_annots)
+{
+       GtkWidget   *swindow;
+       GtkWidget   *group;
+       GtkToolItem *item;
+       GtkWidget   *label;
+
+       swindow = gtk_scrolled_window_new (NULL, NULL);
+       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
+                                       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+       gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow),
+                                            GTK_SHADOW_IN);
+
+       ev_annots->priv->palette = gtk_tool_palette_new ();
+       group = gtk_tool_item_group_new (_("Annotations"));
+       gtk_container_add (GTK_CONTAINER (ev_annots->priv->palette), group);
+
+       /* FIXME: use a better icon than EDIT */
+       item = gtk_toggle_tool_button_new ();
+       gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), GTK_STOCK_EDIT);
+       gtk_tool_button_set_label (GTK_TOOL_BUTTON (item), _("Text"));
+       gtk_widget_set_tooltip_text (GTK_WIDGET (item), _("Add text annotation"));
+       ev_annots->priv->annot_text_item = item;
+       g_signal_connect (item, "toggled",
+                         G_CALLBACK (ev_sidebar_annotations_text_annot_button_toggled),
+                         ev_annots);
+       gtk_tool_item_group_insert (GTK_TOOL_ITEM_GROUP (group), item, -1);
+       gtk_widget_show (GTK_WIDGET (item));
+
+       gtk_container_add (GTK_CONTAINER (swindow), ev_annots->priv->palette);
+       gtk_widget_show (ev_annots->priv->palette);
+
+       label = gtk_label_new (_("Add"));
        gtk_notebook_append_page (GTK_NOTEBOOK (ev_annots->priv->notebook),
-                                 swindow, NULL);
+                                 swindow, label);
+       gtk_widget_show (label);
+
        gtk_widget_show (swindow);
 }
 
@@ -150,6 +235,7 @@ ev_sidebar_annotations_init (EvSidebarAnnotations *ev_annots)
        gtk_notebook_set_show_tabs (GTK_NOTEBOOK (ev_annots->priv->notebook), FALSE);
        gtk_notebook_set_show_border (GTK_NOTEBOOK (ev_annots->priv->notebook), FALSE);
        ev_sidebar_annotations_add_annots_list (ev_annots);
+       ev_sidebar_annotations_add_annots_palette (ev_annots);
        gtk_container_add (GTK_CONTAINER (ev_annots), ev_annots->priv->notebook);
        gtk_widget_show (ev_annots->priv->notebook);
 }
@@ -180,6 +266,7 @@ ev_sidebar_annotations_class_init (EvSidebarAnnotationsClass *klass)
        GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
 
        g_object_class->get_property = ev_sidebar_annotations_get_property;
+       g_object_class->dispose = ev_sidebar_annotations_dispose;
 
        g_type_class_add_private (g_object_class, sizeof (EvSidebarAnnotationsPrivate));
 
@@ -194,6 +281,24 @@ ev_sidebar_annotations_class_init (EvSidebarAnnotationsClass *klass)
                              g_cclosure_marshal_VOID__POINTER,
                              G_TYPE_NONE, 1,
                              G_TYPE_POINTER);
+       signals[BEGIN_ANNOT_ADD] =
+               g_signal_new ("begin-annot-add",
+                             G_TYPE_FROM_CLASS (g_object_class),
+                             G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                             G_STRUCT_OFFSET (EvSidebarAnnotationsClass, begin_annot_add),
+                             NULL, NULL,
+                             g_cclosure_marshal_VOID__ENUM,
+                             G_TYPE_NONE, 1,
+                             EV_TYPE_ANNOTATION_TYPE);
+       signals[ANNOT_ADD_CANCELLED] =
+               g_signal_new ("annot-add-cancelled",
+                             G_TYPE_FROM_CLASS (g_object_class),
+                             G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                             G_STRUCT_OFFSET (EvSidebarAnnotationsClass, annot_add_cancelled),
+                             NULL, NULL,
+                             g_cclosure_marshal_VOID__VOID,
+                             G_TYPE_NONE, 0,
+                             G_TYPE_NONE);
 }
 
 GtkWidget *
@@ -202,6 +307,26 @@ ev_sidebar_annotations_new (void)
        return GTK_WIDGET (g_object_new (EV_TYPE_SIDEBAR_ANNOTATIONS, NULL));
 }
 
+void
+ev_sidebar_annotations_annot_added (EvSidebarAnnotations *sidebar_annots,
+                                   EvAnnotation         *annot)
+{
+       GtkToggleToolButton *toolbutton;
+
+       if (EV_IS_ANNOTATION_TEXT (annot)) {
+               toolbutton = GTK_TOGGLE_TOOL_BUTTON (sidebar_annots->priv->annot_text_item);
+               g_signal_handlers_block_by_func (toolbutton,
+                                                ev_sidebar_annotations_text_annot_button_toggled,
+                                                sidebar_annots);
+               gtk_toggle_tool_button_set_active (toolbutton, FALSE);
+               g_signal_handlers_unblock_by_func (toolbutton,
+                                                  ev_sidebar_annotations_text_annot_button_toggled,
+                                                  sidebar_annots);
+       }
+
+       ev_sidebar_annotations_load (sidebar_annots);
+}
+
 static void
 selection_changed_cb (GtkTreeSelection     *selection,
                      EvSidebarAnnotations *sidebar_annots)
@@ -278,7 +403,8 @@ job_finished_callback (EvJobAnnots          *job,
 
                for (ll = ev_mapping_list_get_list (mapping_list); ll; ll = g_list_next (ll)) {
                        EvAnnotation *annot;
-                       gchar        *label;
+                       const gchar  *label;
+                       const gchar  *modified;
                        gchar        *markup;
                        GtkTreeIter   child_iter;
                        GdkPixbuf    *pixbuf = NULL;
@@ -288,13 +414,13 @@ job_finished_callback (EvJobAnnots          *job,
                                continue;
 
                        label = ev_annotation_markup_get_label (EV_ANNOTATION_MARKUP (annot));
-                       if (annot->modified) {
+                       modified = ev_annotation_get_modified (annot);
+                       if (modified) {
                                markup = g_strdup_printf ("<span weight=\"bold\">%s</span>\n%s",
-                                                         label, annot->modified);
+                                                         label, modified);
                        } else {
                                markup = g_strdup_printf ("<span weight=\"bold\">%s</span>", label);
                        }
-                       g_free (label);
 
                        if (EV_IS_ANNOTATION_TEXT (annot)) {
                                if (!text_icon) {
@@ -342,18 +468,11 @@ job_finished_callback (EvJobAnnots          *job,
        priv->job = NULL;
 }
 
-
 static void
-ev_sidebar_annotations_document_changed_cb (EvDocumentModel      *model,
-                                           GParamSpec           *pspec,
-                                           EvSidebarAnnotations *sidebar_annots)
+ev_sidebar_annotations_load (EvSidebarAnnotations *sidebar_annots)
 {
-       EvDocument *document = ev_document_model_get_document (model);
        EvSidebarAnnotationsPrivate *priv = sidebar_annots->priv;
 
-       if (!EV_IS_DOCUMENT_ANNOTATIONS (document))
-               return;
-
        if (priv->job) {
                g_signal_handlers_disconnect_by_func (priv->job,
                                                      job_finished_callback,
@@ -361,7 +480,7 @@ ev_sidebar_annotations_document_changed_cb (EvDocumentModel      *model,
                g_object_unref (priv->job);
        }
 
-       priv->job = ev_job_annots_new (document);
+       priv->job = ev_job_annots_new (priv->document);
        g_signal_connect (priv->job, "finished",
                          G_CALLBACK (job_finished_callback),
                          sidebar_annots);
@@ -369,6 +488,28 @@ ev_sidebar_annotations_document_changed_cb (EvDocumentModel      *model,
        ev_job_scheduler_push_job (priv->job, EV_JOB_PRIORITY_NONE);
 }
 
+static void
+ev_sidebar_annotations_document_changed_cb (EvDocumentModel      *model,
+                                           GParamSpec           *pspec,
+                                           EvSidebarAnnotations *sidebar_annots)
+{
+       EvDocument *document = ev_document_model_get_document (model);
+       EvSidebarAnnotationsPrivate *priv = sidebar_annots->priv;
+       gboolean show_tabs;
+
+       if (!EV_IS_DOCUMENT_ANNOTATIONS (document))
+               return;
+
+       if (priv->document)
+               g_object_unref (priv->document);
+       priv->document = g_object_ref (document);
+
+       show_tabs = ev_document_annotations_can_add_annotation (EV_DOCUMENT_ANNOTATIONS (document));
+       gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), show_tabs);
+
+       ev_sidebar_annotations_load (sidebar_annots);
+}
+
 /* EvSidebarPageIface */
 static void
 ev_sidebar_annotations_set_model (EvSidebarPage   *sidebar_page,
index 8762d78744951ff9dd10be76643328126d7f4f2b..544fc2443644a0b145fa99fabdd316731cc9f1c4 100644 (file)
@@ -46,13 +46,17 @@ struct _EvSidebarAnnotations {
 struct _EvSidebarAnnotationsClass {
        GtkVBoxClass base_class;
 
-       void    (* annot_activated) (EvSidebarAnnotations *sidebar_annots,
-                                    EvMapping            *mapping);
+       void    (* annot_activated)     (EvSidebarAnnotations *sidebar_annots,
+                                        EvMapping            *mapping);
+       void    (* begin_annot_add)     (EvSidebarAnnotations *sidebar_annots,
+                                        EvAnnotationType      annot_type);
+       void    (* annot_add_cancelled) (EvSidebarAnnotations *sidebar_annots);
 };
 
-GType      ev_sidebar_annotations_get_type (void) G_GNUC_CONST;
-GtkWidget *ev_sidebar_annotations_new      (void);
-
+GType      ev_sidebar_annotations_get_type    (void) G_GNUC_CONST;
+GtkWidget *ev_sidebar_annotations_new         (void);
+void       ev_sidebar_annotations_annot_added (EvSidebarAnnotations *sidebar_annots,
+                                              EvAnnotation         *annot);
 G_END_DECLS
 
 #endif /* __EV_SIDEBAR_ANNOTATIONS_H__ */
index c7e9c6d8adbb37fb02fee569cefd5310d49df161..ece97c7415d93068e64a3056a976d56a43001fa1 100644 (file)
@@ -95,6 +95,7 @@
 #include "ev-window-title.h"
 #include "ev-print-operation.h"
 #include "ev-progress-message-area.h"
+#include "ev-annotation-properties-dialog.h"
 
 #ifdef ENABLE_DBUS
 #include "ev-media-player-keys.h"
@@ -172,9 +173,10 @@ struct _EvWindowPrivate {
        GtkWidget *fullscreen_toolbar;
 
        /* Popup view */
-       GtkWidget *view_popup;
-       EvLink    *link;
-       EvImage   *image;
+       GtkWidget    *view_popup;
+       EvLink       *link;
+       EvImage      *image;
+       EvAnnotation *annot;
 
        /* Popup attachment */
        GtkWidget    *attachment_popup;
@@ -317,6 +319,8 @@ static void     ev_view_popup_cmd_save_image_as         (GtkAction        *actio
                                                         EvWindow         *window);
 static void     ev_view_popup_cmd_copy_image            (GtkAction        *action,
                                                         EvWindow         *window);
+static void     ev_view_popup_cmd_annot_properties      (GtkAction        *action,
+                                                        EvWindow         *window);
 static void    ev_attachment_popup_cmd_open_attachment (GtkAction        *action,
                                                         EvWindow         *window);
 static void    ev_attachment_popup_cmd_save_attachment_as (GtkAction     *action, 
@@ -3307,6 +3311,8 @@ ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window)
                ev_document_model_set_page (ev_window->priv->model, current_page);
        }
 
+       /* TODO: warn about form fields, and annots not saved */
+
        n_print_jobs = ev_window->priv->print_queue ?
                g_queue_get_length (ev_window->priv->print_queue) : 0;
        
@@ -4536,9 +4542,18 @@ view_menu_annot_popup (EvWindow     *ev_window,
        GtkAction *action;
        gboolean   show_annot = FALSE;
 
+       if (ev_window->priv->annot)
+               g_object_unref (ev_window->priv->annot);
+       ev_window->priv->annot = (annot) ? g_object_ref (annot) : NULL;
+
+       action = gtk_action_group_get_action (ev_window->priv->view_popup_action_group,
+                                             "AnnotProperties");
+       gtk_action_set_visible (action, (annot != NULL && EV_IS_ANNOTATION_MARKUP (annot)));
+
        if (annot && EV_IS_ANNOTATION_ATTACHMENT (annot)) {
-               EvAttachment *attachment = EV_ANNOTATION_ATTACHMENT (annot)->attachment;
+               EvAttachment *attachment;
 
+               attachment = ev_annotation_attachment_get_attachment (EV_ANNOTATION_ATTACHMENT (annot));
                if (attachment) {
                        show_annot = TRUE;
                        if (ev_window->priv->attach_list) {
@@ -5029,6 +5044,11 @@ ev_window_dispose (GObject *object)
                priv->image = NULL;
        }
 
+       if (priv->annot) {
+               g_object_unref (priv->annot);
+               priv->annot = NULL;
+       }
+
        if (priv->attach_list) {
                g_list_foreach (priv->attach_list,
                                (GFunc) g_object_unref,
@@ -5338,6 +5358,8 @@ static const GtkActionEntry view_popup_entries [] = {
          NULL, G_CALLBACK (ev_view_popup_cmd_save_image_as) },
        { "CopyImage", NULL, N_("Copy _Image"), NULL,
          NULL, G_CALLBACK (ev_view_popup_cmd_copy_image) },
+       { "AnnotProperties", NULL, N_("Annotation Properties…"), NULL,
+         NULL, G_CALLBACK (ev_view_popup_cmd_annot_properties) }
 };
 
 static const GtkActionEntry attachment_popup_entries [] = {
@@ -5383,6 +5405,30 @@ sidebar_annots_annot_activated_cb (EvSidebarAnnotations *sidebar_annots,
        ev_view_focus_annotation (EV_VIEW (window->priv->view), annot_mapping);
 }
 
+static void
+sidebar_annots_begin_annot_add (EvSidebarAnnotations *sidebar_annots,
+                               EvAnnotationType      annot_type,
+                               EvWindow             *window)
+{
+       ev_view_begin_add_annotation (EV_VIEW (window->priv->view), annot_type);
+}
+
+static void
+view_annot_added (EvView       *view,
+                 EvAnnotation *annot,
+                 EvWindow     *window)
+{
+       ev_sidebar_annotations_annot_added (EV_SIDEBAR_ANNOTATIONS (window->priv->sidebar_annots),
+                                           annot);
+}
+
+static void
+sidebar_annots_annot_add_cancelled (EvSidebarAnnotations *sidebar_annots,
+                                   EvWindow             *window)
+{
+       ev_view_cancel_add_annotation (EV_VIEW (window->priv->view));
+}
+
 static void
 register_custom_actions (EvWindow *window, GtkActionGroup *group)
 {
@@ -5994,6 +6040,67 @@ ev_view_popup_cmd_copy_image (GtkAction *action, EvWindow *window)
        g_object_unref (pixbuf);
 }
 
+static void
+ev_view_popup_cmd_annot_properties (GtkAction *action,
+                                   EvWindow  *window)
+{
+       const gchar                  *author;
+       GdkColor                      color;
+       gdouble                       opacity;
+       gboolean                      popup_is_open;
+       EvAnnotationPropertiesDialog *dialog;
+       EvAnnotation                 *annot = window->priv->annot;
+       EvAnnotationsSaveMask         mask = EV_ANNOTATIONS_SAVE_NONE;
+
+       if (!annot)
+               return;
+
+       dialog = EV_ANNOTATION_PROPERTIES_DIALOG (ev_annotation_properties_dialog_new_with_annotation (window->priv->annot));
+       if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_APPLY) {
+               gtk_widget_destroy (GTK_WIDGET (dialog));
+
+               return;
+       }
+
+       /* Set annotations changes */
+       author = ev_annotation_properties_dialog_get_author (dialog);
+       if (ev_annotation_markup_set_label (EV_ANNOTATION_MARKUP (annot), author))
+               mask |= EV_ANNOTATIONS_SAVE_LABEL;
+
+       ev_annotation_properties_dialog_get_color (dialog, &color);
+       if (ev_annotation_set_color (annot, &color))
+               mask |= EV_ANNOTATIONS_SAVE_COLOR;
+
+       opacity = ev_annotation_properties_dialog_get_opacity (dialog);
+       if (ev_annotation_markup_set_opacity (EV_ANNOTATION_MARKUP (annot), opacity))
+               mask |= EV_ANNOTATIONS_SAVE_OPACITY;
+
+       popup_is_open = ev_annotation_properties_dialog_get_popup_is_open (dialog);
+       if (ev_annotation_markup_set_popup_is_open (EV_ANNOTATION_MARKUP (annot), popup_is_open))
+               mask |= EV_ANNOTATIONS_SAVE_POPUP_IS_OPEN;
+
+       if (EV_IS_ANNOTATION_TEXT (annot)) {
+               EvAnnotationTextIcon icon;
+
+               icon = ev_annotation_properties_dialog_get_text_icon (dialog);
+               if (ev_annotation_text_set_icon (EV_ANNOTATION_TEXT (annot), icon))
+                       mask |= EV_ANNOTATIONS_SAVE_TEXT_ICON;
+       }
+
+       if (mask != EV_ANNOTATIONS_SAVE_NONE) {
+               ev_document_doc_mutex_lock ();
+               ev_document_annotations_save_annotation (EV_DOCUMENT_ANNOTATIONS (window->priv->document),
+                                                        window->priv->annot,
+                                                        mask);
+               ev_document_doc_mutex_unlock ();
+
+               /* FIXME: update annot region only */
+               ev_view_reload (EV_VIEW (window->priv->view));
+       }
+
+       gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
 static void
 ev_attachment_popup_cmd_open_attachment (GtkAction *action, EvWindow *window)
 {
@@ -6553,6 +6660,14 @@ ev_window_init (EvWindow *ev_window)
                          "annot_activated",
                          G_CALLBACK (sidebar_annots_annot_activated_cb),
                          ev_window);
+       g_signal_connect (sidebar_widget,
+                         "begin_annot_add",
+                         G_CALLBACK (sidebar_annots_begin_annot_add),
+                         ev_window);
+       g_signal_connect (sidebar_widget,
+                         "annot_add_cancelled",
+                         G_CALLBACK (sidebar_annots_annot_add_cancelled),
+                         ev_window);
        gtk_widget_show (sidebar_widget);
        ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar),
                             sidebar_widget);
@@ -6598,6 +6713,9 @@ ev_window_init (EvWindow *ev_window)
        g_signal_connect_object (ev_window->priv->view, "selection-changed",
                                 G_CALLBACK (view_selection_changed_cb),
                                 ev_window, 0);
+       g_signal_connect_object (ev_window->priv->view, "annot-added",
+                                G_CALLBACK (view_annot_added),
+                                ev_window, 0);
 #ifdef ENABLE_DBUS
        g_signal_connect_swapped (ev_window->priv->view, "sync-source",
                                  G_CALLBACK (ev_window_sync_source),