[evince] Remove EvPageCache and use EvDocumentModel instead



commit 34148304a0237fd9fd7c4ea05ca2e053d9ddd3ff
Author: Carlos Garcia Campos <carlosgc gnome org>
Date:   Sun Aug 23 18:02:41 2009 +0200

    Remove EvPageCache and use EvDocumentModel instead
    
    EvView is now another view for the common model EvDocumentModel. Now
    it's possible to have several windows for the same document without the
    symlink hack. Every window has its own model, while the document object
    is shared.

 evince-view.h                   |    2 +-
 libmisc/Makefile.am             |    1 +
 libmisc/ev-page-action-widget.c |   93 +++++----
 libmisc/ev-page-action-widget.h |   12 +-
 libmisc/ev-page-action.c        |  100 ++++------
 libmisc/ev-page-action.h        |   14 +-
 libview/Makefile.am             |    4 +-
 libview/ev-document-model.c     |  416 +++++++++++++++++++++++++++++++++++++++
 libview/ev-document-model.h     |   75 +++++++
 libview/ev-page-cache.c         |  168 ----------------
 libview/ev-page-cache.h         |   51 -----
 libview/ev-pixbuf-cache.c       |   25 +--
 libview/ev-view-private.h       |    7 +-
 libview/ev-view.c               |  301 +++++++++++++++-------------
 libview/ev-view.h               |   16 +-
 previewer/ev-previewer-window.c |  176 +++++++++++------
 previewer/ev-previewer-window.h |    5 +-
 previewer/ev-previewer.c        |   28 ++--
 shell/ev-print-operation.c      |    1 -
 shell/ev-properties-dialog.c    |    1 -
 shell/ev-sidebar-attachments.c  |   25 ++-
 shell/ev-sidebar-layers.c       |   28 ++-
 shell/ev-sidebar-links.c        |  128 ++++++++-----
 shell/ev-sidebar-page.c         |   16 +-
 shell/ev-sidebar-page.h         |   13 +-
 shell/ev-sidebar-thumbnails.c   |  120 +++++++-----
 shell/ev-sidebar-thumbnails.h   |    8 +-
 shell/ev-sidebar.c              |   51 +++--
 shell/ev-sidebar.h              |   18 +-
 shell/ev-window.c               |  373 +++++++++++++++++++----------------
 shell/ev-window.h               |    1 -
 31 files changed, 1358 insertions(+), 919 deletions(-)
---
diff --git a/evince-view.h b/evince-view.h
index ed88853..4c83d47 100644
--- a/evince-view.h
+++ b/evince-view.h
@@ -23,7 +23,7 @@
 
 #include <libview/ev-job-scheduler.h>
 #include <libview/ev-jobs.h>
-#include <libview/ev-page-cache.h>
+#include <libview/ev-document-model.h>
 #include <libview/ev-view.h>
 #include <libview/ev-view-type-builtins.h>
 #include <libview/ev-stock-icons.h>
diff --git a/libmisc/Makefile.am b/libmisc/Makefile.am
index 290f574..38a43fa 100644
--- a/libmisc/Makefile.am
+++ b/libmisc/Makefile.am
@@ -10,6 +10,7 @@ libevmisc_la_CFLAGS =	\
 	-DDATADIR=\"$(pkgdatadir)\"	\
 	-I$(top_srcdir)			\
 	-I$(top_srcdir)/libdocument	\
+	-I$(top_srcdir)/libview		\
 	$(SHELL_CORE_CFLAGS)    	\
 	$(WARNING_CFLAGS)       	\
 	$(DISABLE_DEPRECATED)
diff --git a/libmisc/ev-page-action-widget.c b/libmisc/ev-page-action-widget.c
index 249775c..2b29e78 100644
--- a/libmisc/ev-page-action-widget.c
+++ b/libmisc/ev-page-action-widget.c
@@ -43,7 +43,7 @@ struct _EvPageActionWidget
 	GtkToolItem parent;
 
 	EvDocument *document;
-	EvPageCache *page_cache;
+	EvDocumentModel *doc_model;
 
 	GtkWidget *entry;
 	GtkWidget *label;
@@ -74,9 +74,8 @@ update_pages_label (EvPageActionWidget *action_widget,
 }
 
 static void
