[evince] Preliminary support for adding new annotations



commit 584f014b63c56fe3770cba9682fc21c31e09a2e9
Author: Carlos Garcia Campos <carlosgc gnome org>
Date:   Tue Jul 20 17:01:56 2010 +0200

    Preliminary support for adding new annotations
    
    At the moment only Text annotations can be added. See bug #168304.

 backend/pdf/ev-poppler.cc               |  276 +++++++++++-
 configure.ac                            |    1 +
 data/evince-ui.xml                      |    2 +
 libdocument/ev-annotation.c             |  728 +++++++++++++++++++++++++++----
 libdocument/ev-annotation.h             |  140 +++---
 libdocument/ev-document-annotations.c   |   27 +-
 libdocument/ev-document-annotations.h   |   52 ++-
 libview/ev-annotation-window.c          |  111 +++--
 libview/ev-annotation-window.h          |   25 +-
 libview/ev-view-cursor.c                |    3 +
 libview/ev-view-cursor.h                |    3 +-
 libview/ev-view-private.h               |    4 +
 libview/ev-view.c                       |  284 ++++++++++---
 libview/ev-view.h                       |    9 +-
 po/POTFILES.in                          |    1 +
 shell/Makefile.am                       |    2 +
 shell/ev-annotation-properties-dialog.c |  327 ++++++++++++++
 shell/ev-annotation-properties-dialog.h |   54 +++
 shell/ev-sidebar-annotations.c          |  177 +++++++-
 shell/ev-sidebar-annotations.h          |   14 +-
 shell/ev-window.c                       |  126 +++++-
 21 files changed, 2030 insertions(+), 336 deletions(-)
---
diff --git a/backend/pdf/ev-poppler.cc b/backend/pdf/ev-poppler.cc
index f457d64..5943a6d 100644
--- a/backend/pdf/ev-poppler.cc
+++ b/backend/pdf/ev-poppler.cc
@@ -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 */
diff --git a/configure.ac b/configure.ac
index 6e9d965..3c015e1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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
diff --git a/data/evince-ui.xml b/data/evince-ui.xml
index 962e8b2..0d15aab 100644
--- a/data/evince-ui.xml
+++ b/data/evince-ui.xml
@@ -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">
diff --git a/libdocument/ev-annotation.c b/libdocument/ev-annotation.c
index 21ffc0a..f7acc0b 100644
--- a/libdocument/ev-annotation.c
+++ b/libdocument/ev-annotation.c
@@ -22,19 +22,86 @@
 #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;
 }
diff --git a/libdocument/ev-annotation.h b/libdocument/ev-annotation.h
index de8736e..554523c 100644
--- a/libdocument/ev-annotation.h
+++ b/libdocument/ev-annotation.h
@@ -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
 
diff --git a/libdocument/ev-document-annotations.c b/libdocument/ev-document-annotations.c
index 6ccdd57..4bc039e 100644
--- a/libdocument/ev-document-annotations.c
+++ b/libdocument/ev-document-annotations.c
@@ -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;
 }
diff --git a/libdocument/ev-document-annotations.h b/libdocument/ev-document-annotations.h
index 6da49d9..8eb2c7c 100644
--- a/libdocument/ev-document-annotations.h
+++ b/libdocument/ev-document-annotations.h
@@ -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
 
diff --git a/libview/ev-annotation-window.c b/libview/ev-annotation-window.c
index 559b879..749d1a0 100644
--- a/libview/ev-annotation-window.c
+++ b/libview/ev-annotation-window.c
@@ -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
@@ -178,21 +163,38 @@ ev_annotation_window_set_color (EvAnnotationWindow *window,
 }
 
 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);
 }
diff --git a/libview/ev-annotation-window.h b/libview/ev-annotation-window.h
index 697574f..b9ba4f1 100644
--- a/libview/ev-annotation-window.h
+++ b/libview/ev-annotation-window.h
@@ -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
 
diff --git a/libview/ev-view-cursor.c b/libview/ev-view-cursor.c
index 6974d3f..67cacd7 100644
--- a/libview/ev-view-cursor.c
+++ b/libview/ev-view-cursor.c
@@ -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;
diff --git a/libview/ev-view-cursor.h b/libview/ev-view-cursor.h
index 012d5a4..220441c 100644
--- a/libview/ev-view-cursor.h
+++ b/libview/ev-view-cursor.h
@@ -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,
diff --git a/libview/ev-view-private.h b/libview/ev-view-private.h
index 57eea30..a365507 100644
--- a/libview/ev-view-private.h
+++ b/libview/ev-view-private.h
@@ -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,
diff --git a/libview/ev-view.c b/libview/ev-view.c
index eee1b56..471c66c 100644
--- a/libview/ev-view.c
+++ b/libview/ev-view.c
@@ -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);
 		}
 	}
 }
@@ -2708,6 +2728,23 @@ ev_view_get_annotation_at_location (EvView  *view,
 }
 
 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,
 			   gdouble       x,
@@ -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);
 
diff --git a/libview/ev-view.h b/libview/ev-view.h
index 712d554..06f5b30 100644
--- a/libview/ev-view.h
+++ b/libview/ev-view.h
@@ -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
 
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b2eac5e..c93d309 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -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
diff --git a/shell/Makefile.am b/shell/Makefile.am
index 523d299..8336230 100644
--- a/shell/Makefile.am
+++ b/shell/Makefile.am
@@ -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
index 0000000..0f5c6e1
--- /dev/null
+++ b/shell/ev-annotation-properties-dialog.c
@@ -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
index 0000000..e21a883
--- /dev/null
+++ b/shell/ev-annotation-properties-dialog.h
@@ -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__ */
diff --git a/shell/ev-sidebar-annotations.c b/shell/ev-sidebar-annotations.c
index b1f0848..ec544fa 100644
--- a/shell/ev-sidebar-annotations.c
+++ b/shell/ev-sidebar-annotations.c
@@ -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,
diff --git a/shell/ev-sidebar-annotations.h b/shell/ev-sidebar-annotations.h
index 8762d78..544fc24 100644
--- a/shell/ev-sidebar-annotations.h
+++ b/shell/ev-sidebar-annotations.h
@@ -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__ */
diff --git a/shell/ev-window.c b/shell/ev-window.c
index c7e9c6d..ece97c7 100644
--- a/shell/ev-window.c
+++ b/shell/ev-window.c
@@ -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 [] = {
@@ -5384,6 +5406,30 @@ sidebar_annots_annot_activated_cb (EvSidebarAnnotations *sidebar_annots,
 }
 
 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)
 {
 	GtkAction *action;
@@ -5995,6 +6041,67 @@ ev_view_popup_cmd_copy_image (GtkAction *action, EvWindow *window)
 }
 
 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)
 {
 	GList     *l;
@@ -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),



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]