-page_changed_cb (EvPageCache        *page_cache,
-		 gint                page,
-		 EvPageActionWidget *action_widget)
+ev_page_action_widget_set_current_page (EvPageActionWidget *action_widget,
+					gint                page)
 {
 	if (page >= 0) {
 		gchar *page_label;
@@ -97,19 +96,28 @@ page_changed_cb (EvPageCache        *page_cache,
 	update_pages_label (action_widget, page);
 }
 
+static void
+page_changed_cb (EvDocumentModel    *model,
+		 gint                old_page,
+		 gint                new_page,
+		 EvPageActionWidget *action_widget)
+{
+	ev_page_action_widget_set_current_page (action_widget, new_page);
+}
+
 static gboolean
 page_scroll_cb (EvPageActionWidget *action_widget, GdkEventScroll *event)
 {
-	EvPageCache *page_cache = action_widget->page_cache;
+	EvDocumentModel *model = action_widget->doc_model;
 	gint pageno;
 
-	pageno = ev_page_cache_get_current_page (page_cache);
+	pageno = ev_document_model_get_page (model);
 	if ((event->direction == GDK_SCROLL_DOWN) &&
 	    (pageno < ev_document_get_n_pages (action_widget->document) - 1))
 		pageno++;
 	if ((event->direction == GDK_SCROLL_UP) && (pageno > 0))
 		pageno--;
-	ev_page_cache_set_current_page (page_cache, pageno);
+	ev_document_model_set_page (model, pageno);
 
 	return TRUE;
 }
@@ -117,7 +125,7 @@ page_scroll_cb (EvPageActionWidget *action_widget, GdkEventScroll *event)
 static void
 activate_cb (EvPageActionWidget *action_widget)
 {
-	EvPageCache *page_cache;
+	EvDocumentModel *model;
 	const char *text;
 	gchar *page_label;
 	EvLinkDest *link_dest;
@@ -139,9 +147,9 @@ activate_cb (EvPageActionWidget *action_widget)
 
 	/* rest the entry to the current page if we were unable to
 	 * change it */
-	page_cache = action_widget->page_cache;
+	model = action_widget->doc_model;
 	page_label = ev_document_get_page_label (action_widget->document,
-						 ev_page_cache_get_current_page (page_cache));
+						 ev_document_model_get_page (model));
 	gtk_entry_set_text (GTK_ENTRY (action_widget->entry), page_label);
 	gtk_editable_set_position (GTK_EDITABLE (action_widget->entry), -1);
 	g_free (page_label);
@@ -187,38 +195,48 @@ ev_page_action_widget_init (EvPageActionWidget *action_widget)
 	gtk_widget_show (GTK_WIDGET (action_widget));
 }
 
-void
-ev_page_action_widget_set_document (EvPageActionWidget *action_widget,
-				    EvDocument         *document)
+static void
+ev_page_action_widget_document_changed_cb (EvDocumentModel    *model,
+					   GParamSpec         *pspec,
+					   EvPageActionWidget *action_widget)
 {
-	EvPageCache *page_cache = ev_page_cache_get (document);
+	EvDocument *document = ev_document_model_get_document (model);
 
 	g_object_ref (document);
 	if (action_widget->document)
 		g_object_unref (action_widget->document);
 	action_widget->document = document;
 
-	if (action_widget->page_cache != NULL) {
-		if (action_widget->signal_id > 0) {
-			g_signal_handler_disconnect (action_widget->page_cache,
-						     action_widget->signal_id);
-			action_widget->signal_id = 0;
-		}
-		g_object_remove_weak_pointer (G_OBJECT (action_widget->page_cache),
-					      (gpointer)&action_widget->page_cache);
-		action_widget->page_cache = NULL;
+	if (action_widget->signal_id > 0) {
+		g_signal_handler_disconnect (action_widget->doc_model,
+					     action_widget->signal_id);
+		action_widget->signal_id = 0;
 	}
-
-	action_widget->page_cache = page_cache;
-	g_object_add_weak_pointer (G_OBJECT (page_cache),
-				   (gpointer)&action_widget->page_cache);
 	action_widget->signal_id =
-		g_signal_connect_object (page_cache, "page-changed",
+		g_signal_connect_object (action_widget->doc_model,
+					 "page-changed",
 					 G_CALLBACK (page_changed_cb),
 					 action_widget, 0);
-	page_changed_cb (page_cache,
-			 ev_page_cache_get_current_page (page_cache),
-			 action_widget);
+
+	ev_page_action_widget_set_current_page (action_widget,
+						ev_document_model_get_page (model));
+}
+
+void
+ev_page_action_widget_set_model (EvPageActionWidget *action_widget,
+				 EvDocumentModel    *model)
+{
+	if (action_widget->doc_model) {
+		g_object_remove_weak_pointer (G_OBJECT (action_widget->doc_model),
+					      (gpointer)&action_widget->doc_model);
+	}
+	action_widget->doc_model = model;
+	g_object_add_weak_pointer (G_OBJECT (model),
+				   (gpointer)&action_widget->doc_model);
+
+	g_signal_connect (model, "notify::document",
+			  G_CALLBACK (ev_page_action_widget_document_changed_cb),
+			  action_widget);
 }
 
 static void
@@ -226,15 +244,15 @@ ev_page_action_widget_finalize (GObject *object)
 {
 	EvPageActionWidget *action_widget = EV_PAGE_ACTION_WIDGET (object);
 
-	if (action_widget->page_cache != NULL) {
+	if (action_widget->doc_model != NULL) {
 		if (action_widget->signal_id > 0) {
-			g_signal_handler_disconnect (action_widget->page_cache,
+			g_signal_handler_disconnect (action_widget->doc_model,
 						     action_widget->signal_id);
 			action_widget->signal_id = 0;
 		}
-		g_object_remove_weak_pointer (G_OBJECT (action_widget->page_cache),
-					      (gpointer)&action_widget->page_cache);
-		action_widget->page_cache = NULL;
+		g_object_remove_weak_pointer (G_OBJECT (action_widget->doc_model),
+					      (gpointer)&action_widget->doc_model);
+		action_widget->doc_model = NULL;
 	}
 
 	if (action_widget->document) {
@@ -432,7 +450,7 @@ get_filter_model_from_model (GtkTreeModel *model)
 
 
 void
-ev_page_action_widget_update_model (EvPageActionWidget *proxy, GtkTreeModel *model)
+ev_page_action_widget_update_links_model (EvPageActionWidget *proxy, GtkTreeModel *model)
 {
 	GtkTreeModel *filter_model;
 	GtkEntryCompletion *completion;
@@ -470,7 +488,6 @@ ev_page_action_widget_update_model (EvPageActionWidget *proxy, GtkTreeModel *mod
 	gtk_entry_set_completion (GTK_ENTRY (proxy->entry), completion);
 
 	g_object_unref (completion);
-	g_object_unref (model);
 }
 
 void
diff --git a/libmisc/ev-page-action-widget.h b/libmisc/ev-page-action-widget.h
index 1c9ee35..52e09b6 100644
--- a/libmisc/ev-page-action-widget.h
+++ b/libmisc/ev-page-action-widget.h
@@ -36,11 +36,11 @@ struct _EvPageActionWidgetClass
 			        EvLink             *link);
 };
 
-GType ev_page_action_widget_get_type      (void) G_GNUC_CONST;
+GType ev_page_action_widget_get_type          (void) G_GNUC_CONST;
 
-void ev_page_action_widget_update_model   (EvPageActionWidget *proxy,
-					   GtkTreeModel       *model);
+void ev_page_action_widget_update_links_model (EvPageActionWidget *proxy,
+					       GtkTreeModel       *model);
 
-void ev_page_action_widget_set_document   (EvPageActionWidget *action_widget,
-					   EvDocument         *document);
-void ev_page_action_widget_grab_focus     (EvPageActionWidget *proxy);
+void ev_page_action_widget_set_model          (EvPageActionWidget *action_widget,
+					       EvDocumentModel    *doc_model);
+void ev_page_action_widget_grab_focus         (EvPageActionWidget *proxy);
diff --git a/libmisc/ev-page-action.c b/libmisc/ev-page-action.c
index 090712e..6c36351 100644
--- a/libmisc/ev-page-action.c
+++ b/libmisc/ev-page-action.c
@@ -33,7 +33,7 @@
 
 struct _EvPageActionPrivate
 {
-	EvDocument *document;
+	EvDocumentModel *doc_model;
 	GtkTreeModel *model;
 };
 
@@ -55,8 +55,7 @@ G_DEFINE_TYPE (EvPageAction, ev_page_action, GTK_TYPE_ACTION)
 
 enum {
 	PROP_0,
-	PROP_DOCUMENT,
-	PROP_MODEL,
+	PROP_MODEL
 };
 
 static GtkWidget *
@@ -70,22 +69,9 @@ create_tool_item (GtkAction *action)
 }
 
 static void
-update_document (EvPageAction *page, GParamSpec *pspec, EvPageActionWidget *proxy)
-{
-	if (page->priv->document)
-		ev_page_action_widget_set_document (proxy, page->priv->document);
-}
-
-static void
 update_model (EvPageAction *page, GParamSpec *pspec, EvPageActionWidget *proxy)
 {
-	GtkTreeModel *model;
-
-	g_object_get (G_OBJECT (page),
-		      "model", &model,
-		      NULL);
-
-	ev_page_action_widget_update_model (proxy, model);
+	ev_page_action_widget_update_links_model (proxy, page->priv->model);
 }
 
 static void
@@ -97,10 +83,11 @@ activate_link_cb (EvPageActionWidget *proxy, EvLink *link, EvPageAction *action)
 static void
 connect_proxy (GtkAction *action, GtkWidget *proxy)
 {
+	EvPageAction *page = EV_PAGE_ACTION (action);
+
 	if (GTK_IS_TOOL_ITEM (proxy)) {
-		g_signal_connect_object (action, "notify::document",
-					 G_CALLBACK (update_document),
-					 proxy, 0);
+		ev_page_action_widget_set_model (EV_PAGE_ACTION_WIDGET (proxy),
+						 page->priv->doc_model);
 		g_signal_connect (proxy, "activate_link",
 				  G_CALLBACK (activate_link_cb),
 				  action);
@@ -117,11 +104,13 @@ ev_page_action_dispose (GObject *object)
 {
 	EvPageAction *page = EV_PAGE_ACTION (object);
 
-	if (page->priv->document) {
-		g_object_unref (page->priv->document);
-		page->priv->document = NULL;
+	if (page->priv->model) {
+		g_object_unref (page->priv->model);
+		page->priv->model = NULL;
 	}
 
+	page->priv->doc_model = NULL;
+
 	G_OBJECT_CLASS (ev_page_action_parent_class)->dispose (object);
 }
 
@@ -131,25 +120,13 @@ ev_page_action_set_property (GObject      *object,
 			     const GValue *value,
 			     GParamSpec   *pspec)
 {
-	EvPageAction *page;
-	EvDocument *document;
+	EvPageAction *page = EV_PAGE_ACTION (object);
 	GtkTreeModel *model;
 
-	page = EV_PAGE_ACTION (object);
-
 	switch (prop_id)
 	{
-	case PROP_DOCUMENT:
-		document = page->priv->document;
-		page->priv->document = EV_DOCUMENT (g_value_dup_object (value));
-		if (document)
-			g_object_unref (document);
-		break;
 	case PROP_MODEL:
-		model = page->priv->model;
-		page->priv->model = GTK_TREE_MODEL (g_value_dup_object (value));
-		if (model)
-			g_object_unref (model);
+		ev_page_action_set_links_model (page, g_value_get_object (value));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -163,15 +140,10 @@ ev_page_action_get_property (GObject    *object,
 			     GValue     *value,
 			     GParamSpec *pspec)
 {
-	EvPageAction *page;
-
-	page = EV_PAGE_ACTION (object);
+	EvPageAction *page = EV_PAGE_ACTION (object);
 
 	switch (prop_id)
 	{
-	case PROP_DOCUMENT:
-		g_value_set_object (value, page->priv->document);
-		break;
 	case PROP_MODEL:
 		g_value_set_object (value, page->priv->model);
 		break;
@@ -182,21 +154,33 @@ ev_page_action_get_property (GObject    *object,
 }
 
 void
-ev_page_action_set_document (EvPageAction *page, EvDocument *document)
+ev_page_action_set_model (EvPageAction    *page,
+			  EvDocumentModel *model)
 {
-	g_object_set (page,
-		      "document", document,
-		      "model", NULL,
-		      NULL);
+	g_return_if_fail (EV_IS_PAGE_ACTION (page));
+	g_return_if_fail (EV_IS_DOCUMENT_MODEL (model));
+
+	if (page->priv->doc_model == model)
+		return;
+
+	page->priv->doc_model = model;
 }
 
 void
-ev_page_action_set_model (EvPageAction *page_action,
-			  GtkTreeModel *model)
+ev_page_action_set_links_model (EvPageAction *page,
+				GtkTreeModel *links_model)
 {
-	g_object_set (page_action,
-		      "model", model,
-		      NULL);
+	g_return_if_fail (EV_IS_PAGE_ACTION (page));
+	g_return_if_fail (GTK_IS_TREE_MODEL (links_model));
+
+	if (page->priv->model == links_model)
+		return;
+
+	if (page->priv->model)
+		g_object_unref (page->priv->model);
+	page->priv->model = g_object_ref (links_model);
+
+	g_object_notify (G_OBJECT (page), "model");
 }
 
 void
@@ -245,18 +229,10 @@ ev_page_action_class_init (EvPageActionClass *class)
 					       G_TYPE_OBJECT);
 
 	g_object_class_install_property (object_class,
-					 PROP_DOCUMENT,
-					 g_param_spec_object ("document",
-							      "Document",
-							      "Current document",
-							      EV_TYPE_DOCUMENT,
-							      G_PARAM_READWRITE));
-
-	g_object_class_install_property (object_class,
 					 PROP_MODEL,
 					 g_param_spec_object ("model",
 							      "Model",
-							      "Current Model",
+							      "Current Links Model",
 							      GTK_TYPE_TREE_MODEL,
 							      G_PARAM_READWRITE));
 
diff --git a/libmisc/ev-page-action.h b/libmisc/ev-page-action.h
index dc13bdd..1817089 100644
--- a/libmisc/ev-page-action.h
+++ b/libmisc/ev-page-action.h
@@ -24,6 +24,7 @@
 #include <gtk/gtk.h>
 
 #include <evince-document.h>
+#include <evince-view.h>
 
 G_BEGIN_DECLS
 
@@ -54,12 +55,13 @@ struct _EvPageActionClass
 			            EvLink       *link);
 };
 
-GType ev_page_action_get_type     (void);
-void  ev_page_action_set_document (EvPageAction *page_action,
-				   EvDocument   *document);
-void  ev_page_action_set_model    (EvPageAction *page_action,
-				   GtkTreeModel *model);
-void  ev_page_action_grab_focus   (EvPageAction *page_action);
+GType ev_page_action_get_type        (void) G_GNUC_CONST;
+
+void  ev_page_action_set_model       (EvPageAction    *page_action,
+				      EvDocumentModel *model);
+void  ev_page_action_set_links_model (EvPageAction    *page_action,
+				      GtkTreeModel    *links_model);
+void  ev_page_action_grab_focus      (EvPageAction    *page_action);
 
 G_END_DECLS
 
diff --git a/libview/Makefile.am b/libview/Makefile.am
index d9e4c08..1964eee 100644
--- a/libview/Makefile.am
+++ b/libview/Makefile.am
@@ -10,9 +10,9 @@ NOINST_H_FILES =			\
 	ev-view-private.h
 
 INST_H_FILES = 				\
+	ev-document-model.h		\
 	ev-jobs.h			\
 	ev-job-scheduler.h		\
-	ev-page-cache.h			\
 	ev-stock-icons.h		\
 	ev-view.h			\
 	ev-view-type-builtins.h
@@ -22,9 +22,9 @@ header_DATA = $(INST_H_FILES)
 
 libevview_la_SOURCES = 			\
 	ev-annotation-window.c		\
+	ev-document-model.c		\
 	ev-jobs.c			\
 	ev-job-scheduler.c		\
-	ev-page-cache.c			\
 	ev-pixbuf-cache.c		\
 	ev-stock-icons.c		\
 	ev-timeline.c			\
diff --git a/libview/ev-document-model.c b/libview/ev-document-model.c
new file mode 100644
index 0000000..a850e84
--- /dev/null
+++ b/libview/ev-document-model.c
@@ -0,0 +1,416 @@
+/* this file is part of evince, a gnome document viewer
+ *
+ *  Copyright (C) 2009 Carlos Garcia Campos
+ *  Copyright (C) 2005 Red Hat, Inc
+ *
+ * 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 "ev-document-model.h"
+#include "ev-view-type-builtins.h"
+#include "ev-view-marshal.h"
+
+struct _EvDocumentModel
+{
+	GObject base;
+
+	EvDocument *document;
+	gint n_pages;
+
+	gint page;
+	gint rotation;
+	gdouble scale;
+	EvSizingMode sizing_mode;
+
+	gdouble max_scale;
+	gdouble min_scale;
+};
+
+struct _EvDocumentModelClass
+{
+	GObjectClass base_class;
+
+	/* Signals  */
+	void (* page_changed) (EvDocumentModel *model,
+			       gint             old_page,
+			       gint             new_page);
+};
+
+enum {
+	PROP_0,
+	PROP_DOCUMENT,
+	PROP_PAGE,
+	PROP_ROTATION,
+	PROP_SCALE,
+	PROP_SIZING_MODE
+};
+
+enum
+{
+	PAGE_CHANGED,
+	N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0 };
+
+G_DEFINE_TYPE (EvDocumentModel, ev_document_model, G_TYPE_OBJECT)
+
+static void
+ev_document_model_finalize (GObject *object)
+{
+	EvDocumentModel *model = EV_DOCUMENT_MODEL (object);
+
+	if (model->document) {
+		g_object_unref (model->document);
+		model->document = NULL;
+	}
+
+	G_OBJECT_CLASS (ev_document_model_parent_class)->finalize (object);
+}
+
+static void
+ev_document_model_set_property (GObject      *object,
+				guint         prop_id,
+				const GValue *value,
+				GParamSpec   *pspec)
+{
+	EvDocumentModel *model = EV_DOCUMENT_MODEL (object);
+
+	switch (prop_id) {
+	case PROP_DOCUMENT:
+		ev_document_model_set_document (model, (EvDocument *)g_value_get_object (value));
+		break;
+	case PROP_PAGE:
+		ev_document_model_set_page (model, g_value_get_int (value));
+		break;
+	case PROP_ROTATION:
+		ev_document_model_set_rotation (model, g_value_get_int (value));
+		break;
+	case PROP_SCALE:
+		ev_document_model_set_scale (model, g_value_get_double (value));
+		break;
+	case PROP_SIZING_MODE:
+		ev_document_model_set_sizing_mode (model, g_value_get_enum (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	}
+}
+
+static void
+ev_document_model_get_property (GObject    *object,
+				guint       prop_id,
+				GValue     *value,
+				GParamSpec *pspec)
+{
+	EvDocumentModel *model = EV_DOCUMENT_MODEL (object);
+
+	switch (prop_id) {
+	case PROP_DOCUMENT:
+		g_value_set_object (value, model->document);
+		break;
+	case PROP_PAGE:
+		g_value_set_int (value, model->page);
+		break;
+	case PROP_ROTATION:
+		g_value_set_int (value, model->rotation);
+		break;
+	case PROP_SCALE:
+		g_value_set_double (value, model->scale);
+		break;
+	case PROP_SIZING_MODE:
+		g_value_set_enum (value, model->sizing_mode);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	}
+}
+
+static void
+ev_document_model_class_init (EvDocumentModelClass *klass)
+{
+	GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
+
+	g_object_class->get_property = ev_document_model_get_property;
+	g_object_class->set_property = ev_document_model_set_property;
+	g_object_class->finalize = ev_document_model_finalize;
+
+	/* Properties */
+	g_object_class_install_property (g_object_class,
+					 PROP_DOCUMENT,
+					 g_param_spec_object ("document",
+							      "Document",
+							      "The current document",
+							      EV_TYPE_DOCUMENT,
+							      G_PARAM_READWRITE));
+	g_object_class_install_property (g_object_class,
+					 PROP_PAGE,
+					 g_param_spec_int ("page",
+							   "Page",
+							   "Current page",
+							   -1, G_MAXINT, -1,
+							   G_PARAM_READWRITE));
+	g_object_class_install_property (g_object_class,
+					 PROP_ROTATION,
+					 g_param_spec_int ("rotation",
+							   "Rotation",
+							   "Current rotation angle",
+							   0, 360, 0,
+							   G_PARAM_READWRITE));
+	g_object_class_install_property (g_object_class,
+					 PROP_SCALE,
+					 g_param_spec_double ("scale",
+							      "Scale",
+							      "Current scale factor",
+							      0., G_MAXDOUBLE, 1.,
+							      G_PARAM_READWRITE));
+	g_object_class_install_property (g_object_class,
+					 PROP_SIZING_MODE,
+					 g_param_spec_enum ("sizing-mode",
+							    "Sizing Mode",
+							    "Current sizing mode",
+							    EV_TYPE_SIZING_MODE,
+							    EV_SIZING_FIT_WIDTH,
+							    G_PARAM_READWRITE));
+
+	/* Signals */
+	signals [PAGE_CHANGED] =
+		g_signal_new ("page-changed",
+			      EV_TYPE_DOCUMENT_MODEL,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EvDocumentModelClass, page_changed),
+			      NULL, NULL,
+			      ev_view_marshal_VOID__INT_INT,
+			      G_TYPE_NONE, 2,
+			      G_TYPE_INT, G_TYPE_INT);
+}
+
+static void
+ev_document_model_init (EvDocumentModel *model)
+{
+	model->page = -1;
+	model->scale = 1.;
+	model->sizing_mode = EV_SIZING_FIT_WIDTH;
+	model->min_scale = 0.;
+	model->max_scale = G_MAXDOUBLE;
+}
+
+EvDocumentModel *
+ev_document_model_new (void)
+{
+	return g_object_new (EV_TYPE_DOCUMENT_MODEL, NULL);
+}
+
+EvDocumentModel *
+ev_document_model_new_with_document (EvDocument *document)
+{
+	g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL);
+
+	return g_object_new (EV_TYPE_DOCUMENT_MODEL, "document", document, NULL);
+}
+
+void
+ev_document_model_set_document (EvDocumentModel *model,
+				EvDocument      *document)
+{
+	g_return_if_fail (EV_IS_DOCUMENT_MODEL (model));
+	g_return_if_fail (EV_IS_DOCUMENT (document));
+
+	if (document == model->document)
+		return;
+
+	if (model->document)
+		g_object_unref (model->document);
+	model->document = g_object_ref (document);
+
+	model->n_pages = ev_document_get_n_pages (document);
+	ev_document_model_set_page (model, CLAMP (model->page, 0,
+						  model->n_pages - 1));
+
+	g_object_notify (G_OBJECT (model), "document");
+}
+
+EvDocument *
+ev_document_model_get_document (EvDocumentModel *model)
+{
+	g_return_val_if_fail (EV_IS_DOCUMENT_MODEL (model), NULL);
+
+	return model->document;
+}
+
+void
+ev_document_model_set_page (EvDocumentModel *model,
+			    gint             page)
+{
+	gint old_page;
+
+	g_return_if_fail (EV_IS_DOCUMENT_MODEL (model));
+
+	if (model->page == page)
+		return;
+	if (page < 0 || (model->document && page >= model->n_pages))
+		return;
+
+	old_page = model->page;
+	model->page = page;
+	g_signal_emit (model, signals[PAGE_CHANGED], 0, old_page, page);
+
+	g_object_notify (G_OBJECT (model), "page");
+}
+
+void
+ev_document_model_set_page_by_label (EvDocumentModel *model,
+				     const gchar     *page_label)
+{
+	gint page;
+
+	g_return_if_fail (EV_IS_DOCUMENT_MODEL (model));
+	g_return_if_fail (model->document != NULL);
+
+	if (ev_document_find_page_by_label (model->document, page_label, &page))
+		ev_document_model_set_page (model, page);
+}
+
+gint
+ev_document_model_get_page (EvDocumentModel *model)
+{
+	g_return_val_if_fail (EV_IS_DOCUMENT_MODEL (model), -1);
+
+	return model->page;
+}
+
+void
+ev_document_model_set_scale (EvDocumentModel *model,
+			     gdouble          scale)
+{
+	g_return_if_fail (EV_IS_DOCUMENT_MODEL (model));
+
+	scale = CLAMP (scale,
+		       model->sizing_mode == EV_SIZING_FREE ?
+		       model->min_scale : 0, model->max_scale);
+
+	if (scale == model->scale)
+		return;
+
+	model->scale = scale;
+
+	g_object_notify (G_OBJECT (model), "scale");
+}
+
+gdouble
+ev_document_model_get_scale (EvDocumentModel *model)
+{
+	g_return_val_if_fail (EV_IS_DOCUMENT_MODEL (model), 1.0);
+
+	return model->scale;
+}
+
+void
+ev_document_model_set_max_scale (EvDocumentModel *model,
+				 gdouble          max_scale)
+{
+	g_return_if_fail (EV_IS_DOCUMENT_MODEL (model));
+
+	if (max_scale == model->max_scale)
+		return;
+
+	model->max_scale = max_scale;
+
+	if (model->scale > max_scale)
+		ev_document_model_set_scale (model, max_scale);
+}
+
+gdouble
+ev_document_model_get_max_scale (EvDocumentModel *model)
+{
+	g_return_val_if_fail (EV_IS_DOCUMENT_MODEL (model), 1.0);
+
+	return model->max_scale;
+}
+
+void
+ev_document_model_set_min_scale (EvDocumentModel *model,
+				 gdouble          min_scale)
+{
+	g_return_if_fail (EV_IS_DOCUMENT_MODEL (model));
+
+	if (min_scale == model->min_scale)
+		return;
+
+	model->min_scale = min_scale;
+
+	if (model->scale < min_scale)
+		ev_document_model_set_scale (model, min_scale);
+}
+
+gdouble
+ev_document_model_get_min_scale (EvDocumentModel *model)
+{
+	g_return_val_if_fail (EV_IS_DOCUMENT_MODEL (model), 0.);
+
+	return model->min_scale;
+}
+
+void
+ev_document_model_set_sizing_mode (EvDocumentModel *model,
+				   EvSizingMode     mode)
+{
+	g_return_if_fail (EV_IS_DOCUMENT_MODEL (model));
+
+	if (mode == model->sizing_mode)
+		return;
+
+	model->sizing_mode = mode;
+
+	g_object_notify (G_OBJECT (model), "sizing-mode");
+}
+
+EvSizingMode
+ev_document_model_get_sizing_mode (EvDocumentModel *model)
+{
+	g_return_val_if_fail (EV_IS_DOCUMENT_MODEL (model), EV_SIZING_FIT_WIDTH);
+
+	return model->sizing_mode;
+}
+
+void
+ev_document_model_set_rotation (EvDocumentModel *model,
+				gint             rotation)
+{
+	g_return_if_fail (EV_IS_DOCUMENT_MODEL (model));
+
+	if (rotation >= 360)
+		rotation -= 360;
+	else if (rotation < 0)
+		rotation += 360;
+
+	if (rotation == model->rotation)
+		return;
+
+	model->rotation = rotation;
+
+	g_object_notify (G_OBJECT (model), "rotation");
+}
+
+gint
+ev_document_model_get_rotation (EvDocumentModel *model)
+{
+	g_return_val_if_fail (EV_IS_DOCUMENT_MODEL (model), 0);
+
+	return model->rotation;
+}
+
diff --git a/libview/ev-document-model.h b/libview/ev-document-model.h
new file mode 100644
index 0000000..14c960a
--- /dev/null
+++ b/libview/ev-document-model.h
@@ -0,0 +1,75 @@
+/* this file is part of evince, a gnome document viewer
+ *
+ *  Copyright (C) 2009 Carlos Garcia Campos
+ *
+ * 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.
+ */
+
+#if !defined (__EV_EVINCE_VIEW_H_INSIDE__) && !defined (EVINCE_COMPILATION)
+#error "Only <evince-view.h> can be included directly."
+#endif
+
+#ifndef __EV_DOCUMENT_MODEL_H__
+#define __EV_DOCUMENT_MODEL_H__
+
+#include <glib-object.h>
+#include <evince-document.h>
+
+G_BEGIN_DECLS
+
+#define EV_TYPE_DOCUMENT_MODEL            (ev_document_model_get_type ())
+#define EV_DOCUMENT_MODEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_DOCUMENT_MODEL, EvDocumentModel))
+#define EV_IS_DOCUMENT_MODEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_DOCUMENT_MODEL))
+
+typedef enum {
+	EV_SIZING_BEST_FIT,
+	EV_SIZING_FIT_WIDTH,
+	EV_SIZING_FREE,
+} EvSizingMode;
+
+typedef struct _EvDocumentModel        EvDocumentModel;
+typedef struct _EvDocumentModelClass   EvDocumentModelClass;
+
+GType            ev_document_model_get_type          (void) G_GNUC_CONST;
+EvDocumentModel *ev_document_model_new               (void);
+EvDocumentModel *ev_document_model_new_with_document (EvDocument      *document);
+
+void             ev_document_model_set_document      (EvDocumentModel *model,
+						      EvDocument      *document);
+EvDocument      *ev_document_model_get_document      (EvDocumentModel *model);
+void             ev_document_model_set_page          (EvDocumentModel *model,
+						      gint             page);
+void             ev_document_model_set_page_by_label (EvDocumentModel *model,
+						      const gchar     *page_label);
+gint             ev_document_model_get_page          (EvDocumentModel *model);
+void             ev_document_model_set_scale         (EvDocumentModel *model,
+						      gdouble          scale);
+gdouble          ev_document_model_get_scale         (EvDocumentModel *model);
+void             ev_document_model_set_max_scale     (EvDocumentModel *model,
+						      gdouble          max_scale);
+gdouble          ev_document_model_get_max_scale     (EvDocumentModel *model);
+void             ev_document_model_set_min_scale     (EvDocumentModel *model,
+						      gdouble          min_scale);
+gdouble          ev_document_model_get_min_scale     (EvDocumentModel *model);
+void             ev_document_model_set_sizing_mode   (EvDocumentModel *model,
+						      EvSizingMode     mode);
+EvSizingMode     ev_document_model_get_sizing_mode   (EvDocumentModel *model);
+void             ev_document_model_set_rotation      (EvDocumentModel *model,
+						      gint             rotation);
+gint             ev_document_model_get_rotation      (EvDocumentModel *model);
+
+G_END_DECLS
+
+#endif /* __EV_DOCUMENT_MODEL_H__ */
diff --git a/libview/ev-pixbuf-cache.c b/libview/ev-pixbuf-cache.c
index 0ebfeae..df06705 100644
--- a/libview/ev-pixbuf-cache.c
+++ b/libview/ev-pixbuf-cache.c
@@ -1,7 +1,6 @@
 #include <config.h>
 #include "ev-pixbuf-cache.h"
 #include "ev-job-scheduler.h"
-#include "ev-page-cache.h"
 #include "ev-mapping.h"
 #include "ev-document-forms.h"
 #include "ev-document-images.h"
@@ -291,9 +290,8 @@ job_finished_cb (EvJob         *job,
  */
 static void
 check_job_size_and_unref (EvPixbufCache *pixbuf_cache,
-			  CacheJobInfo *job_info,
-			  EvPageCache  *page_cache,
-			  gfloat        scale)
+			  CacheJobInfo  *job_info,
+			  gfloat         scale)
 {
 	gint width, height;
 
@@ -586,18 +584,15 @@ static void
 ev_pixbuf_cache_clear_job_sizes (EvPixbufCache *pixbuf_cache,
 				 gfloat         scale)
 {
-	EvPageCache *page_cache;
 	int i;
 
-	page_cache = ev_page_cache_get (pixbuf_cache->document);
-
 	for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
-		check_job_size_and_unref (pixbuf_cache, pixbuf_cache->job_list + i, page_cache, scale);
+		check_job_size_and_unref (pixbuf_cache, pixbuf_cache->job_list + i, scale);
 	}
 
 	for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
-		check_job_size_and_unref (pixbuf_cache, pixbuf_cache->prev_job + i, page_cache, scale);
-		check_job_size_and_unref (pixbuf_cache, pixbuf_cache->next_job + i, page_cache, scale);
+		check_job_size_and_unref (pixbuf_cache, pixbuf_cache->prev_job + i, scale);
+		check_job_size_and_unref (pixbuf_cache, pixbuf_cache->next_job + i, scale);
 	}
 }
 
@@ -672,7 +667,6 @@ add_job (EvPixbufCache *pixbuf_cache,
 static void
 add_job_if_needed (EvPixbufCache *pixbuf_cache,
 		   CacheJobInfo  *job_info,
-		   EvPageCache   *page_cache,
 		   gint           page,
 		   gint           rotation,
 		   gfloat         scale,
@@ -702,19 +696,16 @@ ev_pixbuf_cache_add_jobs_if_needed (EvPixbufCache *pixbuf_cache,
 				    gint           rotation,
 				    gfloat         scale)
 {
-	EvPageCache *page_cache;
 	CacheJobInfo *job_info;
 	int page;
 	int i;
 
-	page_cache = ev_page_cache_get (pixbuf_cache->document);
-
 	for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
 		job_info = (pixbuf_cache->job_list + i);
 		page = pixbuf_cache->start_page + i;
 
 		add_job_if_needed (pixbuf_cache, job_info,
-				   page_cache, page, rotation, scale,
+				   page, rotation, scale,
 				   EV_JOB_PRIORITY_URGENT);
 	}
 
@@ -723,7 +714,7 @@ ev_pixbuf_cache_add_jobs_if_needed (EvPixbufCache *pixbuf_cache,
 		page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size + i;
 
 		add_job_if_needed (pixbuf_cache, job_info,
-				   page_cache, page, rotation, scale,
+				   page, rotation, scale,
 				   EV_JOB_PRIORITY_LOW);
 	}
 
@@ -732,7 +723,7 @@ ev_pixbuf_cache_add_jobs_if_needed (EvPixbufCache *pixbuf_cache,
 		page = pixbuf_cache->end_page + 1 + i;
 
 		add_job_if_needed (pixbuf_cache, job_info,
-				   page_cache, page, rotation, scale,
+				   page, rotation, scale,
 				   EV_JOB_PRIORITY_LOW);
 	}
 
diff --git a/libview/ev-view-private.h b/libview/ev-view-private.h
index 2f01f72..a2710a9 100644
--- a/libview/ev-view-private.h
+++ b/libview/ev-view-private.h
@@ -26,8 +26,8 @@
 #define __EV_VIEW_PRIVATE_H__
 
 #include "ev-view.h"
+#include "ev-document-model.h"
 #include "ev-pixbuf-cache.h"
-#include "ev-page-cache.h"
 #include "ev-jobs.h"
 #include "ev-image.h"
 #include "ev-form-field.h"
@@ -133,7 +133,8 @@ struct _EvView {
 	gint find_result;
 	gboolean jump_to_find_result;
 	gboolean highlight_find_results;
-	
+
+	EvDocumentModel *model;
 	EvPageCache *page_cache;
 	EvPixbufCache *pixbuf_cache;
 	EvHeightToPageCache *height_to_page_cache;
@@ -161,8 +162,6 @@ struct _EvView {
 	gdouble scale;
 	gint spacing;
 	gdouble dpi;
-	gdouble max_scale;
-	gdouble min_scale;
 
 	gboolean loading;
 	gboolean continuous;
diff --git a/libview/ev-view.c b/libview/ev-view.c
index b2fb610..50e4f72 100644
--- a/libview/ev-view.c
+++ b/libview/ev-view.c
@@ -34,7 +34,6 @@
 #include "ev-document-links.h"
 #include "ev-document-misc.h"
 #include "ev-document-transition.h"
-#include "ev-page-cache.h"
 #include "ev-pixbuf-cache.h"
 #include "ev-transition-animation.h"
 #include "ev-view-marshal.h"
@@ -85,9 +84,6 @@ typedef enum {
 #define ZOOM_IN_FACTOR  1.2
 #define ZOOM_OUT_FACTOR (1.0/ZOOM_IN_FACTOR)
 
-#define MIN_SCALE 0.05409
-#define MAX_SCALE 4.0
-
 #define SCROLL_TIME 150
 
 /*** Scrolling ***/
@@ -219,8 +215,9 @@ static void       ev_view_reload_page                        (EvView
 static void       job_finished_cb                            (EvPixbufCache      *pixbuf_cache,
 							      GdkRegion          *region,
 							      EvView             *view);
-static void       page_changed_cb                            (EvPageCache        *page_cache,
-							      int                 new_page,
+static void       ev_view_page_changed_cb                    (EvDocumentModel    *model,
+							      gint                old_page,
+							      gint                new_page,
 							      EvView             *view);
 static void       on_adjustment_value_changed                (GtkAdjustment      *adjustment,
 							      EvView             *view);
@@ -663,11 +660,11 @@ view_update_range_and_current_page (EvView *view)
 	}
 
 	best_current_page = MAX (best_current_page, view->start_page);
-	current_page = ev_page_cache_get_current_page (view->page_cache);
+	current_page = ev_document_model_get_page (view->model);
 
 	if ((current_page != best_current_page) && (view->pending_scroll == SCROLL_TO_KEEP_POSITION)) {
 		view->current_page = best_current_page;
-		ev_page_cache_set_current_page (view->page_cache, best_current_page);
+		ev_document_model_set_page (view->model, best_current_page);
 	}
 
 	if (start != view->start_page || end != view->end_page) {
@@ -1218,7 +1215,7 @@ find_page_at_location (EvView  *view,
 	g_assert (x_offset);
 	g_assert (y_offset);
 
-	for (i = view->start_page; i <= view->end_page; i++) {
+	for (i = view->start_page; i >= 0 && i <= view->end_page; i++) {
 		GdkRectangle page_area;
 		GtkBorder border;
 
@@ -1411,8 +1408,8 @@ goto_fitr_dest (EvView *view, EvLinkDest *dest)
 				       ev_view_get_width (view),
 				       ev_view_get_height (view));
 
-	ev_view_set_sizing_mode (view, EV_SIZING_FREE);
-	ev_view_set_zoom (view, zoom, FALSE);
+	ev_document_model_set_sizing_mode (view->model, EV_SIZING_FREE);
+	ev_document_model_set_scale (view->model, zoom);
 
 	doc_point.x = change_left ? left : 0;
 	doc_point.y = change_top ? top : 0;
@@ -1445,8 +1442,8 @@ goto_fitv_dest (EvView *view, EvLinkDest *dest)
 					 ev_view_get_width (view),
 				         ev_view_get_height (view));
 
-	ev_view_set_sizing_mode (view, EV_SIZING_FREE);
-	ev_view_set_zoom (view, zoom, FALSE);
+	ev_document_model_set_sizing_mode (view->model, EV_SIZING_FREE);
+	ev_document_model_set_scale (view->model, zoom);
 
 	view->current_page = page;
 	if (change_left)
@@ -1477,8 +1474,8 @@ goto_fith_dest (EvView *view, EvLinkDest *dest)
 					ev_view_get_width (view),
 				        ev_view_get_height (view));
 
-	ev_view_set_sizing_mode (view, EV_SIZING_FIT_WIDTH);
-	ev_view_set_zoom (view, zoom, FALSE);
+	ev_document_model_set_sizing_mode (view->model, EV_SIZING_FIT_WIDTH);
+	ev_document_model_set_scale (view->model, zoom);
 
 	view->current_page = page;
 	if (change_top)
@@ -1502,8 +1499,8 @@ goto_fit_dest (EvView *view, EvLinkDest *dest)
 				       ev_view_get_width (view),
 				       ev_view_get_height (view));
 
-	ev_view_set_sizing_mode (view, EV_SIZING_BEST_FIT);
-	ev_view_set_zoom (view, zoom, FALSE);
+	ev_document_model_set_sizing_mode (view->model, EV_SIZING_BEST_FIT);
+	ev_document_model_set_scale (view->model, zoom);
 
 	view->current_page = page;
 	view->pending_scroll = SCROLL_TO_PAGE_POSITION;
@@ -1523,8 +1520,8 @@ goto_xyz_dest (EvView *view, EvLinkDest *dest)
 	page = ev_link_dest_get_page (dest);
 
 	if (change_zoom && zoom > 1) {
-		ev_view_set_sizing_mode (view, EV_SIZING_FREE);
-		ev_view_set_zoom (view, zoom, FALSE);
+		ev_document_model_set_sizing_mode (view->model, EV_SIZING_FREE);
+		ev_document_model_set_scale (view->model, zoom);
 	}
 
 	left = ev_link_dest_get_left (dest, &change_left);
@@ -1559,7 +1556,7 @@ goto_dest (EvView *view, EvLinkDest *dest)
 
 	switch (type) {
 	        case EV_LINK_DEST_TYPE_PAGE:
-			ev_page_cache_set_current_page (view->page_cache, page);
+			ev_document_model_set_page (view->model, page);
 			break;
 	        case EV_LINK_DEST_TYPE_FIT:
 			goto_fit_dest (view, dest);
@@ -1577,15 +1574,14 @@ goto_dest (EvView *view, EvLinkDest *dest)
 			goto_xyz_dest (view, dest);
 			break;
 	        case EV_LINK_DEST_TYPE_PAGE_LABEL:
-			ev_page_cache_set_page_label (view->page_cache, ev_link_dest_get_page_label (dest));
+			ev_document_model_set_page_by_label (view->model, ev_link_dest_get_page_label (dest));
 			break;
 	        default:
 			g_assert_not_reached ();
 	}
 
 	if (current_page != view->current_page)
-		ev_page_cache_set_current_page (view->page_cache,
-						view->current_page);
+		ev_document_model_set_page (view->model, view->current_page);
 }
 
 static void
@@ -3085,7 +3081,7 @@ ev_view_expose_event (GtkWidget      *widget,
 
 	cr = gdk_cairo_create (view->layout.bin_window);
 	
-	for (i = view->start_page; i <= view->end_page; i++) {
+	for (i = view->start_page; i >= 0 && i <= view->end_page; i++) {
 		GdkRectangle page_area;
 		GtkBorder border;
 		gboolean page_ready = TRUE;
@@ -3881,8 +3877,9 @@ ev_view_goto_entry_activate (GtkEntry *entry,
 	
 	ev_view_goto_window_hide (view);
 
-	if (page >= 0 && page < ev_document_get_n_pages (view->document))
-		ev_page_cache_set_current_page (view->page_cache, page);
+	if (page >= 0 && page < ev_document_get_n_pages (view->document)) {
+		ev_document_model_set_page (view->model, page);
+	}
 }
 
 static void
@@ -4296,7 +4293,7 @@ draw_one_page (EvView       *view,
 	if (!view->presentation) {
 		gint current_page;
 		
-		current_page = ev_page_cache_get_current_page (view->page_cache);
+		current_page = ev_document_model_get_page (view->model);
 		ev_document_misc_paint_one_page (view->layout.bin_window,
 						 GTK_WIDGET (view),
 						 page_area, border, 
@@ -4406,6 +4403,11 @@ ev_view_destroy (GtkObject *object)
 {
 	EvView *view = EV_VIEW (object);
 
+	if (view->model) {
+		g_object_unref (view->model);
+		view->model = NULL;
+	}
+
 	if (view->document) {
 		g_object_unref (view->document);
 		view->document = NULL;
@@ -4486,7 +4488,7 @@ ev_view_set_property (GObject      *object,
 			ev_view_set_sizing_mode (view, g_value_get_enum (value));
 			break;
 	        case PROP_ZOOM:
-			ev_view_set_zoom (view, g_value_get_double (value), FALSE);
+			ev_view_set_zoom (view, g_value_get_double (value));
 			break;
 	        case PROP_ROTATION:
 			ev_view_set_rotation (view, g_value_get_int (value));
@@ -4697,6 +4699,7 @@ ev_view_class_init (EvViewClass *class)
 							      360,
 							      0,
 							      G_PARAM_READWRITE));
+
 	g_object_class_install_property (object_class,
 					 PROP_HAS_SELECTION,
 					 g_param_spec_boolean ("has-selection",
@@ -4861,10 +4864,14 @@ job_finished_cb (EvPixbufCache *pixbuf_cache,
 }
 
 static void
-page_changed_cb (EvPageCache *page_cache,
-		 int          new_page,
-		 EvView      *view)
+ev_view_page_changed_cb (EvDocumentModel *model,
+			 gint             old_page,
+			 gint             new_page,
+			 EvView          *view)
 {
+	if (!view->document)
+		return;
+
 	if (view->current_page != new_page) {
 		if (view->presentation)
 			ev_view_presentation_animation_start (view, new_page);
@@ -4949,14 +4956,9 @@ ev_view_new (void)
 static void
 setup_caches (EvView *view)
 {
-	view->page_cache = ev_page_cache_get (view->document);
 	view->height_to_page_cache = ev_view_get_height_to_page_cache (view);
-	g_signal_connect (view->page_cache, "page-changed", G_CALLBACK (page_changed_cb), view);
 	view->pixbuf_cache = ev_pixbuf_cache_new (GTK_WIDGET (view), view->document);
 	g_signal_connect (view->pixbuf_cache, "job-finished", G_CALLBACK (job_finished_cb), view);
-	page_changed_cb (view->page_cache,
-			 ev_page_cache_get_current_page (view->page_cache),
-			 view);
 }
 
 static void
@@ -4966,10 +4968,6 @@ clear_caches (EvView *view)
 		g_object_unref (view->pixbuf_cache);
 		view->pixbuf_cache = NULL;
 	}
-
-	if (view->page_cache) {
-		view->page_cache = NULL;
-	}
 }
 
 void
@@ -5053,20 +5051,20 @@ ev_view_autoscroll_stop (EvView *view)
 	ev_view_handle_cursor_over_xy (view, x, y);
 }
 
-void
-ev_view_set_document (EvView     *view,
-		      EvDocument *document)
+static void
+ev_view_document_changed_cb (EvDocumentModel *model,
+			     GParamSpec      *pspec,
+			     EvView          *view)
 {
-	g_return_if_fail (EV_IS_VIEW (view));
+	EvDocument *document = ev_document_model_get_document (model);
 
 	view->loading = FALSE;
-	
+
 	if (document != view->document) {
 		clear_caches (view);
 
 		if (view->document) {
 			g_object_unref (view->document);
-			view->page_cache = NULL;
                 }
 
 		view->document = document;
@@ -5077,10 +5075,100 @@ ev_view_set_document (EvView     *view,
 			setup_caches (view);
                 }
 
-		view_update_range_and_current_page (view);
+		ev_view_change_page (view,
+				     ev_document_model_get_page (model),
+				     TRUE);
+	}
+}
+
+static void
+ev_view_rotation_changed_cb (EvDocumentModel *model,
+			     GParamSpec      *pspec,
+			     EvView          *view)
+{
+	gint rotation = ev_document_model_get_rotation (model);
+
+	ev_view_set_rotation (view, rotation);
+
+	if (view->pixbuf_cache) {
+		ev_pixbuf_cache_clear (view->pixbuf_cache);
+		gtk_widget_queue_resize (GTK_WIDGET (view));
+	}
+
+	if (rotation != 0)
+		clear_selection (view);
+}
+
+static void
+ev_view_sizing_mode_changed_cb (EvDocumentModel *model,
+				GParamSpec      *pspec,
+				EvView          *view)
+{
+	EvSizingMode mode = ev_document_model_get_sizing_mode (model);
+
+	ev_view_set_sizing_mode (view, mode);
 
+	if (mode != EV_SIZING_FREE)
 		gtk_widget_queue_resize (GTK_WIDGET (view));
+}
+
+#define EPSILON 0.0000001
+static void
+ev_view_scale_changed_cb (EvDocumentModel *model,
+			  GParamSpec      *pspec,
+			  EvView          *view)
+{
+	gdouble scale = ev_document_model_get_scale (model);
+
+	if (ABS (view->scale - scale) < EPSILON)
+		return;
+
+	if (view->loading_text) {
+		cairo_surface_destroy (view->loading_text);
+		view->loading_text = NULL;
 	}
+
+	ev_view_set_zoom (view, scale);
+
+	view->pending_resize = TRUE;
+	gtk_widget_queue_resize (GTK_WIDGET (view));
+}
+
+void
+ev_view_set_model (EvView          *view,
+		   EvDocumentModel *model)
+{
+	g_return_if_fail (EV_IS_VIEW (view));
+	g_return_if_fail (EV_IS_DOCUMENT_MODEL (model));
+
+	if (model == view->model)
+		return;
+
+	if (view->model) {
+		g_signal_handlers_disconnect_by_func (view->model,
+						      ev_view_document_changed_cb,
+						      view);
+		g_signal_handlers_disconnect_by_func (view->model,
+						      ev_view_page_changed_cb,
+						      view);
+		g_object_unref (view->model);
+	}
+	view->model = g_object_ref (model);
+	g_signal_connect (view->model, "notify::document",
+			  G_CALLBACK (ev_view_document_changed_cb),
+			  view);
+	g_signal_connect (view->model, "notify::rotation",
+			  G_CALLBACK (ev_view_rotation_changed_cb),
+			  view);
+	g_signal_connect (view->model, "notify::sizing-mode",
+			  G_CALLBACK (ev_view_sizing_mode_changed_cb),
+			  view);
+	g_signal_connect (view->model, "notify::scale",
+			  G_CALLBACK (ev_view_scale_changed_cb),
+			  view);
+	g_signal_connect (view->model, "page-changed",
+			  G_CALLBACK (ev_view_page_changed_cb),
+			  view);
 }
 
 static void
@@ -5104,38 +5192,11 @@ ev_view_reload (EvView *view)
 
 /*** Zoom and sizing mode ***/
 
-#define EPSILON 0.0000001
 void
 ev_view_set_zoom (EvView   *view,
-		  double    factor,
-		  gboolean  relative)
+		  double    scale)
 {
-	double scale;
-
-	if (relative)
-		scale = view->scale * factor;
-	else
-		scale = factor;
-
-	scale = CLAMP (scale,
-		       view->sizing_mode == EV_SIZING_FREE ? view->min_scale : 0,
-		       view->max_scale);
-
-	if (scale == view->scale)
-		return;
-
-	if (ABS (view->scale - scale) < EPSILON)
-		return;
-
-	if (view->loading_text) {
-		cairo_surface_destroy (view->loading_text);
-		view->loading_text = NULL;
-	}
-
 	view->scale = scale;
-	view->pending_resize = TRUE;
-
-	gtk_widget_queue_resize (GTK_WIDGET (view));
 
 	g_object_notify (G_OBJECT (view), "zoom");
 }
@@ -5154,8 +5215,6 @@ ev_view_set_screen_dpi (EvView  *view,
 	g_return_if_fail (dpi > 0);
 
 	view->dpi = dpi;
-	view->min_scale = MIN_SCALE * dpi / 72.0;
-	view->max_scale = MAX_SCALE * dpi / 72.0;
 }
 
 gboolean
@@ -5259,8 +5318,8 @@ ev_view_set_presentation (EvView   *view,
 		view->scale_saved = view->scale;
 		ev_view_set_sizing_mode (view, EV_SIZING_BEST_FIT);
 	} else {
-		ev_view_set_sizing_mode (view, view->sizing_mode_saved);
-		ev_view_set_zoom (view, view->scale_saved, FALSE);
+		ev_document_model_set_sizing_mode (view->model, view->sizing_mode_saved);
+		ev_document_model_set_scale (view->model, view->scale_saved);
 	}
 	
 	gtk_widget_queue_resize (GTK_WIDGET (view));
@@ -5336,13 +5395,7 @@ void
 ev_view_set_sizing_mode (EvView       *view,
 			 EvSizingMode  sizing_mode)
 {
-	g_return_if_fail (EV_IS_VIEW (view));
-
-	if (view->sizing_mode == sizing_mode)
-		return;
-
 	view->sizing_mode = sizing_mode;
-	gtk_widget_queue_resize (GTK_WIDGET (view));
 
 	g_object_notify (G_OBJECT (view), "sizing-mode");
 }
@@ -5358,61 +5411,43 @@ ev_view_get_sizing_mode (EvView *view)
 gboolean
 ev_view_can_zoom_in (EvView *view)
 {
-	return view->scale * ZOOM_IN_FACTOR <= view->max_scale;
+	return view->scale * ZOOM_IN_FACTOR <= ev_document_model_get_max_scale (view->model);
 }
 
 gboolean
 ev_view_can_zoom_out (EvView *view)
 {
-	return view->scale * ZOOM_OUT_FACTOR >= view->min_scale;
+	return view->scale * ZOOM_OUT_FACTOR >= ev_document_model_get_min_scale (view->model);
 }
 
 void
 ev_view_zoom_in (EvView *view)
 {
+	gdouble scale;
+
 	g_return_if_fail (view->sizing_mode == EV_SIZING_FREE);
 
 	if (view->presentation)
 		return;
-	
+
 	view->pending_scroll = SCROLL_TO_CENTER;
-	ev_view_set_zoom (view, ZOOM_IN_FACTOR, TRUE);
+	scale = ev_document_model_get_scale (view->model) * ZOOM_IN_FACTOR;
+	ev_document_model_set_scale (view->model, scale);
 }
 
 void
 ev_view_zoom_out (EvView *view)
 {
+	gdouble scale;
+
 	g_return_if_fail (view->sizing_mode == EV_SIZING_FREE);
 
 	if (view->presentation)
 		return;
-	
-	view->pending_scroll = SCROLL_TO_CENTER;
-	ev_view_set_zoom (view, ZOOM_OUT_FACTOR, TRUE);
-}
-
-void
-ev_view_rotate_right (EvView *view)
-{
-	int rotation = view->rotation + 90;
-
-	if (rotation >= 360) {
-		rotation -= 360;
-	}
-
-	ev_view_set_rotation (view, rotation);
-}
 
-void
-ev_view_rotate_left (EvView *view)
-{
-	int rotation = view->rotation - 90;
-
-	if (rotation < 0) {
-		rotation += 360;
-	}
-
-	ev_view_set_rotation (view, rotation);
+	view->pending_scroll = SCROLL_TO_CENTER;
+	scale = ev_document_model_get_scale (view->model) * ZOOM_OUT_FACTOR;
+	ev_document_model_set_scale (view->model, scale);
 }
 
 void
@@ -5420,14 +5455,6 @@ ev_view_set_rotation (EvView *view, int rotation)
 {
 	view->rotation = rotation;
 
-	if (view->pixbuf_cache) {
-		ev_pixbuf_cache_clear (view->pixbuf_cache);
-		gtk_widget_queue_resize (GTK_WIDGET (view));
-	}
-
-	if (rotation != 0)
-		clear_selection (view);
-
 	g_object_notify (G_OBJECT (view), "rotation");
 }
 
@@ -5500,7 +5527,7 @@ ev_view_zoom_for_size_presentation (EvView *view,
 
 	get_doc_page_size (view, view->current_page, &doc_width, &doc_height);
 	scale = zoom_for_size_best_fit (doc_width, doc_height, width, height);
-	ev_view_set_zoom (view, scale, FALSE);
+	ev_document_model_set_scale (view->model, scale);
 }
 
 static void
@@ -5534,7 +5561,7 @@ ev_view_zoom_for_size_continuous_and_dual_page (EvView *view,
 	else
 		g_assert_not_reached ();
 
-	ev_view_set_zoom (view, scale, FALSE);
+	ev_document_model_set_scale (view->model, scale);
 }
 
 static void
@@ -5567,7 +5594,7 @@ ev_view_zoom_for_size_continuous (EvView *view,
 	else
 		g_assert_not_reached ();
 
-	ev_view_set_zoom (view, scale, FALSE);
+	ev_document_model_set_scale (view->model, scale);
 }
 
 static void
@@ -5606,7 +5633,7 @@ ev_view_zoom_for_size_dual_page (EvView *view,
 	else
 		g_assert_not_reached ();
 
-	ev_view_set_zoom (view, scale, FALSE);
+	ev_document_model_set_scale (view->model, scale);
 }
 
 static void
@@ -5633,7 +5660,7 @@ ev_view_zoom_for_size_single_page (EvView *view,
 	else
 		g_assert_not_reached ();
 
-	ev_view_set_zoom (view, scale, FALSE);
+	ev_document_model_set_scale (view->model, scale);
 }
 
 static void
@@ -5726,7 +5753,7 @@ jump_to_find_page (EvView *view, EvViewFindDirection direction, gint shift)
 			page = page + n_pages;
 
 		if (ev_view_find_get_n_results (view, page) > 0) {
-			ev_page_cache_set_current_page (view->page_cache, page);
+			ev_document_model_set_page (view->model, page);
 			break;
 		}
 	}
@@ -6390,7 +6417,7 @@ ev_view_next_page (EvView *view)
 
 	g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
 	
-	if (!view->page_cache)
+	if (!view->document)
 		return FALSE;
 
 	if (view->presentation &&
@@ -6407,7 +6434,7 @@ ev_view_next_page (EvView *view)
 	ev_view_presentation_transition_stop (view);
 	ev_view_reset_presentation_state (view);
 	
-	page = ev_page_cache_get_current_page (view->page_cache);
+	page = ev_document_model_get_page (view->model);
 	n_pages = ev_document_get_n_pages (view->document);
 
 	if (view->dual_page && !view->presentation)
@@ -6416,14 +6443,14 @@ ev_view_next_page (EvView *view)
 		page = page + 1;
 
 	if (page < n_pages) {
-		ev_page_cache_set_current_page (view->page_cache, page);
+		ev_document_model_set_page (view->model, page);
 		return TRUE;
 	} else if (view->presentation && page == n_pages) {
 		view->presentation_state = EV_PRESENTATION_END;
 		gtk_widget_queue_draw (GTK_WIDGET (view));
 		return TRUE;
 	} else if (view->dual_page && page == n_pages) {
-		ev_page_cache_set_current_page (view->page_cache, page - 1);
+		ev_document_model_set_page (view->model, page - 1);
 		return TRUE;
 	} else {
 		return FALSE;
@@ -6437,7 +6464,7 @@ ev_view_previous_page (EvView *view)
 
 	g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
 
-	if (!view->page_cache)
+	if (!view->document)
 		return FALSE;
 
 	if (view->presentation &&
@@ -6459,7 +6486,7 @@ ev_view_previous_page (EvView *view)
 
 	ev_view_reset_presentation_state (view);
 
-	page = ev_page_cache_get_current_page (view->page_cache);
+	page = ev_document_model_get_page (view->model);
 
 	if (view->dual_page && !view->presentation)
 	        page = page - 2; 
@@ -6467,10 +6494,10 @@ ev_view_previous_page (EvView *view)
 		page = page - 1;
 
 	if (page >= 0) {
-		ev_page_cache_set_current_page (view->page_cache, page);
+		ev_document_model_set_page (view->model, page);
 		return TRUE;
 	} else if (ev_view_get_dual_page (view) && page == -1) {
-		ev_page_cache_set_current_page (view->page_cache, 0);
+		ev_document_model_set_page (view->model, 0);
 		return TRUE;
 	} else {	
 		return FALSE;
diff --git a/libview/ev-view.h b/libview/ev-view.h
index d9b5127..53bc7c8 100644
--- a/libview/ev-view.h
+++ b/libview/ev-view.h
@@ -28,6 +28,8 @@
 
 #include <evince-document.h>
 
+#include "ev-document-model.h"
+
 G_BEGIN_DECLS
 
 #define EV_TYPE_VIEW            (ev_view_get_type ())
@@ -37,13 +39,6 @@ G_BEGIN_DECLS
 typedef struct _EvView       EvView;
 typedef struct _EvViewClass  EvViewClass;
 
-
-typedef enum {
-	EV_SIZING_BEST_FIT,
-	EV_SIZING_FIT_WIDTH,
-	EV_SIZING_FREE,
-} EvSizingMode;
-
 typedef enum {
 	EV_VIEW_SELECTION_TEXT,
 	EV_VIEW_SELECTION_RECTANGLE,
@@ -52,8 +47,8 @@ typedef enum {
 GType		ev_view_get_type	  (void) G_GNUC_CONST;
 
 GtkWidget*	ev_view_new		  (void);
-void		ev_view_set_document	  (EvView         *view,
-			   		   EvDocument     *document);
+void		ev_view_set_model	  (EvView         *view,
+			   		   EvDocumentModel *model);
 void 		ev_view_set_loading       (EvView 	  *view,
 				           gboolean        loading);
 void            ev_view_reload            (EvView         *view);
@@ -92,8 +87,7 @@ void		ev_view_zoom_in		  (EvView         *view);
 gboolean        ev_view_can_zoom_out      (EvView         *view);
 void		ev_view_zoom_out	  (EvView         *view);
 void		ev_view_set_zoom	  (EvView         *view,
-					   double          factor,
-					   gboolean        relative);
+					   double          factor);
 double		ev_view_get_zoom	  (EvView         *view);
 void            ev_view_set_screen_dpi    (EvView         *view,
 					   gdouble         dpi);
diff --git a/previewer/ev-previewer-window.c b/previewer/ev-previewer-window.c
index c406a22..08eb895 100644
--- a/previewer/ev-previewer-window.c
+++ b/previewer/ev-previewer-window.c
@@ -32,6 +32,7 @@
 struct _EvPreviewerWindow {
 	GtkWindow         base_instance;
 
+	EvDocumentModel  *model;
 	EvDocument       *document;
 
 	GtkActionGroup   *action_group;
@@ -55,6 +56,14 @@ struct _EvPreviewerWindowClass {
 	GtkWindowClass base_class;
 };
 
+enum {
+	PROP_0,
+	PROP_MODEL
+};
+
+#define MIN_SCALE 0.05409
+#define MAX_SCALE 4.0
+
 G_DEFINE_TYPE (EvPreviewerWindow, ev_previewer_window, GTK_TYPE_WINDOW)
 
 static gdouble
@@ -109,7 +118,7 @@ static void
 ev_previewer_window_zoom_in (GtkAction         *action,
 			     EvPreviewerWindow *window)
 {
-	ev_view_set_sizing_mode (window->view, EV_SIZING_FREE);
+	ev_document_model_set_sizing_mode (window->model, EV_SIZING_FREE);
 	ev_view_zoom_in (window->view);
 }
 
@@ -117,7 +126,7 @@ static void
 ev_previewer_window_zoom_out (GtkAction         *action,
 			      EvPreviewerWindow *window)
 {
-	ev_view_set_sizing_mode (window->view, EV_SIZING_FREE);
+	ev_document_model_set_sizing_mode (window->model, EV_SIZING_FREE);
 	ev_view_zoom_out (window->view);
 }
 
@@ -125,22 +134,18 @@ static void
 ev_previewer_window_zoom_best_fit (GtkToggleAction   *action,
 				   EvPreviewerWindow *window)
 {
-	if (gtk_toggle_action_get_active (action)) {
-		ev_view_set_sizing_mode (window->view, EV_SIZING_BEST_FIT);
-	} else {
-		ev_view_set_sizing_mode (window->view, EV_SIZING_FREE);
-	}
+	ev_document_model_set_sizing_mode (window->model,
+					   gtk_toggle_action_get_active (action) ?
+					   EV_SIZING_BEST_FIT : EV_SIZING_FREE);
 }
 
 static void
 ev_previewer_window_zoom_page_width (GtkToggleAction   *action,
 				     EvPreviewerWindow *window)
 {
-	if (gtk_toggle_action_get_active (action)) {
-		ev_view_set_sizing_mode (window->view, EV_SIZING_FIT_WIDTH);
-	} else {
-		ev_view_set_sizing_mode (window->view, EV_SIZING_FREE);
-	}
+	ev_document_model_set_sizing_mode (window->model,
+					   gtk_toggle_action_get_active (action) ?
+					   EV_SIZING_FIT_WIDTH : EV_SIZING_FREE);
 }
 
 static void
@@ -273,22 +278,14 @@ static const GtkToggleActionEntry toggle_action_entries[] = {
 	  G_CALLBACK (ev_previewer_window_zoom_page_width) }
 };
 
-/* EvView callbacks */
 static void
-view_sizing_mode_changed (EvView            *view,
+view_sizing_mode_changed (EvDocumentModel   *model,
 			  GParamSpec        *pspec,
 			  EvPreviewerWindow *window)
 {
-	EvSizingMode sizing_mode;
+	EvSizingMode sizing_mode = ev_document_model_get_sizing_mode (model);
 	GtkAction   *action;
 
-	if (!window->view)
-		return;
-
-	g_object_get (window->view,
-		      "sizing_mode", &sizing_mode,
-		      NULL);
-
 	action = gtk_action_group_get_action (window->action_group, "ViewBestFit");
 	g_signal_handlers_block_by_func (action,
 					 G_CALLBACK (ev_previewer_window_zoom_best_fit),
@@ -311,10 +308,31 @@ view_sizing_mode_changed (EvView            *view,
 }
 
 static void
+ev_previewer_window_set_document (EvPreviewerWindow *window,
+				  GParamSpec        *pspec,
+				  EvDocumentModel   *model)
+{
+	EvDocument *document = ev_document_model_get_document (model);
+
+	window->document = g_object_ref (document);
+
+	g_signal_connect (model, "notify::sizing-mode",
+			  G_CALLBACK (view_sizing_mode_changed),
+			  window);
+	ev_view_set_loading (window->view, FALSE);
+	gtk_action_group_set_sensitive (window->action_group, TRUE);
+}
+
+static void
 ev_previewer_window_dispose (GObject *object)
 {
 	EvPreviewerWindow *window = EV_PREVIEWER_WINDOW (object);
 
+	if (window->model) {
+		g_object_unref (window->model);
+		window->model = NULL;
+	}
+
 	if (window->document) {
 		g_object_unref (window->document);
 		window->document = NULL;
@@ -380,14 +398,55 @@ data_dir (void)
 static void
 ev_previewer_window_init (EvPreviewerWindow *window)
 {
-	GtkWidget *vbox;
-	GtkWidget *toolbar;
-	GtkAction *action;
-	GError    *error = NULL;
-	gchar     *datadir, *ui_path;
-
 	gtk_window_set_default_size (GTK_WINDOW (window), 600, 600);
-	
+}
+
+static void
+ev_previewer_window_set_property (GObject      *object,
+				  guint         prop_id,
+				  const GValue *value,
+				  GParamSpec   *pspec)
+{
+	EvPreviewerWindow *window = EV_PREVIEWER_WINDOW (object);
+
+	switch (prop_id) {
+	case PROP_MODEL:
+		window->model = g_value_dup_object (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	}
+}
+
+static GObject *
+ev_previewer_window_constructor (GType                  type,
+				 guint                  n_construct_properties,
+				 GObjectConstructParam *construct_params)
+{
+	GObject           *object;
+	EvPreviewerWindow *window;
+	GtkWidget         *vbox;
+	GtkWidget         *toolbar;
+	GtkAction         *action;
+	GError            *error = NULL;
+	gchar             *datadir, *ui_path;
+	gdouble            dpi;
+
+	g_print ("DBG: constructor\n");
+
+	object = G_OBJECT_CLASS (ev_previewer_window_parent_class)->constructor (type,
+										 n_construct_properties,
+										 construct_params);
+	window = EV_PREVIEWER_WINDOW (object);
+
+	dpi = get_screen_dpi (GTK_WINDOW (window));
+	ev_document_model_set_min_scale (window->model, MIN_SCALE * dpi / 72.0);
+	ev_document_model_set_max_scale (window->model, MAX_SCALE * dpi / 72.0);
+	ev_document_model_set_sizing_mode (window->model, EV_SIZING_FIT_WIDTH);
+	g_signal_connect_swapped (window->model, "notify::document",
+				  G_CALLBACK (ev_previewer_window_set_document),
+				  window);
+
 	window->action_group = gtk_action_group_new ("PreviewerActions");
 	gtk_action_group_set_translation_domain (window->action_group, NULL);
 	gtk_action_group_add_actions (window->action_group, action_entries,
@@ -405,6 +464,7 @@ ev_previewer_window_init (EvPreviewerWindow *window)
 			       "icon_name", "text-x-generic",
 			       "visible_overflown", FALSE,
 			       NULL);
+	ev_page_action_set_model (EV_PAGE_ACTION (action), window->model);
 	g_signal_connect (action, "activate_link",
 			  G_CALLBACK (ev_previewer_window_action_page_activated),
 			  window);
@@ -425,75 +485,61 @@ ev_previewer_window_init (EvPreviewerWindow *window)
 	g_free (ui_path);
 	g_free (datadir);
 
+	view_sizing_mode_changed (window->model, NULL, window);
+
 	vbox = gtk_vbox_new (FALSE, 0);
 
 	toolbar = gtk_ui_manager_get_widget (window->ui_manager, "/PreviewToolbar");
 	gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
 	gtk_widget_show (toolbar);
-		
+
 	window->swindow = gtk_scrolled_window_new (NULL, NULL);
 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (window->swindow),
 					GTK_POLICY_AUTOMATIC,
 					GTK_POLICY_AUTOMATIC);
-	
-	window->view = EV_VIEW (ev_view_new ());
-	g_signal_connect (window->view, "notify::sizing-mode",
-			  G_CALLBACK (view_sizing_mode_changed),
-			  window);
 
-	ev_view_set_screen_dpi (window->view, get_screen_dpi (GTK_WINDOW (window)));
+	window->view = EV_VIEW (ev_view_new ());
+	ev_view_set_model (window->view, window->model);
 	ev_view_set_continuous (window->view, FALSE);
-	ev_view_set_sizing_mode (window->view, EV_SIZING_FIT_WIDTH);
 	ev_view_set_loading (window->view, TRUE);
-	view_sizing_mode_changed (window->view, NULL, window);
 
 	gtk_container_add (GTK_CONTAINER (window->swindow), GTK_WIDGET (window->view));
 	gtk_widget_show (GTK_WIDGET (window->view));
 
 	gtk_box_pack_start (GTK_BOX (vbox), window->swindow, TRUE, TRUE, 0);
 	gtk_widget_show (window->swindow);
-	
+
 	gtk_container_add (GTK_CONTAINER (window), vbox);
 	gtk_widget_show (vbox);
+
+	return object;
 }
 
+
 static void
 ev_previewer_window_class_init (EvPreviewerWindowClass *klass)
 {
 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+	gobject_class->constructor = ev_previewer_window_constructor;
+	gobject_class->set_property = ev_previewer_window_set_property;
 	gobject_class->dispose = ev_previewer_window_dispose;
+
+	g_object_class_install_property (gobject_class,
+					 PROP_MODEL,
+					 g_param_spec_object ("model",
+							      "Model",
+							      "The document model",
+							      EV_TYPE_DOCUMENT_MODEL,
+							      G_PARAM_WRITABLE |
+							      G_PARAM_CONSTRUCT_ONLY));
 }
 
 /* Public methods */
 GtkWidget *
-ev_previewer_window_new (void)
+ev_previewer_window_new (EvDocumentModel *model)
 {
-	return GTK_WIDGET (g_object_new (EV_TYPE_PREVIEWER_WINDOW, NULL));
-}
-
-void
-ev_previewer_window_set_document (EvPreviewerWindow *window,
-				  EvDocument        *document)
-{
-	GtkAction *action;
-	
-	g_return_if_fail (EV_IS_PREVIEWER_WINDOW (window));
-	g_return_if_fail (EV_IS_DOCUMENT (document));
-	
-	if (window->document)
-		return;
-
-	action = gtk_action_group_get_action (window->action_group, "PageSelector");
-	ev_page_action_set_document (EV_PAGE_ACTION (action), document);
-	gtk_action_group_set_sensitive (window->action_group, TRUE);
-	
-	window->document = g_object_ref (document);
-	ev_view_set_document (window->view, document);
-	ev_view_set_zoom (window->view,
-			  get_screen_dpi (GTK_WINDOW (window)) / 72.0,
-			  FALSE);
-	ev_view_set_loading (window->view, FALSE);
+	return GTK_WIDGET (g_object_new (EV_TYPE_PREVIEWER_WINDOW, "model", model, NULL));
 }
 
 void
diff --git a/previewer/ev-previewer-window.h b/previewer/ev-previewer-window.h
index aba56d7..8d8217b 100644
--- a/previewer/ev-previewer-window.h
+++ b/previewer/ev-previewer-window.h
@@ -24,6 +24,7 @@
 #include <gtk/gtk.h>
 
 #include <evince-document.h>
+#include <evince-view.h>
 
 G_BEGIN_DECLS
 
@@ -38,10 +39,8 @@ typedef struct _EvPreviewerWindow      EvPreviewerWindow;
 typedef struct _EvPreviewerWindowClass EvPreviewerWindowClass;
 
 GType      ev_previewer_window_get_type           (void) G_GNUC_CONST;
-GtkWidget *ev_previewer_window_new                (void);
+GtkWidget *ev_previewer_window_new                (EvDocumentModel   *model);
 
-void       ev_previewer_window_set_document       (EvPreviewerWindow *window,
-						   EvDocument        *document);
 void       ev_previewer_window_set_print_settings (EvPreviewerWindow *window,
 						   const gchar       *print_settings);
 void       ev_previewer_window_set_source_file    (EvPreviewerWindow *window,
diff --git a/previewer/ev-previewer.c b/previewer/ev-previewer.c
index 5c1980a..7a83eee 100644
--- a/previewer/ev-previewer.c
+++ b/previewer/ev-previewer.c
@@ -65,8 +65,8 @@ ev_previewer_unlink_tempfile (const gchar *filename)
 }
 
 static void
-ev_previewer_load_job_finished (EvJob             *job,
-				EvPreviewerWindow *window)
+ev_previewer_load_job_finished (EvJob           *job,
+				EvDocumentModel *model)
 {
 	if (ev_job_is_failed (job)) {
 		g_warning ("%s", job->error->message);
@@ -74,14 +74,13 @@ ev_previewer_load_job_finished (EvJob             *job,
 
 		return;
 	}
-
-	ev_previewer_window_set_document (window, job->document);
+	ev_document_model_set_document (model, job->document);
 	g_object_unref (job);
 }
 
 static void
-ev_previewer_load_document (const gchar       *filename,
-			    EvPreviewerWindow *window)
+ev_previewer_load_document (const gchar     *filename,
+			    EvDocumentModel *model)
 {
 	EvJob *job;
 	gchar *uri;
@@ -90,7 +89,7 @@ ev_previewer_load_document (const gchar       *filename,
 	job = ev_job_load_new (uri);
 	g_signal_connect (job, "finished",
 			  G_CALLBACK (ev_previewer_load_job_finished),
-			  window);
+			  model);
 	ev_job_scheduler_push_job (job, EV_JOB_PRIORITY_NONE);
 	g_free (uri);
 }
@@ -98,10 +97,11 @@ ev_previewer_load_document (const gchar       *filename,
 gint
 main (gint argc, gchar **argv)
 {
-	GtkWidget      *window;
-	GOptionContext *context;
-	const gchar    *filename;
-	GError         *error = NULL;
+	GtkWidget       *window;
+	GOptionContext  *context;
+	const gchar     *filename;
+	EvDocumentModel *model;
+	GError          *error = NULL;
 
 #ifdef G_OS_WIN32
     if (fileno (stdout) != -1 &&
@@ -175,7 +175,8 @@ main (gint argc, gchar **argv)
 	g_set_application_name (_("GNOME Document Previewer"));
 	gtk_window_set_default_icon_name ("evince");
 
-	window = ev_previewer_window_new ();
+	model = ev_document_model_new ();
+	window = ev_previewer_window_new (model);
 	ev_previewer_window_set_source_file (EV_PREVIEWER_WINDOW (window), filename);
 	ev_previewer_window_set_print_settings (EV_PREVIEWER_WINDOW (window), print_settings);
 	g_signal_connect (window, "delete-event",
@@ -184,7 +185,7 @@ main (gint argc, gchar **argv)
 			  G_CALLBACK (gtk_main_quit), NULL);
 	gtk_widget_show (window);
 
-	ev_previewer_load_document (filename, EV_PREVIEWER_WINDOW (window));
+	ev_previewer_load_document (filename, model);
 	
 	gtk_main ();
 
@@ -195,6 +196,7 @@ main (gint argc, gchar **argv)
 
 	ev_shutdown ();
 	ev_stock_icons_shutdown ();
+	g_object_unref (model);
 	
 	return 0;
 }
diff --git a/shell/ev-print-operation.c b/shell/ev-print-operation.c
index fe5ef54..eb0f9be 100644
--- a/shell/ev-print-operation.c
+++ b/shell/ev-print-operation.c
@@ -28,7 +28,6 @@
 #include <glib/gstdio.h>
 #include <unistd.h>
 
-#include "ev-page-cache.h"
 #include "ev-file-exporter.h"
 #include "ev-jobs.h"
 #include "ev-job-scheduler.h"
diff --git a/shell/ev-properties-dialog.c b/shell/ev-properties-dialog.c
index 0ca4661..b19408e 100644
--- a/shell/ev-properties-dialog.c
+++ b/shell/ev-properties-dialog.c
@@ -26,7 +26,6 @@
 #include <gtk/gtk.h>
 
 #include "ev-document-fonts.h"
-#include "ev-page-cache.h"
 #include "ev-properties-dialog.h"
 #include "ev-properties-fonts.h"
 #include "ev-properties-view.h"
diff --git a/shell/ev-sidebar-attachments.c b/shell/ev-sidebar-attachments.c
index b63c5ef..d89617b 100644
--- a/shell/ev-sidebar-attachments.c
+++ b/shell/ev-sidebar-attachments.c
@@ -651,13 +651,21 @@ job_finished_callback (EvJobAttachments     *job,
 	g_object_unref (job);
 }
 
+
 static void
-ev_sidebar_attachments_set_document (EvSidebarPage   *page,
-				     EvDocument      *document)
+ev_sidebar_attachments_document_changed_cb (EvDocumentModel      *model,
+					    GParamSpec           *pspec,
+					    EvSidebarAttachments *ev_attachbar)
 {
-	EvSidebarAttachments *ev_attachbar = EV_SIDEBAR_ATTACHMENTS (page);
+	EvDocument *document = ev_document_model_get_document (model);
 	EvJob *job;
 
+	if (!EV_IS_DOCUMENT_ATTACHMENTS (document))
+		return;
+
+	if (!ev_document_attachments_has_attachments (EV_DOCUMENT_ATTACHMENTS (document)))
+		return;
+
 	if (!ev_attachbar->priv->icon_theme) {
 		GdkScreen *screen;
 
@@ -682,6 +690,15 @@ ev_sidebar_attachments_set_document (EvSidebarPage   *page,
 	ev_job_scheduler_push_job (job, EV_JOB_PRIORITY_NONE);
 }
 
+static void
+ev_sidebar_attachments_set_model (EvSidebarPage   *page,
+				  EvDocumentModel *model)
+{
+	g_signal_connect (model, "notify::document",
+			  G_CALLBACK (ev_sidebar_attachments_document_changed_cb),
+			  page);
+}
+
 static gboolean
 ev_sidebar_attachments_support_document (EvSidebarPage   *sidebar_page,
 					 EvDocument      *document)
@@ -700,7 +717,7 @@ static void
 ev_sidebar_attachments_page_iface_init (EvSidebarPageIface *iface)
 {
 	iface->support_document = ev_sidebar_attachments_support_document;
-	iface->set_document = ev_sidebar_attachments_set_document;
+	iface->set_model = ev_sidebar_attachments_set_model;
 	iface->get_label = ev_sidebar_attachments_get_label;
 }
 
diff --git a/shell/ev-sidebar-layers.c b/shell/ev-sidebar-layers.c
index cebd96d..5f16895 100644
--- a/shell/ev-sidebar-layers.c
+++ b/shell/ev-sidebar-layers.c
@@ -346,18 +346,15 @@ job_finished_callback (EvJobLayers     *job,
 }
 
 static void
-ev_sidebar_layers_set_document (EvSidebarPage  *sidebar_page,
-				EvDocument     *document)
+ev_sidebar_layers_document_changed_cb (EvDocumentModel *model,
+				       GParamSpec      *pspec,
+				       EvSidebarLayers *sidebar_layers)
 {
-	EvSidebarLayers *sidebar_layers;
-	EvSidebarLayersPrivate *priv;
-
-	g_return_if_fail (EV_IS_SIDEBAR_PAGE (sidebar_page));
-	g_return_if_fail (EV_IS_DOCUMENT (document));
-	
-	sidebar_layers = EV_SIDEBAR_LAYERS (sidebar_page);
+	EvDocument *document = ev_document_model_get_document (model);
+	EvSidebarLayersPrivate *priv = sidebar_layers->priv;
 
-	priv = sidebar_layers->priv;
+	if (!EV_IS_DOCUMENT_LAYERS (document))
+		return;
 
 	if (priv->document) {
 		gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), NULL);
@@ -381,6 +378,15 @@ ev_sidebar_layers_set_document (EvSidebarPage  *sidebar_page,
 	ev_job_scheduler_push_job (priv->job, EV_JOB_PRIORITY_NONE);
 }
 
+static void
+ev_sidebar_layers_set_model (EvSidebarPage   *sidebar_page,
+			     EvDocumentModel *model)
+{
+	g_signal_connect (model, "notify::document",
+			  G_CALLBACK (ev_sidebar_layers_document_changed_cb),
+			  sidebar_page);
+}
+
 static gboolean
 ev_sidebar_layers_support_document (EvSidebarPage *sidebar_page,
 				    EvDocument    *document)
@@ -399,7 +405,7 @@ static void
 ev_sidebar_layers_page_iface_init (EvSidebarPageIface *iface)
 {
 	iface->support_document = ev_sidebar_layers_support_document;
-	iface->set_document = ev_sidebar_layers_set_document;
+	iface->set_model = ev_sidebar_layers_set_model;
 	iface->get_label = ev_sidebar_layers_get_label;
 }
 
diff --git a/shell/ev-sidebar-links.c b/shell/ev-sidebar-links.c
index 8993e5f..6eb7e23 100644
--- a/shell/ev-sidebar-links.c
+++ b/shell/ev-sidebar-links.c
@@ -46,7 +46,7 @@ struct _EvSidebarLinksPrivate {
 	EvJob *job;
 	GtkTreeModel *model;
 	EvDocument *document;
-	EvPageCache *page_cache;
+	EvDocumentModel *doc_model;
 };
 
 enum {
@@ -60,18 +60,20 @@ enum {
 	N_SIGNALS
 };
 
-static void update_page_callback 			(EvPageCache       *page_cache,
-							 gint               current_page,
-						         EvSidebarLinks    *sidebar_links);
+static void update_page_callback 			(EvSidebarLinks    *sidebar_links,
+							 gint               old_page,
+							 gint               current_page);
 static void row_activated_callback 			(GtkTreeView *treeview,
 		                                         GtkTreePath *arg1,
 	                                                 GtkTreeViewColumn *arg2,
 		                                         gpointer user_data);
+static void ev_sidebar_links_set_links_model            (EvSidebarLinks *links,
+							 GtkTreeModel   *model);
 static void job_finished_callback 			(EvJobLinks     *job,
 				    		         EvSidebarLinks *sidebar_links);
+static void ev_sidebar_links_set_current_page           (EvSidebarLinks *sidebar_links,
+							 gint            current_page);
 static void ev_sidebar_links_page_iface_init 		(EvSidebarPageIface *iface);
-static void ev_sidebar_links_set_document      	 	(EvSidebarPage  *sidebar_page,
-		    			        	 EvDocument     *document);
 static gboolean ev_sidebar_links_support_document	(EvSidebarPage  *sidebar_page,
 						         EvDocument     *document);
 static const gchar* ev_sidebar_links_get_label 		(EvSidebarPage *sidebar_page);
@@ -95,18 +97,12 @@ ev_sidebar_links_set_property (GObject      *object,
 			       const GValue *value,
 			       GParamSpec   *pspec)
 {
-	EvSidebarLinks *ev_sidebar_links;
-	GtkTreeModel *model;
-  
-	ev_sidebar_links = EV_SIDEBAR_LINKS (object);
+	EvSidebarLinks *ev_sidebar_links = EV_SIDEBAR_LINKS (object);
 
 	switch (prop_id)
 	{
 	case PROP_MODEL:
-		model = ev_sidebar_links->priv->model;
-		ev_sidebar_links->priv->model = GTK_TREE_MODEL (g_value_dup_object (value));
-		if (model)
-			g_object_unref (model);
+		ev_sidebar_links_set_links_model (ev_sidebar_links, g_value_get_object (value));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -159,7 +155,7 @@ ev_sidebar_links_dispose (GObject *object)
 	if (sidebar->priv->document) {
 		g_object_unref (sidebar->priv->document);
 		sidebar->priv->document = NULL;
-		sidebar->priv->page_cache = NULL;
+		sidebar->priv->doc_model = NULL;
 	}
 
 	G_OBJECT_CLASS (ev_sidebar_links_parent_class)->dispose (object);
@@ -175,9 +171,8 @@ ev_sidebar_links_map (GtkWidget *widget)
 	GTK_WIDGET_CLASS (ev_sidebar_links_parent_class)->map (widget);
 
 	if (links->priv->model) {
-		update_page_callback (links->priv->page_cache,
-				      ev_page_cache_get_current_page (links->priv->page_cache),
-				      links);
+		ev_sidebar_links_set_current_page (links,
+						   ev_document_model_get_page (links->priv->doc_model));
 	}
 }
 
@@ -239,10 +234,10 @@ selection_changed_callback (GtkTreeSelection   *selection,
 		if (link == NULL)
 			return;
 
-		g_signal_handler_block (ev_sidebar_links->priv->page_cache,
+		g_signal_handler_block (ev_sidebar_links->priv->doc_model,
 					ev_sidebar_links->priv->page_changed_id);
 		g_signal_emit (ev_sidebar_links, signals[LINK_ACTIVATED], 0, link);
-		g_signal_handler_unblock (ev_sidebar_links->priv->page_cache,
+		g_signal_handler_unblock (ev_sidebar_links->priv->doc_model,
 					  ev_sidebar_links->priv->page_changed_id);
 
 		g_object_unref (link);
@@ -523,7 +518,7 @@ update_page_callback_foreach (GtkTreeModel *model,
 		dest_page = ev_link_get_page (link);
 		g_object_unref (link);
 		
-		current_page = ev_page_cache_get_current_page (sidebar_links->priv->page_cache);
+		current_page = ev_document_model_get_page (sidebar_links->priv->doc_model);
 			 
 		if (dest_page == current_page) {
 			gtk_tree_view_expand_to_path (GTK_TREE_VIEW (sidebar_links->priv->tree_view),
@@ -539,9 +534,8 @@ update_page_callback_foreach (GtkTreeModel *model,
 }
 
 static void
-update_page_callback (EvPageCache    *page_cache,
-		      gint            current_page,
-		      EvSidebarLinks *sidebar_links)
+ev_sidebar_links_set_current_page (EvSidebarLinks *sidebar_links,
+				   gint            current_page)
 {
 	GtkTreeSelection *selection;
 	GtkTreeModel *model;
@@ -586,6 +580,14 @@ update_page_callback (EvPageCache    *page_cache,
 	g_signal_handler_unblock (sidebar_links->priv->tree_view, sidebar_links->priv->row_activated_id);
 }
 
+static void
+update_page_callback (EvSidebarLinks *sidebar_links,
+		      gint            old_page,
+		      gint            new_page)
+{
+	ev_sidebar_links_set_current_page (sidebar_links, new_page);
+}
+
 static void 
 row_activated_callback (GtkTreeView       *treeview,
 			GtkTreePath       *arg1,
@@ -622,19 +624,32 @@ expand_open_links (GtkTreeView *tree_view, GtkTreeModel *model, GtkTreeIter *par
 		} while (gtk_tree_model_iter_next (model, &iter));
 	}
 }
-	
+
+static void
+ev_sidebar_links_set_links_model (EvSidebarLinks *sidebar_links,
+				  GtkTreeModel   *model)
+{
+	EvSidebarLinksPrivate *priv = sidebar_links->priv;
+
+	if (priv->model == model)
+		return;
+
+	if (priv->model)
+		g_object_unref (priv->model);
+	priv->model = g_object_ref (model);
+
+	g_object_notify (G_OBJECT (sidebar_links), "model");
+}
+
 static void
 job_finished_callback (EvJobLinks     *job,
 		       EvSidebarLinks *sidebar_links)
 {
-	EvSidebarLinksPrivate *priv;
+	EvSidebarLinksPrivate *priv = sidebar_links->priv;
 	GtkTreeSelection *selection;
 
-	priv = sidebar_links->priv;
-	
-	priv->model = job->model;
-	g_object_notify (G_OBJECT (sidebar_links), "model");
-	
+	ev_sidebar_links_set_links_model (sidebar_links, job->model);
+
 	gtk_tree_model_foreach (priv->model, (GtkTreeModelForeachFunc)fill_page_labels, sidebar_links);
 
 	gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), job->model);
@@ -653,34 +668,34 @@ job_finished_callback (EvJobLinks     *job,
 					  G_CALLBACK (selection_changed_callback),
 					  sidebar_links);
 	}
-	priv->page_changed_id =	g_signal_connect (priv->page_cache, "page-changed",
-						  G_CALLBACK (update_page_callback),
-						  sidebar_links);
+	priv->page_changed_id =
+		g_signal_connect_swapped (priv->doc_model, "page-changed",
+					  G_CALLBACK (update_page_callback),
+					  sidebar_links);
 	if (priv->row_activated_id <= 0) {
 		priv->row_activated_id =
 			g_signal_connect (priv->tree_view, "row-activated",
 					  G_CALLBACK (row_activated_callback),
 					  sidebar_links);
 	}
-	
-	update_page_callback (priv->page_cache,
-			      ev_page_cache_get_current_page (priv->page_cache),
-			      sidebar_links);
+
+	ev_sidebar_links_set_current_page (sidebar_links,
+					   ev_document_model_get_page (priv->doc_model));
 }
 
 static void
-ev_sidebar_links_set_document (EvSidebarPage  *sidebar_page,
-			       EvDocument     *document)
+ev_sidebar_links_document_changed_cb (EvDocumentModel *model,
+				      GParamSpec      *pspec,
+				      EvSidebarLinks  *sidebar_links)
 {
-	EvSidebarLinks *sidebar_links;
-	EvSidebarLinksPrivate *priv;
+	EvDocument *document = ev_document_model_get_document (model);
+	EvSidebarLinksPrivate *priv = sidebar_links->priv;
 
-	g_return_if_fail (EV_IS_SIDEBAR_PAGE (sidebar_page));
-	g_return_if_fail (EV_IS_DOCUMENT (document));
-	
-	sidebar_links = EV_SIDEBAR_LINKS (sidebar_page);
+	if (!EV_IS_DOCUMENT_LINKS (document))
+		return;
 
-	priv = sidebar_links->priv;
+	if (!ev_document_links_has_document_links (EV_DOCUMENT_LINKS (document)))
+		return;
 
 	if (priv->document) {
 		gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), NULL);
@@ -688,7 +703,6 @@ ev_sidebar_links_set_document (EvSidebarPage  *sidebar_page,
 	}
 
 	priv->document = g_object_ref (document);
-	priv->page_cache = ev_page_cache_get (document);
 
 	if (priv->job) {
 		g_signal_handlers_disconnect_by_func (priv->job,
@@ -706,6 +720,22 @@ ev_sidebar_links_set_document (EvSidebarPage  *sidebar_page,
 	ev_job_scheduler_push_job (priv->job, EV_JOB_PRIORITY_NONE);
 }
 
+static void
+ev_sidebar_links_set_model (EvSidebarPage   *sidebar_page,
+			    EvDocumentModel *model)
+{
+	EvSidebarLinks *sidebar_links = EV_SIDEBAR_LINKS (sidebar_page);
+	EvSidebarLinksPrivate *priv = sidebar_links->priv;
+
+	if (priv->doc_model == model)
+		return;
+
+	priv->doc_model = model;
+	g_signal_connect (model, "notify::document",
+			  G_CALLBACK (ev_sidebar_links_document_changed_cb),
+			  sidebar_page);
+}
+
 static gboolean
 ev_sidebar_links_support_document (EvSidebarPage  *sidebar_page,
 				   EvDocument *document)
@@ -724,7 +754,7 @@ static void
 ev_sidebar_links_page_iface_init (EvSidebarPageIface *iface)
 {
 	iface->support_document = ev_sidebar_links_support_document;
-	iface->set_document = ev_sidebar_links_set_document;
+	iface->set_model = ev_sidebar_links_set_model;
 	iface->get_label = ev_sidebar_links_get_label;
 }
 
diff --git a/shell/ev-sidebar-page.c b/shell/ev-sidebar-page.c
index 14bb847..e0cf814 100644
--- a/shell/ev-sidebar-page.c
+++ b/shell/ev-sidebar-page.c
@@ -39,25 +39,25 @@ ev_sidebar_page_support_document (EvSidebarPage *sidebar_page,
 
 	iface = EV_SIDEBAR_PAGE_GET_IFACE (sidebar_page);
 
-        g_return_val_if_fail (iface->set_document, FALSE);
+        g_return_val_if_fail (iface->support_document, FALSE);
 	
         return iface->support_document (sidebar_page, document);    
 }
 
-void 
-ev_sidebar_page_set_document (EvSidebarPage *sidebar_page,
-			      EvDocument    *document)
+void
+ev_sidebar_page_set_model (EvSidebarPage   *sidebar_page,
+			   EvDocumentModel *model)
 {
 	EvSidebarPageIface *iface;
 
         g_return_if_fail (EV_IS_SIDEBAR_PAGE (sidebar_page));
-	g_return_if_fail (EV_IS_DOCUMENT (document));
+	g_return_if_fail (EV_IS_DOCUMENT_MODEL (model));
 
 	iface = EV_SIDEBAR_PAGE_GET_IFACE (sidebar_page);
 
-	g_assert (iface->set_document);
-	
-	iface->set_document (sidebar_page, document);
+	g_assert (iface->set_model);
+
+	iface->set_model (sidebar_page, model);
 }
 
 const gchar *
diff --git a/shell/ev-sidebar-page.h b/shell/ev-sidebar-page.h
index 3739a07..a3c0f13 100644
--- a/shell/ev-sidebar-page.h
+++ b/shell/ev-sidebar-page.h
@@ -25,6 +25,7 @@
 #include <glib.h>
 
 #include "ev-document.h"
+#include "ev-document-model.h"
 
 G_BEGIN_DECLS
 
@@ -45,16 +46,16 @@ struct _EvSidebarPageIface
 	/* Methods  */
 	gboolean    (* support_document)  (EvSidebarPage   *sidebar_page,
 				           EvDocument *document);
-	void 	    (* set_document)	  (EvSidebarPage   *sidebar_page,
-					   EvDocument *document);
-	const gchar*(* get_label)         (EvSidebarPage  *sidebar_page);	
+	void 	    (* set_model)	  (EvSidebarPage   *sidebar_page,
+					   EvDocumentModel *model);
+	const gchar*(* get_label)         (EvSidebarPage  *sidebar_page);
 };
 
-GType         ev_sidebar_page_get_type          (void);
+GType         ev_sidebar_page_get_type          (void) G_GNUC_CONST;
 gboolean      ev_sidebar_page_support_document  (EvSidebarPage    *sidebar_page,
 	 			                 EvDocument *document);
-void          ev_sidebar_page_set_document      (EvSidebarPage    *sidebar_page,
-				                 EvDocument *document);
+void          ev_sidebar_page_set_model         (EvSidebarPage    *sidebar_page,
+				                 EvDocumentModel *model);
 const gchar*  ev_sidebar_page_get_label         (EvSidebarPage *page);
 
 
diff --git a/shell/ev-sidebar-thumbnails.c b/shell/ev-sidebar-thumbnails.c
index 7137fa1..e104c3e 100644
--- a/shell/ev-sidebar-thumbnails.c
+++ b/shell/ev-sidebar-thumbnails.c
@@ -66,7 +66,7 @@ struct _EvSidebarThumbnailsPrivate {
 	GtkListStore *list_store;
 	GHashTable *loading_icons;
 	EvDocument *document;
-	EvPageCache *page_cache;
+	EvDocumentModel *model;
 	EvThumbsSizeCache *size_cache;
 
 	gint n_pages, pages_done;
@@ -94,8 +94,6 @@ static void         ev_sidebar_thumbnails_clear_model      (EvSidebarThumbnails
 static gboolean     ev_sidebar_thumbnails_support_document (EvSidebarPage       *sidebar_page,
 							    EvDocument          *document);
 static void         ev_sidebar_thumbnails_page_iface_init  (EvSidebarPageIface  *iface);
-static void         ev_sidebar_thumbnails_set_document     (EvSidebarPage       *sidebar_page,
-							    EvDocument          *document);
 static const gchar* ev_sidebar_thumbnails_get_label        (EvSidebarPage       *sidebar_page);
 static void         thumbnail_job_completed_callback       (EvJobThumbnail      *job,
 							    EvSidebarThumbnails *sidebar_thumbnails);
@@ -585,34 +583,6 @@ ev_sidebar_thumbnails_fill_model (EvSidebarThumbnails *sidebar_thumbnails)
 	}
 }
 
-static gboolean
-refresh (EvSidebarThumbnails *sidebar_thumbnails)
-{
-	adjustment_changed_cb (sidebar_thumbnails);
-	return FALSE;
-}
-
-void
-ev_sidebar_thumbnails_refresh (EvSidebarThumbnails *sidebar_thumbnails,
-			       int                  rotation)
-{
-	sidebar_thumbnails->priv->rotation = rotation;
-	if (sidebar_thumbnails->priv->loading_icons)
-		g_hash_table_remove_all (sidebar_thumbnails->priv->loading_icons);
-
-	if (sidebar_thumbnails->priv->document == NULL ||
-	    sidebar_thumbnails->priv->n_pages <= 0)
-		return;
-
-	ev_sidebar_thumbnails_clear_model (sidebar_thumbnails);
-	ev_sidebar_thumbnails_fill_model (sidebar_thumbnails);
-
-	/* Trigger a redraw */
-	sidebar_thumbnails->priv->start_page = -1;
-	sidebar_thumbnails->priv->end_page = -1;
-	g_idle_add ((GSourceFunc)refresh, sidebar_thumbnails);
-}
-
 static void
 ev_sidebar_tree_selection_changed (GtkTreeSelection *selection,
 				   EvSidebarThumbnails *ev_sidebar_thumbnails)
@@ -630,7 +600,7 @@ ev_sidebar_tree_selection_changed (GtkTreeSelection *selection,
 	page = gtk_tree_path_get_indices (path)[0];
 	gtk_tree_path_free (path);
 
-	ev_page_cache_set_current_page_history (priv->page_cache, page);
+	ev_document_model_set_page (priv->model, page);
 }
 
 static void
@@ -655,7 +625,7 @@ ev_sidebar_icon_selection_changed (GtkIconView         *icon_view,
 	gtk_tree_path_free (path);
 	g_list_free (selected);
 
-	ev_page_cache_set_current_page_history (priv->page_cache, page);
+	ev_document_model_set_page (priv->model, page);
 }
 
 static void
@@ -749,9 +719,8 @@ ev_sidebar_thumbnails_init (EvSidebarThumbnails *ev_sidebar_thumbnails)
 }
 
 static void
-page_changed_cb (EvPageCache         *page_cache,
-		 int                  page,
-		 EvSidebarThumbnails *sidebar)
+ev_sidebar_thumbnails_set_current_page (EvSidebarThumbnails *sidebar,
+					gint                 page)
 {
 	GtkTreeView *tree_view;
 	GtkTreePath *path;
@@ -781,6 +750,45 @@ page_changed_cb (EvPageCache         *page_cache,
 }
 
 static void
+page_changed_cb (EvSidebarThumbnails *sidebar,
+		 gint                 old_page,
+		 gint                 new_page)
+{
+	ev_sidebar_thumbnails_set_current_page (sidebar, new_page);
+}
+
+static gboolean
+refresh (EvSidebarThumbnails *sidebar_thumbnails)
+{
+	adjustment_changed_cb (sidebar_thumbnails);
+	return FALSE;
+}
+
+static void
+ev_sidebar_thumbnails_rotation_changed_cb (EvDocumentModel     *model,
+					   GParamSpec          *pspec,
+					   EvSidebarThumbnails *sidebar_thumbnails)
+{
+	gint rotation = ev_document_model_get_rotation (model);
+
+	sidebar_thumbnails->priv->rotation = rotation;
+	if (sidebar_thumbnails->priv->loading_icons)
+		g_hash_table_remove_all (sidebar_thumbnails->priv->loading_icons);
+
+	if (sidebar_thumbnails->priv->document == NULL ||
+	    sidebar_thumbnails->priv->n_pages <= 0)
+		return;
+
+	ev_sidebar_thumbnails_clear_model (sidebar_thumbnails);
+	ev_sidebar_thumbnails_fill_model (sidebar_thumbnails);
+
+	/* Trigger a redraw */
+	sidebar_thumbnails->priv->start_page = -1;
+	sidebar_thumbnails->priv->end_page = -1;
+	g_idle_add ((GSourceFunc)refresh, sidebar_thumbnails);
+}
+
+static void
 thumbnail_job_completed_callback (EvJobThumbnail      *job,
 				  EvSidebarThumbnails *sidebar_thumbnails)
 {
@@ -797,15 +805,13 @@ thumbnail_job_completed_callback (EvJobThumbnail      *job,
 }
 
 static void
-ev_sidebar_thumbnails_set_document (EvSidebarPage *sidebar_page,
-				    EvDocument    *document)
+ev_sidebar_thumbnails_document_changed_cb (EvDocumentModel     *model,
+					   GParamSpec          *pspec,
+					   EvSidebarThumbnails *sidebar_thumbnails)
 {
-	EvSidebarThumbnails *sidebar_thumbnails = EV_SIDEBAR_THUMBNAILS (sidebar_page);
-
+	EvDocument *document = ev_document_model_get_document (model);
 	EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
 
-	priv->page_cache = ev_page_cache_get (document);
-
 	if (!EV_IS_DOCUMENT_THUMBNAILS (document) ||
 	    ev_document_get_n_pages (document) <= 0 ||
 	    !ev_document_check_dimensions (document)) {
@@ -849,15 +855,35 @@ ev_sidebar_thumbnails_set_document (EvSidebarPage *sidebar_page,
 	}
 
 	/* Connect to the signal and trigger a fake callback */
-	g_signal_connect (priv->page_cache, "page-changed", G_CALLBACK (page_changed_cb), sidebar_thumbnails);
+	g_signal_connect_swapped (priv->model, "page-changed",
+				  G_CALLBACK (page_changed_cb),
+				  sidebar_thumbnails);
+	g_signal_connect (priv->model, "notify::rotation",
+			  G_CALLBACK (ev_sidebar_thumbnails_rotation_changed_cb),
+			  sidebar_thumbnails);
 	sidebar_thumbnails->priv->start_page = -1;
 	sidebar_thumbnails->priv->end_page = -1;
-	page_changed_cb (priv->page_cache,
-			 ev_page_cache_get_current_page (priv->page_cache),
-			 sidebar_thumbnails);
+	ev_sidebar_thumbnails_set_current_page (sidebar_thumbnails,
+						ev_document_model_get_page (model));
 	adjustment_changed_cb (sidebar_thumbnails);
 }
 
+static void
+ev_sidebar_thumbnails_set_model (EvSidebarPage   *sidebar_page,
+				 EvDocumentModel *model)
+{
+	EvSidebarThumbnails *sidebar_thumbnails = EV_SIDEBAR_THUMBNAILS (sidebar_page);
+	EvSidebarThumbnailsPrivate *priv = sidebar_thumbnails->priv;
+
+	if (priv->model == model)
+		return;
+
+	priv->model = model;
+	g_signal_connect (model, "notify::document",
+			  G_CALLBACK (ev_sidebar_thumbnails_document_changed_cb),
+			  sidebar_page);
+}
+
 static gboolean
 ev_sidebar_thumbnails_clear_job (GtkTreeModel *model,                                             
 			         GtkTreePath *path,
@@ -903,7 +929,7 @@ static void
 ev_sidebar_thumbnails_page_iface_init (EvSidebarPageIface *iface)
 {
 	iface->support_document = ev_sidebar_thumbnails_support_document;
-	iface->set_document = ev_sidebar_thumbnails_set_document;
+	iface->set_model = ev_sidebar_thumbnails_set_model;
 	iface->get_label = ev_sidebar_thumbnails_get_label;
 }
 
diff --git a/shell/ev-sidebar-thumbnails.h b/shell/ev-sidebar-thumbnails.h
index 5a3ddda..d49836d 100644
--- a/shell/ev-sidebar-thumbnails.h
+++ b/shell/ev-sidebar-thumbnails.h
@@ -26,8 +26,6 @@
 
 #include <gtk/gtk.h>
 
-#include "ev-document.h"
-
 G_BEGIN_DECLS
 
 typedef struct _EvSidebarThumbnails EvSidebarThumbnails;
@@ -37,7 +35,7 @@ typedef struct _EvSidebarThumbnailsPrivate EvSidebarThumbnailsPrivate;
 #define EV_TYPE_SIDEBAR_THUMBNAILS		(ev_sidebar_thumbnails_get_type())
 #define EV_SIDEBAR_THUMBNAILS(object)		(G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_SIDEBAR_THUMBNAILS, EvSidebarThumbnails))
 #define EV_SIDEBAR_THUMBNAILS_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_SIDEBAR_THUMBNAILS, EvSidebarThumbnailsClass))
-#define EV_IS_SIDEBAR_THUMBNAILS(object)		(G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_SIDEBAR_THUMBNAILS))
+#define EV_IS_SIDEBAR_THUMBNAILS(object)	(G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_SIDEBAR_THUMBNAILS))
 #define EV_IS_SIDEBAR_THUMBNAILS_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_SIDEBAR_THUMBNAILS))
 #define EV_SIDEBAR_THUMBNAILS_GET_CLASS(object)	(G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_SIDEBAR_THUMBNAILS, EvSidebarThumbnailsClass))
 
@@ -51,10 +49,8 @@ struct _EvSidebarThumbnailsClass {
 	GtkVBoxClass base_class;
 };
 
-GType      ev_sidebar_thumbnails_get_type     (void);
+GType      ev_sidebar_thumbnails_get_type     (void) G_GNUC_CONST;
 GtkWidget *ev_sidebar_thumbnails_new          (void);
-void       ev_sidebar_thumbnails_refresh      (EvSidebarThumbnails *sidebar_thumbnails,
-					       int                  rotation);
 
 G_END_DECLS
 
diff --git a/shell/ev-sidebar.c b/shell/ev-sidebar.c
index 2d97381..f15b376 100644
--- a/shell/ev-sidebar.c
+++ b/shell/ev-sidebar.c
@@ -53,7 +53,8 @@ struct _EvSidebarPrivate {
 	GtkWidget *menu;
 	GtkWidget *hbox;
 	GtkWidget *label;
-	   
+
+	EvDocumentModel *model;
 	GtkTreeModel *page_model;
 };
 
@@ -439,7 +440,9 @@ ev_sidebar_add_page (EvSidebar   *ev_sidebar,
 	g_return_if_fail (EV_IS_SIDEBAR (ev_sidebar));
 	g_return_if_fail (EV_IS_SIDEBAR_PAGE (main_widget));
 	g_return_if_fail (GTK_IS_WIDGET (main_widget));
-	
+
+	ev_sidebar_page_set_model (EV_SIDEBAR_PAGE (main_widget),
+				   ev_sidebar->priv->model);
 	title = ev_sidebar_page_get_label (EV_SIDEBAR_PAGE (main_widget));
 	   
 	index = gtk_notebook_append_page (GTK_NOTEBOOK (ev_sidebar->priv->notebook),
@@ -480,22 +483,17 @@ ev_sidebar_add_page (EvSidebar   *ev_sidebar,
 	g_free (label_title);
 }
 
-void
-ev_sidebar_set_document (EvSidebar   *sidebar,
-			 EvDocument  *document)
+static void
+ev_sidebar_document_changed_cb (EvDocumentModel *model,
+				GParamSpec      *pspec,
+				EvSidebar       *sidebar)
 {
-	EvSidebarPrivate *priv;
+	EvSidebarPrivate *priv = sidebar->priv;
+	EvDocument *document = ev_document_model_get_document (model);
 	GtkTreeIter iter;
 	gboolean valid;
-	gboolean has_pages;
-	   
-	g_return_if_fail (EV_IS_SIDEBAR (sidebar));
-	g_return_if_fail (EV_IS_DOCUMENT (document));
-	   
-	priv = sidebar->priv;
-	
-	has_pages = FALSE;
-	
+	gboolean has_pages = FALSE;
+
 	for (valid = gtk_tree_model_get_iter_first (priv->page_model, &iter);
 	     valid;
 	     valid = gtk_tree_model_iter_next (priv->page_model, &iter)) {
@@ -506,18 +504,16 @@ ev_sidebar_set_document (EvSidebar   *sidebar,
 				    PAGE_COLUMN_MAIN_WIDGET, &widget,
 				    PAGE_COLUMN_MENU_ITEM, &menu_widget,
 				    -1);
-			 
 
 		if (ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (widget),	document)) {
-				ev_sidebar_page_set_document (EV_SIDEBAR_PAGE (widget), document);
-				has_pages = TRUE;
+			has_pages = TRUE;
 		} else {
-				gtk_widget_set_sensitive (menu_widget, FALSE);
+			gtk_widget_set_sensitive (menu_widget, FALSE);
 		}
 		g_object_unref (widget);
 		g_object_unref (menu_widget);
 	}
-	
+
 	if (!has_pages) {
 		gtk_widget_hide (GTK_WIDGET (sidebar));
 	} else {
@@ -526,3 +522,18 @@ ev_sidebar_set_document (EvSidebar   *sidebar,
 	}
 }
 
+void
+ev_sidebar_set_model (EvSidebar       *sidebar,
+		      EvDocumentModel *model)
+{
+	g_return_if_fail (EV_IS_SIDEBAR (sidebar));
+	g_return_if_fail (EV_IS_DOCUMENT_MODEL (model));
+
+	if (model == sidebar->priv->model)
+		return;
+
+	sidebar->priv->model = model;
+	g_signal_connect (model, "notify::document",
+			  G_CALLBACK (ev_sidebar_document_changed_cb),
+			  sidebar);
+}
diff --git a/shell/ev-sidebar.h b/shell/ev-sidebar.h
index 5f01132..3601b73 100644
--- a/shell/ev-sidebar.h
+++ b/shell/ev-sidebar.h
@@ -26,7 +26,7 @@
 
 #include <gtk/gtk.h>
 
-#include "ev-document.h"
+#include "ev-document-model.h"
 
 G_BEGIN_DECLS
 
@@ -51,14 +51,14 @@ struct _EvSidebarClass {
 	GtkVBoxClass base_class;
 };
 
-GType      ev_sidebar_get_type  	   (void);
-GtkWidget *ev_sidebar_new         	   (void);
-void       ev_sidebar_add_page    	   (EvSidebar   *ev_sidebar,
-					    GtkWidget   *main_widget);
-void       ev_sidebar_set_page    	   (EvSidebar   *ev_sidebar,
-					    GtkWidget   *main_widget);
-void       ev_sidebar_set_document	   (EvSidebar   *ev_sidebar,
-					    EvDocument  *document);
+GType      ev_sidebar_get_type  (void) G_GNUC_CONST;
+GtkWidget *ev_sidebar_new       (void);
+void       ev_sidebar_add_page  (EvSidebar       *ev_sidebar,
+				 GtkWidget       *main_widget);
+void       ev_sidebar_set_page  (EvSidebar       *ev_sidebar,
+				 GtkWidget       *main_widget);
+void       ev_sidebar_set_model (EvSidebar       *sidebar,
+				 EvDocumentModel *model);
 
 G_END_DECLS
 
diff --git a/shell/ev-window.c b/shell/ev-window.c
index 7593fd8..82425dc 100644
--- a/shell/ev-window.c
+++ b/shell/ev-window.c
@@ -176,6 +176,7 @@ struct _EvWindowPrivate {
 	GList        *attach_list;
 
 	/* Document */
+	EvDocumentModel *model;
 	char *uri;
 	glong uri_mtime;
 	char *local_uri;
@@ -185,7 +186,6 @@ struct _EvWindowPrivate {
 	
 	EvDocument *document;
 	EvHistory *history;
-	EvPageCache *page_cache;
 	EvWindowPageMode page_mode;
 	EvWindowTitle *title;
 
@@ -226,6 +226,9 @@ struct _EvWindowPrivate {
 #define ATTACHMENTS_SIDEBAR_ID "attachments"
 #define LAYERS_SIDEBAR_ID "layers"
 
+#define MIN_SCALE 0.05409
+#define MAX_SCALE 4.0
+
 static const gchar *document_print_settings[] = {
 	GTK_PRINT_SETTINGS_N_COPIES,
 	GTK_PRINT_SETTINGS_COLLATE,
@@ -254,10 +257,10 @@ static void     ev_window_set_icon_from_thumbnail       (EvJobThumbnail   *job,
 							 EvWindow         *ev_window);
 static void     ev_window_save_job_cb                   (EvJob            *save,
 							 EvWindow         *window);
-static void     ev_window_sizing_mode_changed_cb        (EvView           *view,
+static void     ev_window_sizing_mode_changed_cb        (EvDocumentModel  *model,
 							 GParamSpec       *pspec,
 							 EvWindow         *ev_window);
-static void     ev_window_zoom_changed_cb 	        (EvView           *view,
+static void     ev_window_zoom_changed_cb 	        (EvDocumentModel  *model,
 							 GParamSpec       *pspec,
 							 EvWindow         *ev_window);
 static void     ev_window_add_recent                    (EvWindow         *window,
@@ -339,11 +342,8 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window)
 
 	if (document) {
 		has_document = TRUE;
-		info = ev_document_get_info (document);
-	}
-
-	if (has_document && ev_window->priv->page_cache) {
 		has_pages = ev_document_get_n_pages (document) > 0;
+		info = ev_document_get_info (document);
 	}
 
 	if (!info || info->fields_mask == 0) {
@@ -422,9 +422,10 @@ ev_window_update_actions (EvWindow *ev_window)
 	gboolean has_pages = FALSE;
 	gboolean presentation_mode;
 	gboolean can_find_in_page = FALSE;
+	EvSizingMode sizing_mode;
 
-	if (ev_window->priv->document && ev_window->priv->page_cache) {
-		page = ev_page_cache_get_current_page (ev_window->priv->page_cache);
+	if (ev_window->priv->document) {
+		page = ev_document_model_get_page (ev_window->priv->model);
 		n_pages = ev_document_get_n_pages (ev_window->priv->document);
 		has_pages = n_pages > 0;
 	}
@@ -466,17 +467,16 @@ ev_window_update_actions (EvWindow *ev_window)
 		ev_window_set_action_sensitive (ev_window, "GoLastPage", FALSE);
 	}
 
-	if (has_pages &&
-	    ev_view_get_sizing_mode (view) != EV_SIZING_FIT_WIDTH &&
-	    ev_view_get_sizing_mode (view) != EV_SIZING_BEST_FIT) {
+	sizing_mode = ev_document_model_get_sizing_mode (ev_window->priv->model);
+	if (has_pages && sizing_mode != EV_SIZING_FIT_WIDTH && sizing_mode != EV_SIZING_BEST_FIT) {
 		GtkAction *action;
 		float      zoom;
 		float      real_zoom;
 
-		action = gtk_action_group_get_action (ev_window->priv->action_group, 
+		action = gtk_action_group_get_action (ev_window->priv->action_group,
 						      ZOOM_CONTROL_ACTION);
 
-		real_zoom = ev_view_get_zoom (EV_VIEW (ev_window->priv->view));
+		real_zoom = ev_document_model_get_scale (ev_window->priv->model);
 		real_zoom *= 72.0 / get_screen_dpi (GTK_WINDOW (ev_window));
 		zoom = ephy_zoom_get_nearest_zoom_level (real_zoom);
 
@@ -732,19 +732,6 @@ ev_window_warning_message (EvWindow    *window,
 	ev_window_set_message_area (window, area);
 }
 
-static void
-page_changed_cb (EvPageCache *page_cache,
-		 gint         page,
-		 EvWindow    *ev_window)
-{
-	ev_window_update_actions (ev_window);
-
-	ev_window_update_find_status_message (ev_window);
-
-	if (!ev_window_is_empty (ev_window))
-		ev_metadata_manager_set_int (ev_window->priv->uri, "page", page);
-}
-
 typedef struct _FindTask {
 	const gchar *page_label;
 	gchar *chapter;
@@ -843,23 +830,29 @@ ev_window_add_history (EvWindow *window, gint page, EvLink *link)
 static void
 view_handle_link_cb (EvView *view, EvLink *link, EvWindow *window)
 {
-	int current_page = ev_page_cache_get_current_page (window->priv->page_cache);
+	int current_page = ev_document_model_get_page (window->priv->model);
 	
 	ev_window_add_history (window, 0, link);
 	ev_window_add_history (window, current_page, NULL);
 }
 
 static void
-history_changed_cb (EvPageCache *page_cache,
-		    gint         page,
-		    EvWindow 	*window)
+ev_window_page_changed_cb (EvWindow        *ev_window,
+			   gint             old_page,
+			   gint             new_page,
+			   EvDocumentModel *model)
 {
-	int current_page = ev_page_cache_get_current_page (window->priv->page_cache);
+	ev_window_update_actions (ev_window);
 
-	ev_window_add_history (window, page, NULL);
-	ev_window_add_history (window, current_page, NULL);
+	ev_window_update_find_status_message (ev_window);
 
-	return;
+	if (abs (new_page - old_page) > 1) {
+		ev_window_add_history (ev_window, new_page, NULL);
+		ev_window_add_history (ev_window, old_page, NULL);
+	}
+
+	if (!ev_window_is_empty (ev_window))
+		ev_metadata_manager_set_int (ev_window->priv->uri, "page", new_page);
 }
 
 static void
@@ -940,6 +933,66 @@ setup_sidebar_from_metadata (EvWindow *window)
 }
 
 static void
+setup_model_from_metadata (EvWindow *window)
+{
+	gchar *uri = window->priv->uri;
+	GValue page = { 0, };
+	GValue sizing_mode = { 0, };
+	GValue zoom = { 0, };
+	GValue rotation = { 0, };
+
+	/* Current page */
+	if (ev_metadata_manager_get (uri, "page", &page, TRUE)) {
+		ev_document_model_set_page (window->priv->model,
+					    g_value_get_int (&page));
+		g_value_unset (&page);
+	}
+
+	/* Sizing mode */
+	if (ev_metadata_manager_get (uri, "sizing_mode", &sizing_mode, FALSE)) {
+		GEnumValue *enum_value;
+
+		enum_value = g_enum_get_value_by_nick
+			(g_type_class_peek (EV_TYPE_SIZING_MODE), g_value_get_string (&sizing_mode));
+		ev_document_model_set_sizing_mode (window->priv->model, enum_value->value);
+		g_value_unset (&sizing_mode);
+	}
+
+	/* Zoom */
+	if (ev_document_model_get_sizing_mode (window->priv->model) == EV_SIZING_FREE &&
+	    ev_metadata_manager_get (uri, "zoom", &zoom, FALSE)) {
+		gdouble zoom_value;
+
+		zoom_value = g_value_get_double (&zoom);
+		zoom_value *= get_screen_dpi (GTK_WINDOW (window)) / 72.0;
+		ev_document_model_set_scale (window->priv->model, zoom_value);
+		g_value_unset (&zoom);
+	}
+
+	/* Rotation */
+	if (ev_metadata_manager_get (uri, "rotation", &rotation, TRUE)) {
+		gint rotation_value;
+
+		switch (g_value_get_int (&rotation)) {
+		case 90:
+			rotation_value = 90;
+			break;
+		case 180:
+			rotation_value = 180;
+			break;
+		case 270:
+			rotation_value = 270;
+			break;
+		default:
+			rotation_value = 0;
+			break;
+		}
+		ev_document_model_set_rotation (window->priv->model, rotation_value);
+		g_value_unset (&rotation);
+	}
+}
+
+static void
 setup_document_from_metadata (EvWindow *window)
 {
 	gchar *uri = window->priv->uri;
@@ -949,20 +1002,21 @@ setup_document_from_metadata (EvWindow *window)
 	GValue width_ratio = { 0, };
 	GValue height_ratio = { 0, };
 
+#if 0 /* FIXME */
 	/* View the previously shown page, but make sure to not open a document on
 	 * the last page, since closing it on the last page most likely means the
 	 * user was finished reading the document. In that case, reopening should
 	 * show the first page. */
-	if (uri && ev_metadata_manager_get (uri, "page", &page, TRUE)) {
+	if (ev_metadata_manager_get (uri, "page", &page, TRUE)) {
 		gint n_pages;
 		gint new_page;
 		
 		n_pages = ev_document_get_n_pages (window->priv->document);
 		new_page = CLAMP (g_value_get_int (&page), 0, n_pages - 1);
-		ev_page_cache_set_current_page (window->priv->page_cache,
-						new_page);
+		ev_document_model_set_page (window->priv->model, new_page);
 		g_value_unset (&page);
 	}
+#endif
 
 	setup_sidebar_from_metadata (window);
 
@@ -1045,33 +1099,10 @@ setup_view_from_metadata (EvWindow *window)
 {
 	EvView *view = EV_VIEW (window->priv->view);
 	gchar *uri = window->priv->uri;
-	GEnumValue *enum_value;
-	GValue sizing_mode = { 0, };
-	GValue zoom = { 0, };
 	GValue continuous = { 0, };
 	GValue dual_page = { 0, };
 	GValue presentation = { 0, };
 	GValue fullscreen = { 0, };
-	GValue rotation = { 0, };
-
-	/* Sizing mode */
-	if (ev_metadata_manager_get (uri, "sizing_mode", &sizing_mode, FALSE)) {
-		enum_value = g_enum_get_value_by_nick
-			(g_type_class_peek (EV_TYPE_SIZING_MODE), g_value_get_string (&sizing_mode));
-		g_value_unset (&sizing_mode);
-		ev_view_set_sizing_mode (view, enum_value->value);
-	}
-
-	/* Zoom */
-	if (ev_metadata_manager_get (uri, "zoom", &zoom, FALSE) &&
-	    ev_view_get_sizing_mode (view) == EV_SIZING_FREE) {
-		gdouble zoom_value;
-
-		zoom_value = g_value_get_double (&zoom);
-		zoom_value *= get_screen_dpi (GTK_WINDOW (window)) / 72.0;
-		ev_view_set_zoom (view, zoom_value, FALSE);
-		g_value_unset (&zoom);
-	}
 
 	/* Continuous */
 	if (ev_metadata_manager_get (uri, "continuous", &continuous, FALSE)) {
@@ -1100,26 +1131,6 @@ setup_view_from_metadata (EvWindow *window)
 		}
 		g_value_unset (&fullscreen);
 	}
-
-	/* Rotation */
-	if (ev_metadata_manager_get (uri, "rotation", &rotation, TRUE)) {
-		if (g_value_get_int (&rotation)) {
-			switch (g_value_get_int (&rotation)) {
-			        case 90:
-					ev_view_set_rotation (view, 90);
-					break;
-			        case 180:
-					ev_view_set_rotation (view, 180);
-					break;
-			        case 270:
-					ev_view_set_rotation (view, 270);
-					break;
-			        default:
-					break;
-			}
-		}
-		g_value_unset (&rotation);
-	}
 }
 
 static void
@@ -1179,7 +1190,6 @@ ev_window_setup_document (EvWindow *ev_window)
 {
 	const EvDocumentInfo *info;
 	EvDocument *document = ev_window->priv->document;
-	EvSidebar *sidebar = EV_SIDEBAR (ev_window->priv->sidebar);
 	GtkAction *action;
 
 	ev_window->priv->setup_document_idle = 0;
@@ -1190,10 +1200,6 @@ ev_window_setup_document (EvWindow *ev_window)
 	ev_window_title_set_document (ev_window->priv->title, document);
 	ev_window_title_set_uri (ev_window->priv->title, ev_window->priv->uri);
 
-	ev_sidebar_set_document (sidebar, document);
-
-	action = gtk_action_group_get_action (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
-	ev_page_action_set_document (EV_PAGE_ACTION (action), document);
 	ev_window_setup_action_sensitivity (ev_window);
 
 	if (ev_window->priv->history)
@@ -1219,19 +1225,14 @@ ev_window_setup_document (EvWindow *ev_window)
 static void
 ev_window_set_document (EvWindow *ev_window, EvDocument *document)
 {
-	EvView *view = EV_VIEW (ev_window->priv->view);
+	if (ev_window->priv->document == document)
+		return;
 
 	if (ev_window->priv->document)
 		g_object_unref (ev_window->priv->document);
 	ev_window->priv->document = g_object_ref (document);
 
 	ev_window_set_message_area (ev_window, NULL);
-	
-	ev_window->priv->page_cache = ev_page_cache_get (ev_window->priv->document);
-	g_signal_connect (ev_window->priv->page_cache, "page-changed",
-			  G_CALLBACK (page_changed_cb), ev_window);
-	g_signal_connect (ev_window->priv->page_cache, "history-changed",
-			  G_CALLBACK (history_changed_cb), ev_window);
 
 	if (ev_window->priv->in_reload && ev_window->priv->dest) {
 		gint page;
@@ -1240,7 +1241,7 @@ ev_window_set_document (EvWindow *ev_window, EvDocument *document)
 		page = CLAMP (ev_link_dest_get_page (ev_window->priv->dest),
 			      0,
 			      ev_document_get_n_pages (document) - 1);
-		ev_page_cache_set_current_page (ev_window->priv->page_cache, page);
+		ev_document_model_set_page (ev_window->priv->model, page);
 		g_object_unref (ev_window->priv->dest);
 		ev_window->priv->dest = NULL;
 	}
@@ -1251,8 +1252,6 @@ ev_window_set_document (EvWindow *ev_window, EvDocument *document)
 	} else if (!ev_document_check_dimensions (document)) {
 		ev_window_warning_message (ev_window, "%s",
 					   _("The document contains only empty pages"));
-	} else {
-		ev_view_set_document (view, document);
 	}
 
 	if (ev_window->priv->setup_document_idle > 0)
@@ -1386,7 +1385,7 @@ ev_window_load_job_cb (EvJob *job,
 
 	/* Success! */
 	if (!ev_job_is_failed (job)) {
-		ev_window_set_document (ev_window, document);
+		ev_document_model_set_document (ev_window->priv->model, document);
 
 		setup_document_from_metadata (ev_window);
 		setup_view_from_metadata (ev_window);
@@ -1503,8 +1502,8 @@ ev_window_reload_job_cb (EvJob    *job,
 	if (ev_window->priv->dest) {
 		dest = g_object_ref (ev_window->priv->dest);
 	}
-	ev_window_set_document (ev_window, job->document);
-
+	ev_document_model_set_document (ev_window->priv->model,
+					job->document);
 	ev_window_handle_link (ev_window, dest);
 
 	/* Restart the search after reloading */
@@ -1839,6 +1838,7 @@ ev_window_open_uri (EvWindow       *ev_window,
 	ev_window->priv->dest = dest ? g_object_ref (dest) : NULL;
 
 	setup_size_from_metadata (ev_window);
+	setup_model_from_metadata (ev_window);
 
 	ev_window->priv->load_job = ev_job_load_new (uri);
 	g_signal_connect (ev_window->priv->load_job,
@@ -2013,7 +2013,7 @@ ev_window_reload_document (EvWindow *ev_window,
 	ev_window_clear_reload_job (ev_window);
 	ev_window->priv->in_reload = TRUE;
 
-	page = ev_page_cache_get_current_page (ev_window->priv->page_cache);
+	page = ev_document_model_get_page (ev_window->priv->model);
 	
 	if (ev_window->priv->dest)
 		g_object_unref (ev_window->priv->dest);
@@ -2194,13 +2194,11 @@ ev_window_cmd_file_open_copy_at_dest (EvWindow *window, EvLinkDest *dest)
 static void
 ev_window_cmd_file_open_copy (GtkAction *action, EvWindow *window)
 {
-	EvPageCache *page_cache;
 	EvLinkDest  *dest;
 	gint         current_page;
 
-	page_cache = ev_page_cache_get (window->priv->document);
-	current_page = ev_page_cache_get_current_page (page_cache);
-	
+	current_page = ev_document_model_get_page (window->priv->model);
+
 	dest = ev_link_dest_new_page (current_page);
 	ev_window_cmd_file_open_copy_at_dest (window, dest);
 	g_object_unref (dest);
@@ -2988,7 +2986,6 @@ ev_window_print_range (EvWindow *ev_window,
 		       gint      last_page)
 {
 	EvPrintOperation *op;
-	EvPageCache      *page_cache;
 	gint              current_page;
 	gint              document_last_page;
 
@@ -3014,8 +3011,7 @@ ev_window_print_range (EvWindow *ev_window,
 			  G_CALLBACK (ev_window_print_operation_done),
 			  (gpointer)ev_window);
 
-	page_cache = ev_page_cache_get (ev_window->priv->document);
-	current_page = ev_page_cache_get_current_page (page_cache);
+	current_page = ev_document_model_get_page (ev_window->priv->model);
 	document_last_page = ev_document_get_n_pages (ev_window->priv->document);
 
 	if (!ev_window->priv->print_settings) {
@@ -3238,9 +3234,9 @@ ev_window_cmd_view_best_fit (GtkAction *action, EvWindow *ev_window)
 	ev_window_stop_presentation (ev_window, TRUE);
 
 	if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
-		ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), EV_SIZING_BEST_FIT);
+		ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_BEST_FIT);
 	} else {
-		ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), EV_SIZING_FREE);
+		ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FREE);
 	}
 	ev_window_update_actions (ev_window);
 }
@@ -3251,9 +3247,9 @@ ev_window_cmd_view_page_width (GtkAction *action, EvWindow *ev_window)
 	ev_window_stop_presentation (ev_window, TRUE);
 
 	if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
-		ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), EV_SIZING_FIT_WIDTH);
+		ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FIT_WIDTH);
 	} else {
-		ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), EV_SIZING_FREE);
+		ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FREE);
 	}
 	ev_window_update_actions (ev_window);
 }
@@ -3665,15 +3661,17 @@ ev_window_screen_changed (GtkWidget *widget,
 	EvWindow *window = EV_WINDOW (widget);
 	EvWindowPrivate *priv = window->priv;
 	GdkScreen *screen;
+	gdouble dpi;
 
 	screen = gtk_widget_get_screen (widget);
 	if (screen == old_screen)
 		return;
 
 	ev_window_setup_gtk_settings (window);
-	ev_view_set_screen_dpi (EV_VIEW (priv->view),
-				get_screen_dpi (GTK_WINDOW (window)));
-	
+	dpi = get_screen_dpi (GTK_WINDOW (window));
+	ev_document_model_set_min_scale (priv->model, MIN_SCALE * dpi / 72.0);
+	ev_document_model_set_max_scale (priv->model, MAX_SCALE * dpi / 72.0);
+
 	if (GTK_WIDGET_CLASS (ev_window_parent_class)->screen_changed) {
 		GTK_WIDGET_CLASS (ev_window_parent_class)->screen_changed (widget, old_screen);
 	}
@@ -3745,13 +3743,17 @@ ev_window_set_page_mode (EvWindow         *window,
 static void
 ev_window_cmd_edit_rotate_left (GtkAction *action, EvWindow *ev_window)
 {
-	ev_view_rotate_left (EV_VIEW (ev_window->priv->view));
+	gint rotation = ev_document_model_get_rotation (ev_window->priv->model);
+
+	ev_document_model_set_rotation (ev_window->priv->model, rotation - 90);
 }
 
 static void
 ev_window_cmd_edit_rotate_right (GtkAction *action, EvWindow *ev_window)
 {
-	ev_view_rotate_right (EV_VIEW (ev_window->priv->view));
+	gint rotation = ev_document_model_get_rotation (ev_window->priv->model);
+
+	ev_document_model_set_rotation (ev_window->priv->model, rotation + 90);
 }
 
 static void
@@ -3803,7 +3805,7 @@ ev_window_cmd_view_zoom_in (GtkAction *action, EvWindow *ev_window)
 {
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
-	ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), EV_SIZING_FREE);
+	ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FREE);
 	ev_view_zoom_in (EV_VIEW (ev_window->priv->view));
 }
 
@@ -3812,7 +3814,7 @@ ev_window_cmd_view_zoom_out (GtkAction *action, EvWindow *ev_window)
 {
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
-	ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), EV_SIZING_FREE);
+	ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FREE);
 	ev_view_zoom_out (EV_VIEW (ev_window->priv->view));
 }
 
@@ -3837,7 +3839,7 @@ ev_window_cmd_go_first_page (GtkAction *action, EvWindow *ev_window)
 {
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
-	ev_page_cache_set_current_page (ev_window->priv->page_cache, 0);
+	ev_document_model_set_page (ev_window->priv->model, 0);
 }
 
 static void
@@ -3845,8 +3847,8 @@ ev_window_cmd_go_last_page (GtkAction *action, EvWindow *ev_window)
 {
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
-	ev_page_cache_set_current_page (ev_window->priv->page_cache,
-					ev_document_get_n_pages (ev_window->priv->document) - 1);
+	ev_document_model_set_page (ev_window->priv->model,
+				    ev_document_get_n_pages (ev_window->priv->document) - 1);
 }
 
 static void
@@ -3857,10 +3859,11 @@ ev_window_cmd_go_forward (GtkAction *action, EvWindow *ev_window)
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
 	n_pages = ev_document_get_n_pages (ev_window->priv->document);
-	current_page = ev_page_cache_get_current_page (ev_window->priv->page_cache);
+	current_page = ev_document_model_get_page (ev_window->priv->model);
 	
-	if (current_page + 10 < n_pages)
-		ev_page_cache_set_current_page (ev_window->priv->page_cache, current_page + 10);
+	if (current_page + 10 < n_pages) {
+		ev_document_model_set_page (ev_window->priv->model, current_page + 10);
+	}
 }
 
 static void
@@ -3870,10 +3873,11 @@ ev_window_cmd_go_backward (GtkAction *action, EvWindow *ev_window)
 	
         g_return_if_fail (EV_IS_WINDOW (ev_window));
 
-	current_page = ev_page_cache_get_current_page (ev_window->priv->page_cache);
+	current_page = ev_document_model_get_page (ev_window->priv->model);
 	
-	if (current_page - 10 >= 0)
-		ev_page_cache_set_current_page (ev_window->priv->page_cache, current_page - 10);
+	if (current_page - 10 >= 0) {
+		ev_document_model_set_page (ev_window->priv->model, current_page - 10);
+	}
 }
 
 static void
@@ -3957,23 +3961,30 @@ save_sizing_mode (EvWindow *window)
 	EvSizingMode mode;
 	GEnumValue *enum_value;
 
-	mode = ev_view_get_sizing_mode (EV_VIEW (window->priv->view));
-	enum_value = g_enum_get_value (g_type_class_peek (EV_TYPE_SIZING_MODE), mode);
+	if (ev_window_is_empty (window))
+		return;
 
-	if (!ev_window_is_empty (window))
-		ev_metadata_manager_set_string (window->priv->uri, "sizing_mode",
-						enum_value->value_nick);
+	mode = ev_document_model_get_sizing_mode (window->priv->model);
+	enum_value = g_enum_get_value (g_type_class_peek (EV_TYPE_SIZING_MODE), mode);
+	ev_metadata_manager_set_string (window->priv->uri, "sizing_mode",
+					enum_value->value_nick);
 }
 
-static void     
-ev_window_sizing_mode_changed_cb (EvView *view, GParamSpec *pspec,
-		 		  EvWindow   *ev_window)
+static void
+ev_window_document_changed_cb (EvDocumentModel *model,
+			       GParamSpec      *pspec,
+			       EvWindow        *ev_window)
 {
-	EvSizingMode sizing_mode;
+	ev_window_set_document (ev_window,
+				ev_document_model_get_document (model));
+}
 
-	g_object_get (ev_window->priv->view,
-		      "sizing-mode", &sizing_mode,
-		      NULL);
+static void
+ev_window_sizing_mode_changed_cb (EvDocumentModel *model,
+				  GParamSpec      *pspec,
+		 		  EvWindow        *ev_window)
+{
+	EvSizingMode sizing_mode = ev_document_model_get_sizing_mode (model);
 
 	g_object_set (ev_window->priv->scrolled_window,
 		      "hscrollbar-policy",
@@ -3986,15 +3997,15 @@ ev_window_sizing_mode_changed_cb (EvView *view, GParamSpec *pspec,
 	save_sizing_mode (ev_window);
 }
 
-static void     
-ev_window_zoom_changed_cb (EvView *view, GParamSpec *pspec, EvWindow *ev_window)
+static void
+ev_window_zoom_changed_cb (EvDocumentModel *model, GParamSpec *pspec, EvWindow *ev_window)
 {
         ev_window_update_actions (ev_window);
 
-	if (ev_view_get_sizing_mode (view) == EV_SIZING_FREE && !ev_window_is_empty (ev_window)) {
+	if (ev_document_model_get_sizing_mode (model) == EV_SIZING_FREE && !ev_window_is_empty (ev_window)) {
 		gdouble zoom;
 
-		zoom = ev_view_get_zoom (view);
+		zoom = ev_document_model_get_scale (model);
 		zoom *= 72.0 / get_screen_dpi (GTK_WINDOW(ev_window));
 		ev_metadata_manager_set_double (ev_window->priv->uri, "zoom", zoom);
 	}
@@ -4038,19 +4049,15 @@ ev_window_continuous_changed_cb (EvView *view, GParamSpec *pspec, EvWindow *ev_w
 					         ev_view_get_continuous (EV_VIEW (ev_window->priv->view)));
 }
 
-static void     
-ev_window_rotation_changed_cb (EvView *view, GParamSpec *pspec, EvWindow *window)
+static void
+ev_window_rotation_changed_cb (EvDocumentModel *model, GParamSpec *pspec, EvWindow *window)
 {
-	int rotation;
-
-	rotation = ev_view_get_rotation (EV_VIEW (window->priv->view));
+	gint rotation = ev_document_model_get_rotation (model);
 
 	if (!ev_window_is_empty (window))
 		ev_metadata_manager_set_int (window->priv->uri, "rotation",
 					     rotation);
 
-	ev_sidebar_thumbnails_refresh (EV_SIDEBAR_THUMBNAILS (window->priv->sidebar_thumbs),
-				       rotation);
 	ev_window_refresh_window_thumbnail (window, rotation);
 }
 
@@ -4376,7 +4383,7 @@ ev_window_update_find_status_message (EvWindow *ev_window)
 		gint n_results;
 
 		n_results = ev_job_find_get_n_results (EV_JOB_FIND (ev_window->priv->find_job),
-						       ev_page_cache_get_current_page (ev_window->priv->page_cache));
+						       ev_document_model_get_page (ev_window->priv->model));
 		/* TRANS: Sometimes this could be better translated as
 		                      "%d hit(s) on this page".  Therefore this string
 				      contains plural cases. */
@@ -4479,7 +4486,7 @@ find_bar_search_changed_cb (EggFindBar *find_bar,
 
 	if (search_string && search_string[0]) {
 		ev_window->priv->find_job = ev_job_find_new (ev_window->priv->document,
-							     ev_page_cache_get_current_page (ev_window->priv->page_cache),
+							     ev_document_model_get_page (ev_window->priv->model),
 							     ev_document_get_n_pages (ev_window->priv->document),
 							     search_string,
 							     case_sensitive);
@@ -4534,8 +4541,6 @@ zoom_control_changed_cb (EphyZoomAction *action,
 			 EvWindow       *ev_window)
 {
 	EvSizingMode mode;
-	
-	g_return_if_fail (EV_IS_WINDOW (ev_window));
 
 	if (zoom == EPHY_ZOOM_BEST_FIT) {
 		mode = EV_SIZING_BEST_FIT;
@@ -4545,12 +4550,11 @@ zoom_control_changed_cb (EphyZoomAction *action,
 		mode = EV_SIZING_FREE;
 	}
 
-	ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), mode);
-	
+	ev_document_model_set_sizing_mode (ev_window->priv->model, mode);
+
 	if (mode == EV_SIZING_FREE) {
-		ev_view_set_zoom (EV_VIEW (ev_window->priv->view),
-				  zoom * get_screen_dpi (GTK_WINDOW (ev_window)) / 72.0,
-				  FALSE);
+		ev_document_model_set_scale (ev_window->priv->model,
+					     zoom * get_screen_dpi (GTK_WINDOW (ev_window)) / 72.0);
 	}
 }
 
@@ -4671,9 +4675,12 @@ ev_window_dispose (GObject *object)
 
 	priv->recent_ui_id = 0;
 
-	if (priv->page_cache) {
-		g_signal_handlers_disconnect_by_func (priv->page_cache, page_changed_cb, window);
-		priv->page_cache = NULL;
+	if (priv->model) {
+		g_signal_handlers_disconnect_by_func (priv->model,
+						      ev_window_page_changed_cb,
+						      window);
+		g_object_unref (priv->model);
+		priv->model = NULL;
 	}
 
 	if (priv->document) {
@@ -5103,6 +5110,8 @@ register_custom_actions (EvWindow *window, GtkActionGroup *group)
 			       "icon_name", "text-x-generic",
 			       "visible_overflown", FALSE,
 			       NULL);
+	ev_page_action_set_model (EV_PAGE_ACTION (action),
+				  window->priv->model);
 	g_signal_connect (action, "activate_link",
 			  G_CALLBACK (activate_link_cb), window);
 	gtk_action_group_add_action (group, action);
@@ -5213,7 +5222,7 @@ sidebar_widget_model_set (EvSidebarLinks *ev_sidebar_links,
 		      NULL);
 
 	action = gtk_action_group_get_action (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
-	ev_page_action_set_model (EV_PAGE_ACTION (action), model);
+	ev_page_action_set_links_model (EV_PAGE_ACTION (action), model);
 	g_object_unref (model);
 }
 
@@ -5858,6 +5867,7 @@ ev_window_init (EvWindow *ev_window)
 	GtkWidget *sidebar_widget;
 	GObject *mpkeys;
 	gchar *ui_path;
+	gdouble dpi;
 
 	g_signal_connect (ev_window, "configure_event",
 			  G_CALLBACK (window_configure_event_cb), NULL);
@@ -5866,6 +5876,8 @@ ev_window_init (EvWindow *ev_window)
 
 	ev_window->priv = EV_WINDOW_GET_PRIVATE (ev_window);
 
+	ev_window->priv->model = ev_document_model_new ();
+
 	ev_window->priv->page_mode = PAGE_MODE_DOCUMENT;
 	ev_window->priv->title = ev_window_title_new (ev_window);
 
@@ -5964,6 +5976,8 @@ ev_window_init (EvWindow *ev_window)
 	gtk_widget_show (ev_window->priv->hpaned);
 	
 	ev_window->priv->sidebar = ev_sidebar_new ();
+	ev_sidebar_set_model (EV_SIDEBAR (ev_window->priv->sidebar),
+			      ev_window->priv->model);
 	gtk_paned_pack1 (GTK_PANED (ev_window->priv->hpaned),
 			 ev_window->priv->sidebar, FALSE, FALSE);
 	gtk_widget_show (ev_window->priv->sidebar);
@@ -6031,6 +6045,10 @@ ev_window_init (EvWindow *ev_window)
 	gtk_widget_show (ev_window->priv->view_box);
 
 	ev_window->priv->view = ev_view_new ();
+	ev_view_set_model (EV_VIEW (ev_window->priv->view), ev_window->priv->model);
+	dpi = get_screen_dpi (GTK_WINDOW (ev_window));
+	ev_document_model_set_min_scale (ev_window->priv->model, MIN_SCALE * dpi / 72.0);
+	ev_document_model_set_max_scale (ev_window->priv->model, MAX_SCALE * dpi / 72.0);
 	ev_view_set_screen_dpi (EV_VIEW (ev_window->priv->view),
 				get_screen_dpi (GTK_WINDOW (ev_window)));
 	ev_window->priv->password_view = ev_password_view_new (GTK_WINDOW (ev_window));
@@ -6070,14 +6088,29 @@ ev_window_init (EvWindow *ev_window)
 	gtk_container_add (GTK_CONTAINER (ev_window->priv->scrolled_window),
 			   ev_window->priv->view);
 
-	g_signal_connect (ev_window->priv->view,
+	/* Connect to model signals */
+	g_signal_connect_swapped (ev_window->priv->model,
+				  "page-changed",
+				  G_CALLBACK (ev_window_page_changed_cb),
+				  ev_window);
+	g_signal_connect (ev_window->priv->model,
+			  "notify::document",
+			  G_CALLBACK (ev_window_document_changed_cb),
+			  ev_window);
+	g_signal_connect (ev_window->priv->model,
+			  "notify::scale",
+			  G_CALLBACK (ev_window_zoom_changed_cb),
+			  ev_window);
+	g_signal_connect (ev_window->priv->model,
 			  "notify::sizing-mode",
 			  G_CALLBACK (ev_window_sizing_mode_changed_cb),
 			  ev_window);
-	g_signal_connect (ev_window->priv->view,
-			  "notify::zoom",
-			  G_CALLBACK (ev_window_zoom_changed_cb),
+	g_signal_connect (ev_window->priv->model,
+			  "notify::rotation",
+			  G_CALLBACK (ev_window_rotation_changed_cb),
 			  ev_window);
+
+	/* Connect to view signals */
 	g_signal_connect (ev_window->priv->view,
 			  "notify::dual-page",
 			  G_CALLBACK (ev_window_dual_mode_changed_cb),
@@ -6087,10 +6120,6 @@ ev_window_init (EvWindow *ev_window)
 			  G_CALLBACK (ev_window_continuous_changed_cb),
 			  ev_window);
 	g_signal_connect (ev_window->priv->view,
-			  "notify::rotation",
-			  G_CALLBACK (ev_window_rotation_changed_cb),
-			  ev_window);
-	g_signal_connect (ev_window->priv->view,
 			  "notify::has-selection",
 			  G_CALLBACK (ev_window_has_selection_changed_cb),
 			  ev_window);
@@ -6169,7 +6198,7 @@ ev_window_init (EvWindow *ev_window)
 	setup_view_from_metadata (ev_window);
 	setup_sidebar_from_metadata (ev_window);
 
-        ev_window_sizing_mode_changed_cb (EV_VIEW (ev_window->priv->view), NULL, ev_window);
+        ev_window_sizing_mode_changed_cb (ev_window->priv->model, NULL, ev_window);
 	ev_window_setup_action_sensitivity (ev_window);
 
 	/* Drag and Drop */
diff --git a/shell/ev-window.h b/shell/ev-window.h
index 1df15ec..c95c1a4 100644
--- a/shell/ev-window.h
+++ b/shell/ev-window.h
@@ -27,7 +27,6 @@
 #include <gtk/gtk.h>
 
 #include "ev-link.h"
-#include "ev-page-cache.h"
 
 G_BEGIN_DECLS
 



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