[epiphany/overview] Add a GdMainView as the overview for EphyWindow



commit 8918d361a42ad8d9fee173aae114845cfd91841d
Author: Claudio Saavedra <csaavedra igalia com>
Date:   Tue Jan 17 16:46:52 2012 +0200

    Add a GdMainView as the overview for EphyWindow
    
    It's still empty and needs plenty of love

 lib/widgets/Makefile.am             |   15 +-
 lib/widgets/ephy-overview-store.c   |  151 +++++++++++
 lib/widgets/ephy-overview-store.h   |   59 ++++
 lib/widgets/gd-main-icon-view.c     |  181 +++++++++++++
 lib/widgets/gd-main-icon-view.h     |   74 ++++++
 lib/widgets/gd-main-list-view.c     |  215 +++++++++++++++
 lib/widgets/gd-main-list-view.h     |   80 ++++++
 lib/widgets/gd-main-view-generic.c  |  144 ++++++++++
 lib/widgets/gd-main-view-generic.h  |  105 ++++++++
 lib/widgets/gd-main-view.c          |  422 +++++++++++++++++++++++++++++
 lib/widgets/gd-main-view.h          |  100 +++++++
 lib/widgets/gd-two-lines-renderer.c |  496 +++++++++++++++++++++++++++++++++++
 lib/widgets/gd-two-lines-renderer.h |   75 ++++++
 src/ephy-window.c                   |   55 ++++-
 14 files changed, 2170 insertions(+), 2 deletions(-)
---
diff --git a/lib/widgets/Makefile.am b/lib/widgets/Makefile.am
index f581674..cf605a2 100644
--- a/lib/widgets/Makefile.am
+++ b/lib/widgets/Makefile.am
@@ -11,6 +11,8 @@ libephywidgets_la_SOURCES = \
 	ephy-node-view.h			\
 	ephy-search-entry.c			\
 	ephy-search-entry.h			\
+	ephy-overview-store.c			\
+	ephy-overview-store.h			\
 	ephy-tree-model-node.c			\
 	ephy-tree-model-node.h			\
 	ephy-tree-model-sort.c			\
@@ -20,11 +22,22 @@ libephywidgets_la_SOURCES = \
 	nautilus-floating-bar.c			\
 	nautilus-floating-bar.h			\
 	totem-glow-button.c			\
-	totem-glow-button.h
+	totem-glow-button.h			\
+	gd-main-icon-view.h			\
+	gd-main-list-view.h			\
+	gd-main-view.h				\
+	gd-main-view-generic.h			\
+	gd-two-lines-renderer.h			\
+	gd-main-icon-view.c			\
+	gd-main-list-view.c			\
+	gd-main-view.c				\
+	gd-main-view-generic.c			\
+	gd-two-lines-renderer.c
 
 libephywidgets_la_CPPFLAGS = \
 	-I$(top_builddir)/lib		\
 	-I$(top_builddir)/lib/widgets	\
+	-I$(top_srcdir)/lib/history	\
 	-I$(top_srcdir)/lib		\
 	-I$(top_srcdir)/embed		\
 	-I$(top_srcdir)/lib/egg		\
diff --git a/lib/widgets/ephy-overview-store.c b/lib/widgets/ephy-overview-store.c
new file mode 100644
index 0000000..0b0dbd5
--- /dev/null
+++ b/lib/widgets/ephy-overview-store.c
@@ -0,0 +1,151 @@
+/* ephy-overview-store.c */
+
+#include "config.h"
+
+#include "gd-main-view.h"
+#include "ephy-overview-store.h"
+
+G_DEFINE_TYPE (EphyOverviewStore, ephy_overview_store, GTK_TYPE_LIST_STORE)
+
+#define OVERVIEW_STORE_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), EPHY_TYPE_OVERVIEW_STORE, EphyOverviewStorePrivate))
+
+struct _EphyOverviewStorePrivate
+{
+  void *history;
+};
+
+
+static void
+ephy_overview_store_get_property (GObject    *object,
+                                  guint       property_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+  switch (property_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+ephy_overview_store_set_property (GObject      *object,
+                                  guint         property_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+  switch (property_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+ephy_overview_store_dispose (GObject *object)
+{
+  G_OBJECT_CLASS (ephy_overview_store_parent_class)->dispose (object);
+}
+
+static void
+ephy_overview_store_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (ephy_overview_store_parent_class)->finalize (object);
+}
+
+static void
+ephy_overview_store_class_init (EphyOverviewStoreClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (EphyOverviewStorePrivate));
+
+  object_class->get_property = ephy_overview_store_get_property;
+  object_class->set_property = ephy_overview_store_set_property;
+  object_class->dispose = ephy_overview_store_dispose;
+  object_class->finalize = ephy_overview_store_finalize;
+}
+
+static void
+ephy_overview_store_init (EphyOverviewStore *self)
+{
+  GType types[5];
+
+  self->priv = OVERVIEW_STORE_PRIVATE (self);
+
+  /* This should be renamed to something that fits Ephy overview
+     instead of using GD column names. */
+  types[GD_MAIN_COLUMN_ID] = G_TYPE_STRING;
+  types[GD_MAIN_COLUMN_TITLE] = G_TYPE_STRING;
+  types[GD_MAIN_COLUMN_AUTHOR] = G_TYPE_STRING;
+  types[GD_MAIN_COLUMN_ICON] = GDK_TYPE_PIXBUF;
+  types[GD_MAIN_COLUMN_MTIME] = G_TYPE_LONG;
+
+  gtk_list_store_set_column_types (GTK_LIST_STORE (self),
+				   5, types);
+}
+
+EphyOverviewStore *
+ephy_overview_store_new (void)
+{
+  return g_object_new (EPHY_TYPE_OVERVIEW_STORE, NULL);
+}
+
+/* This is only needed for the history model: */
+/* static void */
+/* on_top_urls_fetched (EphyHistoryService *service, */
+/* 		     gboolean success, */
+/* 		     gpointer result_data, */
+/* 		     gpointer user_data) */
+
+/* { */
+/*   GList *urls, *iter; */
+/*   EphyHistoryURL *url; */
+/*   GtkListStore *store; */
+
+/*   g_return_if_fail (success == TRUE); */
+
+/*   urls = (GList *) result_data; */
+/*   store = GTK_LIST_STORE (user_data); */
+
+/*   for (iter = urls; iter != NULL; iter = iter->next) { */
+/*     url = (EphyHistoryURL *)iter->data; */
+/*     gtk_list_store_insert_with_values (store, NULL, G_MAXINT, */
+/* 				       /\* GD_MAIN_COLUMN_ID, url->id, *\/ */
+/* 				       GD_MAIN_COLUMN_TITLE, url->title ? url->title : "", */
+/* 				       GD_MAIN_COLUMN_AUTHOR, url->url, */
+/* 				       GD_MAIN_COLUMN_MTIME, url->last_visit_time, */
+/* 				       -1); */
+/*   } */
+
+/*   g_list_free_full (urls, (GDestroyNotify) ephy_history_url_free); */
+/* } */
+
+static void
+fetch_items (EphyOverviewStore *store)
+{
+  /* ephy_browse_history_get_top_urls (store->priv->history, */
+  /* 				    8, */
+  /* 				    (EphyHistoryJobCallback) on_top_urls_fetched, */
+  /* 				    store); */
+}
+
+/* void */
+/* ephy_overview_store_set_browse_history (EphyOverviewStore *store, */
+/* 					EphyBrowseHistory *history) */
+/* { */
+/*   g_return_if_fail (EPHY_IS_OVERVIEW_STORE (store)); */
+/*   g_return_if_fail (EPHY_IS_BROWSE_HISTORY (history)); */
+
+/*   if (store->priv->history == history) */
+/*     return; */
+
+/*   if (store->priv->history) { */
+/*     g_object_unref (store->priv->history); */
+/*     gtk_list_store_clear (GTK_LIST_STORE (store)); */
+/*   } */
+
+/*   store->priv->history = g_object_ref (history); */
+/*   fetch_items (store); */
+/* } */
diff --git a/lib/widgets/ephy-overview-store.h b/lib/widgets/ephy-overview-store.h
new file mode 100644
index 0000000..2c11ea1
--- /dev/null
+++ b/lib/widgets/ephy-overview-store.h
@@ -0,0 +1,59 @@
+/* ephy-overview-store.h */
+
+#ifndef _EPHY_OVERVIEW_STORE_H
+#define _EPHY_OVERVIEW_STORE_H
+
+#include <gtk/gtk.h>
+#include <glib-object.h>
+
+/* #include "ephy-browse-history.h" */
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_OVERVIEW_STORE ephy_overview_store_get_type()
+
+#define EPHY_OVERVIEW_STORE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  EPHY_TYPE_OVERVIEW_STORE, EphyOverviewStore))
+
+#define EPHY_OVERVIEW_STORE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  EPHY_TYPE_OVERVIEW_STORE, EphyOverviewStoreClass))
+
+#define EPHY_IS_OVERVIEW_STORE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  EPHY_TYPE_OVERVIEW_STORE))
+
+#define EPHY_IS_OVERVIEW_STORE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  EPHY_TYPE_OVERVIEW_STORE))
+
+#define EPHY_OVERVIEW_STORE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  EPHY_TYPE_OVERVIEW_STORE, EphyOverviewStoreClass))
+
+typedef struct _EphyOverviewStore EphyOverviewStore;
+typedef struct _EphyOverviewStoreClass EphyOverviewStoreClass;
+typedef struct _EphyOverviewStorePrivate EphyOverviewStorePrivate;
+
+struct _EphyOverviewStore
+{
+  GtkListStore parent;
+
+  EphyOverviewStorePrivate *priv;
+};
+
+struct _EphyOverviewStoreClass
+{
+  GtkListStoreClass parent_class;
+};
+
+GType ephy_overview_store_get_type (void) G_GNUC_CONST;
+
+EphyOverviewStore *ephy_overview_store_new (void);
+/* void ephy_overview_store_set_browse_history (EphyOverviewStore *store, */
+/* 					     EphyBrowseHistory *history); */
+
+G_END_DECLS
+
+#endif /* _EPHY_OVERVIEW_STORE_H */
diff --git a/lib/widgets/gd-main-icon-view.c b/lib/widgets/gd-main-icon-view.c
new file mode 100644
index 0000000..77c1352
--- /dev/null
+++ b/lib/widgets/gd-main-icon-view.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2011 Red Hat, Inc.
+ *
+ * Gnome Documents 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.
+ *
+ * Gnome Documents 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 Gnome Documents; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Cosimo Cecchi <cosimoc redhat com>
+ *
+ */
+
+#include "gd-main-icon-view.h"
+#include "gd-main-view.h"
+#include "gd-main-view-generic.h"
+#include "gd-two-lines-renderer.h"
+
+#include <math.h>
+#include <glib/gi18n.h>
+
+#define VIEW_ITEM_WIDTH 140
+#define VIEW_ITEM_WRAP_WIDTH 128
+#define VIEW_COLUMN_SPACING 20
+#define VIEW_MARGIN 16
+
+static void gd_main_view_generic_iface_init (GdMainViewGenericIface *iface);
+G_DEFINE_TYPE_WITH_CODE (GdMainIconView, gd_main_icon_view, GTK_TYPE_ICON_VIEW,
+                         G_IMPLEMENT_INTERFACE (GD_TYPE_MAIN_VIEW_GENERIC,
+                                                gd_main_view_generic_iface_init))
+
+static void
+on_icon_selection_changed (GtkIconView *iv,
+                           gpointer user_data)
+{
+  GdMainIconView *self = user_data;
+  g_signal_emit_by_name (self, "view-selection-changed");
+}
+
+static void
+gd_main_icon_view_constructed (GObject *obj)
+{
+  GdMainIconView *self = GD_MAIN_ICON_VIEW (obj);
+  GtkCellRenderer *cell;
+
+  G_OBJECT_CLASS (gd_main_icon_view_parent_class)->constructed (obj);
+
+  gtk_widget_set_hexpand (GTK_WIDGET (self), TRUE);
+  gtk_widget_set_vexpand (GTK_WIDGET (self), TRUE);
+
+  g_object_set (self,
+                "item-width", VIEW_ITEM_WIDTH,
+                "column-spacing", VIEW_COLUMN_SPACING,
+                "margin", VIEW_MARGIN,
+                NULL);
+
+  g_signal_connect (self, "selection-changed",
+                    G_CALLBACK (on_icon_selection_changed), self);
+
+  cell = gtk_cell_renderer_pixbuf_new ();
+  g_object_set (cell,
+                "xalign", 0.5,
+                "yalign", 0.5,
+                NULL);
+
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self), cell, FALSE);
+  gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (self), cell,
+                                 "pixbuf", GD_MAIN_COLUMN_ICON);
+
+  cell = gd_two_lines_renderer_new ();
+  g_object_set (cell,
+                "alignment", PANGO_ALIGN_CENTER,
+                "wrap-mode", PANGO_WRAP_WORD_CHAR,
+                "wrap-width", VIEW_ITEM_WRAP_WIDTH,
+                "text-lines", 3,
+                NULL);
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self), cell, FALSE);
+  gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (self), cell,
+                                 "text", GD_MAIN_COLUMN_TITLE);
+  gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (self), cell,
+                                 "line-two", GD_MAIN_COLUMN_AUTHOR);
+}
+
+static void
+gd_main_icon_view_class_init (GdMainIconViewClass *klass)
+{
+  GObjectClass *oclass = G_OBJECT_CLASS (klass);
+
+  oclass->constructed = gd_main_icon_view_constructed;
+}
+
+static void
+gd_main_icon_view_init (GdMainIconView *self)
+{
+  /* nothing */
+}
+
+static GList *
+gd_main_icon_view_get_selection (GdMainViewGeneric *mv)
+{
+  GtkIconView *iv = GTK_ICON_VIEW (mv);
+
+  return gtk_icon_view_get_selected_items (iv);
+}
+
+static GtkTreePath *
+gd_main_icon_view_get_path_at_pos (GdMainViewGeneric *mv,
+                                   gint x,
+                                   gint y)
+{
+  return gtk_icon_view_get_path_at_pos (GTK_ICON_VIEW (mv), x, y);
+}
+
+static void
+gd_main_icon_view_set_selection_mode (GdMainViewGeneric *mv,
+                                      GtkSelectionMode mode)
+{
+  gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (mv), mode);
+}
+
+static void
+gd_main_icon_view_scroll_to_path (GdMainViewGeneric *mv,
+                                  GtkTreePath *path)
+{
+  gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (mv), path, TRUE, 0.5, 0.5);
+}
+
+static gboolean
+gd_main_icon_view_path_is_selected (GdMainViewGeneric *mv,
+                                    GtkTreePath *path)
+{
+  return gtk_icon_view_path_is_selected (GTK_ICON_VIEW (mv), path);
+}
+
+static void
+gd_main_icon_view_select_path (GdMainViewGeneric *mv,
+                               GtkTreePath *path)
+{
+  gtk_icon_view_select_path (GTK_ICON_VIEW (mv), path);
+}
+
+static void
+gd_main_icon_view_unselect_path (GdMainViewGeneric *mv,
+                                 GtkTreePath *path)
+{
+  gtk_icon_view_unselect_path (GTK_ICON_VIEW (mv), path);
+}
+
+static void
+gd_main_icon_view_set_model (GdMainViewGeneric *mv,
+                             GtkTreeModel *model)
+{
+  gtk_icon_view_set_model (GTK_ICON_VIEW (mv), model);
+}
+
+static void
+gd_main_view_generic_iface_init (GdMainViewGenericIface *iface)
+{
+  iface->set_model = gd_main_icon_view_set_model;
+  iface->get_selection = gd_main_icon_view_get_selection;
+  iface->get_path_at_pos = gd_main_icon_view_get_path_at_pos;
+  iface->scroll_to_path = gd_main_icon_view_scroll_to_path;
+  iface->set_selection_mode = gd_main_icon_view_set_selection_mode;
+  iface->path_is_selected = gd_main_icon_view_path_is_selected;
+  iface->select_path = gd_main_icon_view_select_path;
+  iface->unselect_path = gd_main_icon_view_unselect_path;
+}
+
+GtkWidget *
+gd_main_icon_view_new (void)
+{
+  return g_object_new (GD_TYPE_MAIN_ICON_VIEW, NULL);
+}
diff --git a/lib/widgets/gd-main-icon-view.h b/lib/widgets/gd-main-icon-view.h
new file mode 100644
index 0000000..8b89f80
--- /dev/null
+++ b/lib/widgets/gd-main-icon-view.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2011 Red Hat, Inc.
+ *
+ * Gnome Documents 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.
+ *
+ * Gnome Documents 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 Gnome Documents; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Cosimo Cecchi <cosimoc redhat com>
+ *
+ */
+
+#ifndef __GD_MAIN_ICON_VIEW_H__
+#define __GD_MAIN_ICON_VIEW_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GD_TYPE_MAIN_ICON_VIEW gd_main_icon_view_get_type()
+
+#define GD_MAIN_ICON_VIEW(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+   GD_TYPE_MAIN_ICON_VIEW, GdMainIconView))
+
+#define GD_MAIN_ICON_VIEW_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+   GD_TYPE_MAIN_ICON_VIEW, GdMainIconViewClass))
+
+#define GD_IS_MAIN_ICON_VIEW(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+   GD_TYPE_MAIN_ICON_VIEW))
+
+#define GD_IS_MAIN_ICON_VIEW_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+   GD_TYPE_MAIN_ICON_VIEW))
+
+#define GD_MAIN_ICON_VIEW_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+   GD_TYPE_MAIN_ICON_VIEW, GdMainIconViewClass))
+
+typedef struct _GdMainIconView GdMainIconView;
+typedef struct _GdMainIconViewClass GdMainIconViewClass;
+typedef struct _GdMainIconViewPrivate GdMainIconViewPrivate;
+
+struct _GdMainIconView
+{
+  GtkIconView parent;
+
+  GdMainIconViewPrivate *priv;
+};
+
+struct _GdMainIconViewClass
+{
+  GtkIconViewClass parent_class;
+};
+
+GType gd_main_icon_view_get_type (void) G_GNUC_CONST;
+
+GtkWidget * gd_main_icon_view_new (void);
+
+G_END_DECLS
+
+#endif /* __GD_MAIN_ICON_VIEW_H__ */
diff --git a/lib/widgets/gd-main-list-view.c b/lib/widgets/gd-main-list-view.c
new file mode 100644
index 0000000..c5d4c0d
--- /dev/null
+++ b/lib/widgets/gd-main-list-view.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2011 Red Hat, Inc.
+ *
+ * Gnome Documents 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.
+ *
+ * Gnome Documents 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 Gnome Documents; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Cosimo Cecchi <cosimoc redhat com>
+ *
+ */
+
+#include "gd-main-list-view.h"
+#include "gd-main-view.h"
+#include "gd-main-view-generic.h"
+#include "gd-two-lines-renderer.h"
+
+#include <glib/gi18n.h>
+
+struct _GdMainListViewPrivate {
+  GtkTreeViewColumn *tree_col;
+};
+
+static void gd_main_view_generic_iface_init (GdMainViewGenericIface *iface);
+G_DEFINE_TYPE_WITH_CODE (GdMainListView, gd_main_list_view, GTK_TYPE_TREE_VIEW,
+                         G_IMPLEMENT_INTERFACE (GD_TYPE_MAIN_VIEW_GENERIC,
+                                                gd_main_view_generic_iface_init))
+
+static void
+on_tree_selection_changed (GtkTreeSelection *selection,
+                           gpointer user_data)
+{
+  GdMainListView *self = user_data;
+  g_signal_emit_by_name (self, "view-selection-changed");
+}
+
+static void
+gd_main_list_view_constructed (GObject *obj)
+{
+  GdMainListView *self = GD_MAIN_LIST_VIEW (obj);
+  GtkTreeViewColumn *col;
+  GtkCellRenderer *cell;
+  GtkTreeSelection *selection;
+
+  G_OBJECT_CLASS (gd_main_list_view_parent_class)->constructed (obj);
+
+  gtk_widget_set_hexpand (GTK_WIDGET (self), TRUE);
+  gtk_widget_set_vexpand (GTK_WIDGET (self), TRUE);
+
+  g_object_set (self,
+                "headers-visible", FALSE,
+                "enable-search", FALSE,
+                NULL);
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
+  g_signal_connect (selection, "changed",
+                    G_CALLBACK (on_tree_selection_changed), self);
+
+  self->priv->tree_col = gtk_tree_view_column_new ();
+  gtk_tree_view_append_column (GTK_TREE_VIEW (self), self->priv->tree_col);
+
+  cell = gtk_cell_renderer_pixbuf_new ();
+  g_object_set (cell,
+                "xalign", 0.5,
+                "yalign", 0.5,
+                NULL);
+  gtk_tree_view_column_pack_start (self->priv->tree_col, cell, FALSE);
+  gtk_tree_view_column_add_attribute (self->priv->tree_col, cell,
+                                      "pixbuf", GD_MAIN_COLUMN_ICON);
+
+  cell = gd_two_lines_renderer_new ();
+  g_object_set (cell,
+                "alignment", PANGO_ALIGN_LEFT,
+                "wrap-mode", PANGO_WRAP_WORD_CHAR,
+                "xpad", 12,
+                "text-lines", 2,
+                NULL);
+  gtk_tree_view_column_pack_start (self->priv->tree_col, cell, FALSE);
+  gtk_tree_view_column_add_attribute (self->priv->tree_col, cell,
+                                      "text", GD_MAIN_COLUMN_TITLE);
+  gtk_tree_view_column_add_attribute (self->priv->tree_col, cell,
+                                      "line-two", GD_MAIN_COLUMN_AUTHOR);
+}
+
+static void
+gd_main_list_view_class_init (GdMainListViewClass *klass)
+{
+  GObjectClass *oclass = G_OBJECT_CLASS (klass);
+
+  oclass->constructed = gd_main_list_view_constructed;
+
+  g_type_class_add_private (klass, sizeof (GdMainListViewPrivate));
+}
+
+static void
+gd_main_list_view_init (GdMainListView *self)
+{
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GD_TYPE_MAIN_LIST_VIEW, GdMainListViewPrivate);
+}
+
+static GList *
+gd_main_list_view_get_selection (GdMainViewGeneric *mv)
+{
+  GtkTreeSelection *selection;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (mv));
+  return gtk_tree_selection_get_selected_rows (selection, NULL);
+}
+
+static GtkTreePath *
+gd_main_list_view_get_path_at_pos (GdMainViewGeneric *mv,
+                                   gint x,
+                                   gint y)
+{
+  GtkTreePath *path = NULL;
+
+  gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (mv), x, y, &path,
+                                 NULL, NULL, NULL);
+
+  return path;
+}
+
+static void
+gd_main_list_view_set_selection_mode (GdMainViewGeneric *mv,
+                                      GtkSelectionMode mode)
+{
+  GtkTreeSelection *selection;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (mv));
+  gtk_tree_selection_set_mode (selection, mode);
+}
+
+static void
+gd_main_list_view_scroll_to_path (GdMainViewGeneric *mv,
+                                  GtkTreePath *path)
+{
+  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (mv), path, NULL, TRUE, 0.5, 0.5);
+}
+
+static gboolean
+gd_main_list_view_path_is_selected (GdMainViewGeneric *mv,
+                                    GtkTreePath *path)
+{
+  GtkTreeSelection *selection;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (mv));
+  return gtk_tree_selection_path_is_selected (selection, path);
+}
+
+static void
+gd_main_list_view_select_path (GdMainViewGeneric *mv,
+                               GtkTreePath *path)
+{
+  GtkTreeSelection *selection;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (mv));
+  gtk_tree_selection_select_path (selection, path);
+}
+
+static void
+gd_main_list_view_unselect_path (GdMainViewGeneric *mv,
+                                 GtkTreePath *path)
+{
+  GtkTreeSelection *selection;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (mv));
+  gtk_tree_selection_unselect_path (selection, path);
+}
+
+static void
+gd_main_list_view_set_model (GdMainViewGeneric *mv,
+                             GtkTreeModel *model)
+{
+  gtk_tree_view_set_model (GTK_TREE_VIEW (mv), model);
+}
+
+static void
+gd_main_view_generic_iface_init (GdMainViewGenericIface *iface)
+{
+  iface->set_model = gd_main_list_view_set_model;
+  iface->get_selection = gd_main_list_view_get_selection;
+  iface->get_path_at_pos = gd_main_list_view_get_path_at_pos;
+  iface->scroll_to_path = gd_main_list_view_scroll_to_path;
+  iface->set_selection_mode = gd_main_list_view_set_selection_mode;
+  iface->select_path = gd_main_list_view_select_path;
+  iface->unselect_path = gd_main_list_view_unselect_path;
+  iface->path_is_selected = gd_main_list_view_path_is_selected;
+}
+
+void
+gd_main_list_view_add_renderer (GdMainListView *self,
+                                GtkCellRenderer *renderer,
+                                GtkTreeCellDataFunc func,
+                                gpointer user_data,
+                                GDestroyNotify destroy)
+{
+  gtk_tree_view_column_pack_start (self->priv->tree_col, renderer, FALSE);
+  gtk_tree_view_column_set_cell_data_func (self->priv->tree_col, renderer,
+                                           func, user_data, destroy);
+}
+
+GtkWidget *
+gd_main_list_view_new (void)
+{
+  return g_object_new (GD_TYPE_MAIN_LIST_VIEW, NULL);
+}
diff --git a/lib/widgets/gd-main-list-view.h b/lib/widgets/gd-main-list-view.h
new file mode 100644
index 0000000..eb9cece
--- /dev/null
+++ b/lib/widgets/gd-main-list-view.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2011 Red Hat, Inc.
+ *
+ * Gnome Documents 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.
+ *
+ * Gnome Documents 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 Gnome Documents; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Cosimo Cecchi <cosimoc redhat com>
+ *
+ */
+
+#ifndef __GD_MAIN_LIST_VIEW_H__
+#define __GD_MAIN_LIST_VIEW_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GD_TYPE_MAIN_LIST_VIEW gd_main_list_view_get_type()
+
+#define GD_MAIN_LIST_VIEW(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+   GD_TYPE_MAIN_LIST_VIEW, GdMainListView))
+
+#define GD_MAIN_LIST_VIEW_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+   GD_TYPE_MAIN_LIST_VIEW, GdMainListViewClass))
+
+#define GD_IS_MAIN_LIST_VIEW(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+   GD_TYPE_MAIN_LIST_VIEW))
+
+#define GD_IS_MAIN_LIST_VIEW_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+   GD_TYPE_MAIN_LIST_VIEW))
+
+#define GD_MAIN_LIST_VIEW_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+   GD_TYPE_MAIN_LIST_VIEW, GdMainListViewClass))
+
+typedef struct _GdMainListView GdMainListView;
+typedef struct _GdMainListViewClass GdMainListViewClass;
+typedef struct _GdMainListViewPrivate GdMainListViewPrivate;
+
+struct _GdMainListView
+{
+  GtkTreeView parent;
+
+  GdMainListViewPrivate *priv;
+};
+
+struct _GdMainListViewClass
+{
+  GtkTreeViewClass parent_class;
+};
+
+GType gd_main_list_view_get_type (void) G_GNUC_CONST;
+
+GtkWidget * gd_main_list_view_new (void);
+
+void gd_main_list_view_add_renderer (GdMainListView *self,
+                                     GtkCellRenderer *renderer,
+                                     GtkTreeCellDataFunc func,
+                                     gpointer user_data,
+                                     GDestroyNotify destroy);
+
+G_END_DECLS
+
+#endif /* __GD_MAIN_LIST_VIEW_H__ */
diff --git a/lib/widgets/gd-main-view-generic.c b/lib/widgets/gd-main-view-generic.c
new file mode 100644
index 0000000..254dd51
--- /dev/null
+++ b/lib/widgets/gd-main-view-generic.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2011 Red Hat, Inc.
+ *
+ * Gnome Documents 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.
+ *
+ * Gnome Documents 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 Gnome Documents; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Cosimo Cecchi <cosimoc redhat com>
+ *
+ */
+
+#include "gd-main-view-generic.h"
+
+enum {
+  VIEW_SELECTION_CHANGED = 1,
+  NUM_SIGNALS
+};
+
+static guint signals[NUM_SIGNALS] = { 0, };
+
+typedef GdMainViewGenericIface GdMainViewGenericInterface;
+G_DEFINE_INTERFACE (GdMainViewGeneric, gd_main_view_generic, GTK_TYPE_WIDGET)
+
+static void
+gd_main_view_generic_default_init (GdMainViewGenericInterface *iface)
+{
+  signals[VIEW_SELECTION_CHANGED] = 
+    g_signal_new ("view-selection-changed",
+                  GD_TYPE_MAIN_VIEW_GENERIC,
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GdMainViewGenericIface, selection_changed),
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 0);
+}
+
+/**
+ * gd_main_view_generic_set_model:
+ * @self:
+ * @model: (allow-none):
+ *
+ */
+void
+gd_main_view_generic_set_model (GdMainViewGeneric *self,
+                        GtkTreeModel *model)
+{
+  GdMainViewGenericInterface *iface;
+
+  iface = GD_MAIN_VIEW_GENERIC_GET_IFACE (self);
+
+  (* iface->set_model) (self, model);
+}
+
+/**
+ * gd_main_view_generic_get_selection:
+ * @self:
+ *
+ * Returns: (element-type GtkTreePath) (transfer full):
+ */
+GList *
+gd_main_view_generic_get_selection (GdMainViewGeneric *self)
+{
+  GdMainViewGenericInterface *iface;
+
+  iface = GD_MAIN_VIEW_GENERIC_GET_IFACE (self);
+
+  return (* iface->get_selection) (self);
+}
+
+GtkTreePath *
+gd_main_view_generic_get_path_at_pos (GdMainViewGeneric *self,
+                                      gint x,
+                                      gint y)
+{
+  GdMainViewGenericInterface *iface;
+
+  iface = GD_MAIN_VIEW_GENERIC_GET_IFACE (self);
+
+  return (* iface->get_path_at_pos) (self, x, y);
+}
+
+void
+gd_main_view_generic_set_selection_mode (GdMainViewGeneric *self,
+                                         GtkSelectionMode mode)
+{
+  GdMainViewGenericInterface *iface;
+
+  iface = GD_MAIN_VIEW_GENERIC_GET_IFACE (self);
+
+  (* iface->set_selection_mode) (self, mode);
+}
+
+void
+gd_main_view_generic_scroll_to_path (GdMainViewGeneric *self,
+                                     GtkTreePath *path)
+{
+  GdMainViewGenericInterface *iface;
+
+  iface = GD_MAIN_VIEW_GENERIC_GET_IFACE (self);
+
+  (* iface->scroll_to_path) (self, path);
+}
+
+gboolean
+gd_main_view_generic_path_is_selected (GdMainViewGeneric *self,
+                                       GtkTreePath *path)
+{
+  GdMainViewGenericInterface *iface;
+
+  iface = GD_MAIN_VIEW_GENERIC_GET_IFACE (self);
+
+  return (* iface->path_is_selected) (self, path);
+}
+
+void
+gd_main_view_generic_select_path (GdMainViewGeneric *self,
+                                  GtkTreePath *path)
+{
+  GdMainViewGenericInterface *iface;
+
+  iface = GD_MAIN_VIEW_GENERIC_GET_IFACE (self);
+
+  (* iface->select_path) (self, path);
+}
+
+void
+gd_main_view_generic_unselect_path (GdMainViewGeneric *self,
+                                    GtkTreePath *path)
+{
+  GdMainViewGenericInterface *iface;
+
+  iface = GD_MAIN_VIEW_GENERIC_GET_IFACE (self);
+
+  (* iface->unselect_path) (self, path);
+}
diff --git a/lib/widgets/gd-main-view-generic.h b/lib/widgets/gd-main-view-generic.h
new file mode 100644
index 0000000..4a13e2c
--- /dev/null
+++ b/lib/widgets/gd-main-view-generic.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2011 Red Hat, Inc.
+ *
+ * Gnome Documents 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.
+ *
+ * Gnome Documents 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 Gnome Documents; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Cosimo Cecchi <cosimoc redhat com>
+ *
+ */
+
+#ifndef __GD_MAIN_VIEW_GENERIC_H__
+#define __GD_MAIN_VIEW_GENERIC_H__
+
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GD_TYPE_MAIN_VIEW_GENERIC gd_main_view_generic_get_type()
+
+#define GD_MAIN_VIEW_GENERIC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+   GD_TYPE_MAIN_VIEW_GENERIC, GdMainViewGeneric))
+
+#define GD_MAIN_VIEW_GENERIC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+   GD_TYPE_MAIN_VIEW_GENERIC, GdMainViewGenericIface))
+
+#define GD_IS_MAIN_VIEW_GENERIC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+   GD_TYPE_MAIN_VIEW_GENERIC))
+
+#define GD_IS_MAIN_VIEW_GENERIC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+   GD_TYPE_MAIN_VIEW_GENERIC))
+
+#define GD_MAIN_VIEW_GENERIC_GET_IFACE(obj) \
+  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), \
+   GD_TYPE_MAIN_VIEW_GENERIC, GdMainViewGenericIface))
+
+typedef struct _GdMainViewGeneric GdMainViewGeneric;
+typedef struct _GdMainViewGenericIface GdMainViewGenericIface;
+
+struct _GdMainViewGenericIface
+{
+  GTypeInterface base_iface;
+
+  /* signals */
+  void          (* selection_changed)    (GdMainViewGeneric  *view);
+
+  /* vtable */
+  void          (* set_model)            (GdMainViewGeneric  *view,
+                                          GtkTreeModel       *model);
+
+  GtkTreePath * (* get_path_at_pos)      (GdMainViewGeneric *view,
+                                          gint               x, 
+                                          gint               y);
+  void          (* scroll_to_path)       (GdMainViewGeneric *view,
+                                          GtkTreePath       *path);
+  void          (* set_selection_mode)   (GdMainViewGeneric *view,
+                                          GtkSelectionMode   selection_mode);
+  GList *       (* get_selection)        (GdMainViewGeneric *view);
+  gboolean      (* path_is_selected)     (GdMainViewGeneric *view,
+                                          GtkTreePath       *path);
+  void          (* select_path)          (GdMainViewGeneric *view,
+                                          GtkTreePath       *path);
+  void          (* unselect_path)        (GdMainViewGeneric *view,
+                                          GtkTreePath       *path);
+};
+
+GType gd_main_view_generic_get_type (void) G_GNUC_CONST;
+
+void gd_main_view_generic_set_model (GdMainViewGeneric *self,
+                                     GtkTreeModel *model);
+
+void gd_main_view_generic_scroll_to_path (GdMainViewGeneric *self,
+                                          GtkTreePath *path);
+void gd_main_view_generic_set_selection_mode (GdMainViewGeneric *self,
+                                              GtkSelectionMode mode);
+GtkTreePath * gd_main_view_generic_get_path_at_pos (GdMainViewGeneric *self,
+                                                    gint x,
+                                                    gint y);
+GList * gd_main_view_generic_get_selection (GdMainViewGeneric *self);
+gboolean gd_main_view_generic_path_is_selected (GdMainViewGeneric *self,
+                                                GtkTreePath *path);
+void gd_main_view_generic_select_path (GdMainViewGeneric *self,
+                                       GtkTreePath *path);
+void gd_main_view_generic_unselect_path (GdMainViewGeneric *self,
+                                         GtkTreePath *path);
+
+G_END_DECLS
+
+#endif /* __GD_MAIN_VIEW_GENERIC_H__ */
diff --git a/lib/widgets/gd-main-view.c b/lib/widgets/gd-main-view.c
new file mode 100644
index 0000000..5275cd0
--- /dev/null
+++ b/lib/widgets/gd-main-view.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2011 Red Hat, Inc.
+ *
+ * Gnome Documents 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.
+ *
+ * Gnome Documents 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 Gnome Documents; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Cosimo Cecchi <cosimoc redhat com>
+ *
+ */
+
+#include "gd-main-view.h"
+
+#include "gd-main-view-generic.h"
+#include "gd-main-icon-view.h"
+#include "gd-main-list-view.h"
+
+struct _GdMainViewPrivate {
+  GdMainViewType current_type;
+  gboolean selection_mode;
+
+  GtkWidget *current_view;
+  GtkTreeModel *model;
+};
+
+enum {
+  PROP_VIEW_TYPE = 1,
+  PROP_SELECTION_MODE,
+  PROP_MODEL,
+  NUM_PROPERTIES
+};
+
+enum {
+  ITEM_ACTIVATED = 1,
+  SELECTION_MODE_REQUEST,
+  NUM_SIGNALS
+};
+
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
+static guint signals[NUM_SIGNALS] = { 0, };
+
+G_DEFINE_TYPE (GdMainView, gd_main_view, GTK_TYPE_SCROLLED_WINDOW)
+
+static void
+gd_main_view_init (GdMainView *self)
+{
+  GtkStyleContext *context;
+
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GD_TYPE_MAIN_VIEW, GdMainViewPrivate);
+  self->priv->current_type = GD_MAIN_VIEW_NONE;
+
+  gtk_widget_set_hexpand (GTK_WIDGET (self), TRUE);
+  gtk_widget_set_vexpand (GTK_WIDGET (self), TRUE);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (self), GTK_SHADOW_IN);
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (self));
+  gtk_style_context_add_class (context, "documents-scrolledwin");
+}
+
+static void
+gd_main_view_get_property (GObject    *object,
+                           guint       property_id,
+                           GValue     *value,
+                           GParamSpec *pspec)
+{
+  GdMainView *self = GD_MAIN_VIEW (object);
+
+  switch (property_id)
+    {
+    case PROP_VIEW_TYPE:
+      g_value_set_int (value, gd_main_view_get_view_type (self));
+      break;
+    case PROP_SELECTION_MODE:
+      g_value_set_boolean (value, gd_main_view_get_selection_mode (self));
+      break;
+    case PROP_MODEL:
+      g_value_set_object (value, gd_main_view_get_model (self));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gd_main_view_set_property (GObject    *object,
+                           guint       property_id,
+                           const GValue *value,
+                           GParamSpec *pspec)
+{
+  GdMainView *self = GD_MAIN_VIEW (object);
+
+  switch (property_id)
+    {
+    case PROP_VIEW_TYPE:
+      gd_main_view_set_view_type (self, g_value_get_int (value));
+      break;
+    case PROP_SELECTION_MODE:
+      gd_main_view_set_selection_mode (self, g_value_get_boolean (value));
+      break;
+    case PROP_MODEL:
+      gd_main_view_set_model (self, g_value_get_object (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gd_main_view_class_init (GdMainViewClass *klass)
+{
+  GObjectClass *oclass = G_OBJECT_CLASS (klass);
+
+  oclass->get_property = gd_main_view_get_property;
+  oclass->set_property = gd_main_view_set_property;
+
+  properties[PROP_VIEW_TYPE] =
+    g_param_spec_int ("view-type",
+                      "View type",
+                      "View type",
+                      GD_MAIN_VIEW_NONE,
+                      GD_MAIN_VIEW_LIST,
+                      GD_MAIN_VIEW_NONE,
+                      G_PARAM_READWRITE |
+                      G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_SELECTION_MODE] =
+    g_param_spec_boolean ("selection-mode",
+                          "Selection mode",
+                          "Whether the view is in selection mode",
+                          FALSE,
+                          G_PARAM_READWRITE |
+                          G_PARAM_CONSTRUCT |
+                          G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_MODEL] =
+    g_param_spec_object ("model",
+                         "Model",
+                         "The GtkTreeModel",
+                         GTK_TYPE_TREE_MODEL,
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT |
+                         G_PARAM_STATIC_STRINGS);
+
+  signals[ITEM_ACTIVATED] =
+    g_signal_new ("item-activated",
+                  GD_TYPE_MAIN_VIEW,
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL, NULL,
+                  G_TYPE_NONE, 2,
+                  G_TYPE_STRING, 
+                  GTK_TYPE_TREE_PATH);
+
+  signals[SELECTION_MODE_REQUEST] =
+    g_signal_new ("selection-mode-request",
+                  GD_TYPE_MAIN_VIEW,
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL, NULL,
+                  G_TYPE_NONE, 0);
+
+  g_type_class_add_private (klass, sizeof (GdMainViewPrivate));
+  g_object_class_install_properties (oclass, NUM_PROPERTIES, properties);
+}
+
+static GdMainViewGeneric *
+get_generic (GdMainView *self)
+{
+  if (self->priv->current_view != NULL)
+    return GD_MAIN_VIEW_GENERIC (self->priv->current_view);
+
+  return NULL;
+}
+
+static gboolean
+on_button_release_selection_mode (GdMainView *self,
+                                  GdkEventButton *event,
+                                  gboolean entered_mode,
+                                  GtkTreePath *path)
+{
+  GdMainViewGeneric *generic = get_generic (self);
+  gboolean selected;
+
+  selected = gd_main_view_generic_path_is_selected (generic, path);
+
+  if (selected && !entered_mode)
+    gd_main_view_generic_unselect_path (generic, path);
+  else if (!selected)
+    gd_main_view_generic_select_path (generic, path);
+
+  return TRUE;
+}
+
+static gboolean
+on_button_release_view_mode (GdMainView *self,
+                             GdkEventButton *event,
+                             GtkTreePath *path)
+{
+  GtkTreeIter iter;
+  gchar *id;
+
+  if (self->priv->model == NULL)
+    return FALSE;
+
+  if (!gtk_tree_model_get_iter (self->priv->model, &iter, path))
+    return FALSE;
+
+  gtk_tree_model_get (self->priv->model, &iter,
+                      GD_MAIN_COLUMN_ID, &id,
+                      -1);
+
+  g_signal_emit (self, signals[ITEM_ACTIVATED], 0, id, path);
+  g_free (id);
+
+  return TRUE;
+}
+
+static gboolean
+on_button_release_event (GtkWidget *view,
+                         GdkEventButton *event,
+                         gpointer user_data)
+{
+  GdMainView *self = user_data;
+  GdMainViewGeneric *generic = get_generic (self);
+  GtkTreePath *path;
+  gboolean entered_mode = FALSE, selection_mode;
+  gboolean res;
+
+  /* eat double/triple click events */
+  if (event->type != GDK_BUTTON_RELEASE)
+    return TRUE;
+
+  path = gd_main_view_generic_get_path_at_pos (generic, event->x, event->y);
+
+  if (path == NULL)
+    return FALSE;
+
+  selection_mode = self->priv->selection_mode;
+
+  if (!selection_mode)
+    {
+      if ((event->button == 3) ||
+          (event->button == 1) && (event->state & GDK_CONTROL_MASK))
+        {
+          g_signal_emit (self, signals[SELECTION_MODE_REQUEST], 0);
+          selection_mode = TRUE;
+          entered_mode = TRUE;
+        }
+    }
+
+  if (selection_mode)
+    res = on_button_release_selection_mode (self, event, entered_mode, path);
+  else
+    res = on_button_release_view_mode (self, event, path);
+
+  gtk_tree_path_free (path);
+  return res;
+}
+
+static gboolean
+on_button_press_event (GtkWidget *view,
+                       GdkEventButton *event_button,
+                       gpointer user_data)
+{
+  /* TODO: eat button press events for now; in the future we might want
+   * to add support for DnD.
+   */
+  return TRUE;
+}
+
+static void
+gd_main_view_apply_model (GdMainView *self)
+{
+  GdMainViewGeneric *generic = get_generic (self);
+  gd_main_view_generic_set_model (generic, self->priv->model);
+}
+
+static void
+gd_main_view_apply_selection_mode (GdMainView *self)
+{
+  GdMainViewGeneric *generic = get_generic (self);
+
+  if (self->priv->selection_mode)
+    gd_main_view_generic_set_selection_mode (generic, GTK_SELECTION_MULTIPLE);
+  else
+    gd_main_view_generic_set_selection_mode (generic, GTK_SELECTION_NONE);
+}
+
+static void
+gd_main_view_rebuild (GdMainView *self)
+{
+  GtkStyleContext *context;
+
+  if (self->priv->current_type == GD_MAIN_VIEW_NONE)
+    return;
+
+  if (self->priv->current_view != NULL)
+    gtk_widget_destroy (self->priv->current_view);
+
+  if (self->priv->current_type == GD_MAIN_VIEW_ICON)
+    self->priv->current_view = gd_main_icon_view_new ();
+  else
+    self->priv->current_view = gd_main_list_view_new ();
+
+  context = gtk_widget_get_style_context (self->priv->current_view);
+  gtk_style_context_add_class (context, "documents-main-view");
+
+  gtk_container_add (GTK_CONTAINER (self), self->priv->current_view);
+
+  g_signal_connect (self->priv->current_view, "button-press-event",
+                    G_CALLBACK (on_button_press_event), self);
+  g_signal_connect (self->priv->current_view, "button-release-event",
+                    G_CALLBACK (on_button_release_event), self);
+
+  gd_main_view_apply_selection_mode (self);
+  gd_main_view_apply_model (self);
+
+  gtk_widget_show_all (GTK_WIDGET (self));
+}
+
+GtkWidget *
+gd_main_view_new (GdMainViewType type)
+{
+  return g_object_new (GD_TYPE_MAIN_VIEW,
+                       "view-type", type,
+                       NULL);
+}
+
+void
+gd_main_view_set_view_type (GdMainView *self,
+                            GdMainViewType type)
+{
+  if (type != self->priv->current_type)
+    {
+      self->priv->current_type = type;
+      gd_main_view_rebuild (self);
+
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VIEW_TYPE]);
+    }
+}
+
+GdMainViewType
+gd_main_view_get_view_type (GdMainView *self)
+{
+  return self->priv->current_type;
+}
+
+void
+gd_main_view_set_selection_mode (GdMainView *self,
+                                 gboolean selection_mode)
+{
+  if (selection_mode != self->priv->selection_mode)
+    {
+      self->priv->selection_mode = selection_mode;
+      gd_main_view_apply_selection_mode (self);
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTION_MODE]);
+    }
+}
+
+GdMainViewType
+gd_main_view_get_selection_mode (GdMainView *self)
+{
+  return self->priv->selection_mode;
+}
+
+/**
+ * gd_main_view_set_model:
+ * @self:
+ * @model: (allow-none):
+ *
+ */
+void
+gd_main_view_set_model (GdMainView *self,
+                        GtkTreeModel *model)
+{
+  if (model != self->priv->model)
+    {
+      g_clear_object (&self->priv->model);
+
+      if (model)
+        self->priv->model = g_object_ref (model);
+      else
+        self->priv->model = NULL;
+
+      gd_main_view_apply_model (self);
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
+    }
+}
+
+/**
+ * gd_main_view_get_model:
+ * @self:
+ *
+ * Returns: (transfer none):
+ */
+GtkTreeModel *
+gd_main_view_get_model (GdMainView *self)
+{
+  return self->priv->model;
+}
+
+/**
+ * gd_main_view_get_generic_view:
+ * @self:
+ *
+ * Returns: (transfer none):
+ */
+GtkWidget *
+gd_main_view_get_generic_view (GdMainView *self)
+{
+  return self->priv->current_view;
+}
diff --git a/lib/widgets/gd-main-view.h b/lib/widgets/gd-main-view.h
new file mode 100644
index 0000000..e14a6a9
--- /dev/null
+++ b/lib/widgets/gd-main-view.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2011 Red Hat, Inc.
+ *
+ * Gnome Documents 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.
+ *
+ * Gnome Documents 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 Gnome Documents; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Cosimo Cecchi <cosimoc redhat com>
+ *
+ */
+
+#ifndef __GD_MAIN_VIEW_H__
+#define __GD_MAIN_VIEW_H__
+
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GD_TYPE_MAIN_VIEW gd_main_view_get_type()
+
+#define GD_MAIN_VIEW(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+   GD_TYPE_MAIN_VIEW, GdMainView))
+
+#define GD_MAIN_VIEW_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+   GD_TYPE_MAIN_VIEW, GdMainViewIface))
+
+#define GD_IS_MAIN_VIEW(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+   GD_TYPE_MAIN_VIEW))
+
+#define GD_IS_MAIN_VIEW_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+   GD_TYPE_MAIN_VIEW))
+
+#define GD_MAIN_VIEW_GET_IFACE(obj) \
+  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), \
+   GD_TYPE_MAIN_VIEW, GdMainViewIface))
+
+typedef struct _GdMainView GdMainView;
+typedef struct _GdMainViewClass GdMainViewClass;
+typedef struct _GdMainViewPrivate GdMainViewPrivate;
+
+typedef enum {
+  GD_MAIN_COLUMN_ID,
+  GD_MAIN_COLUMN_TITLE,
+  GD_MAIN_COLUMN_AUTHOR,
+  GD_MAIN_COLUMN_ICON,
+  GD_MAIN_COLUMN_MTIME
+} GdMainColumns;
+
+typedef enum {
+  GD_MAIN_VIEW_NONE,
+  GD_MAIN_VIEW_ICON,
+  GD_MAIN_VIEW_LIST
+} GdMainViewType;
+
+struct _GdMainView {
+  GtkScrolledWindow parent;
+
+  GdMainViewPrivate *priv;
+};
+
+struct _GdMainViewClass {
+  GtkScrolledWindowClass parent_class;
+};
+
+GType gd_main_view_get_type (void) G_GNUC_CONST;
+
+GtkWidget * gd_main_view_new (GdMainViewType type);
+void         gd_main_view_set_view_type (GdMainView *self,
+                                         GdMainViewType type);
+GdMainViewType gd_main_view_get_view_type (GdMainView *self);
+
+void gd_main_view_set_selection_mode (GdMainView *self,
+                                      gboolean selection_mode);
+GdMainViewType gd_main_view_get_selection_mode (GdMainView *self);
+
+GtkTreeModel * gd_main_view_get_model (GdMainView *self);
+void gd_main_view_set_model (GdMainView *self,
+                             GtkTreeModel *model);
+
+GtkWidget * gd_main_view_get_generic_view (GdMainView *self);
+
+G_END_DECLS
+
+#endif /* __GD_MAIN_VIEW_H__ */
diff --git a/lib/widgets/gd-two-lines-renderer.c b/lib/widgets/gd-two-lines-renderer.c
new file mode 100644
index 0000000..c69fa0e
--- /dev/null
+++ b/lib/widgets/gd-two-lines-renderer.c
@@ -0,0 +1,496 @@
+/*
+ * Copyright (c) 2011 Red Hat, Inc.
+ *
+ * Gnome Documents 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.
+ *
+ * Gnome Documents 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 Gnome Documents; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Cosimo Cecchi <cosimoc redhat com>
+ *
+ */
+
+#include "gd-two-lines-renderer.h"
+#include <string.h>
+
+G_DEFINE_TYPE (GdTwoLinesRenderer, gd_two_lines_renderer, GTK_TYPE_CELL_RENDERER_TEXT)
+
+struct _GdTwoLinesRendererPrivate {
+  gchar *line_two;
+  gint text_lines;
+};
+
+enum {
+  PROP_TEXT_LINES = 1,
+  PROP_LINE_TWO,
+  NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
+
+static PangoLayout *
+create_layout_with_attrs (GtkWidget *widget,
+                          GdTwoLinesRenderer *self,
+                          PangoEllipsizeMode ellipsize)
+{
+  PangoLayout *layout;
+  gint wrap_width;
+  PangoWrapMode wrap_mode;
+  PangoAlignment alignment;
+
+  g_object_get (self,
+                "wrap-width", &wrap_width,
+                "wrap-mode", &wrap_mode,
+                "alignment", &alignment,
+                NULL);
+
+  layout = pango_layout_new (gtk_widget_get_pango_context (widget));
+
+  pango_layout_set_ellipsize (layout, ellipsize);
+  pango_layout_set_wrap (layout, wrap_mode);
+  pango_layout_set_alignment (layout, alignment);
+
+  if (wrap_width != -1)
+    pango_layout_set_width (layout, wrap_width * PANGO_SCALE);
+
+  return layout;
+}
+
+static void
+gd_two_lines_renderer_prepare_layouts (GdTwoLinesRenderer *self,
+                                       GtkWidget *widget,
+                                       PangoLayout **layout_one,
+                                       PangoLayout **layout_two)
+{
+  PangoLayout *line_one;
+  PangoLayout *line_two = NULL;
+  gchar *text = NULL;
+
+  g_object_get (self,
+                "text", &text,
+                NULL);
+
+  line_one = create_layout_with_attrs (widget, self, PANGO_ELLIPSIZE_MIDDLE);
+
+  if (self->priv->line_two == NULL ||
+      g_strcmp0 (self->priv->line_two, "") == 0)
+    {
+      pango_layout_set_height (line_one, - (self->priv->text_lines));
+      pango_layout_set_text (line_one, text, -1);
+    }
+  else
+    {
+      line_two = create_layout_with_attrs (widget, self, PANGO_ELLIPSIZE_END);
+
+      pango_layout_set_height (line_one, - (self->priv->text_lines - 1));
+      pango_layout_set_height (line_two, -1);
+
+      pango_layout_set_text (line_one, text, -1);
+      pango_layout_set_text (line_two, self->priv->line_two, -1);
+    }
+
+  if (layout_one)
+    *layout_one = line_one;
+  if (layout_two)
+    *layout_two = line_two;
+
+  g_free (text);
+}
+
+static void
+gd_two_lines_renderer_get_size (GtkCellRenderer *cell,
+                                GtkWidget *widget,
+                                PangoLayout *layout_1,
+                                PangoLayout *layout_2,
+                                gint *width,
+                                gint *height,
+                                const GdkRectangle *cell_area,
+                                gint *x_offset,
+                                gint *y_offset)
+{
+  GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (cell);
+  gint xpad, ypad;
+  PangoLayout *layout_one, *layout_two;
+  GdkRectangle layout_one_rect, layout_two_rect, layout_union;
+
+  if (layout_1 == NULL)
+    {
+      gd_two_lines_renderer_prepare_layouts (self, widget, &layout_one, &layout_two);
+    }
+  else
+    {
+      layout_one = g_object_ref (layout_1);
+
+      if (layout_2 != NULL)
+        layout_two = g_object_ref (layout_2);
+      else
+        layout_two = NULL;
+    }
+
+  gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
+  pango_layout_get_pixel_extents (layout_one, NULL, (PangoRectangle *) &layout_one_rect);
+
+  if (layout_two != NULL)
+    {
+      pango_layout_get_pixel_extents (layout_two, NULL, (PangoRectangle *) &layout_two_rect);
+
+      layout_union.width = MAX(layout_one_rect.width, layout_two_rect.width);
+      layout_union.height = layout_one_rect.height + layout_two_rect.height;
+    }
+  else
+    {
+      layout_union = layout_one_rect;
+    }
+
+  g_clear_object (&layout_one);
+  g_clear_object (&layout_two);
+
+  if (cell_area)
+    {
+      gfloat xalign, yalign;
+
+      gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
+
+      layout_union.height = MIN (layout_union.height, cell_area->height - 2 * ypad);
+      layout_union.width  = MIN (layout_union.width, cell_area->width - 2 * xpad);
+
+      if (x_offset)
+	{
+	  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+	    *x_offset = (1.0 - xalign) * (cell_area->width - (layout_union.width + (2 * xpad)));
+	  else 
+	    *x_offset = xalign * (cell_area->width - (layout_union.width + (2 * xpad)));
+	    *x_offset = MAX (*x_offset, 0);
+	}
+      if (y_offset)
+	{
+	  *y_offset = yalign * (cell_area->height - (layout_union.height + (2 * ypad)));
+	  *y_offset = MAX (*y_offset, 0);
+	}
+    }
+  else
+    {
+      if (x_offset) *x_offset = 0;
+      if (y_offset) *y_offset = 0;
+    }
+
+  if (height)
+    *height = ypad * 2 + layout_union.height;
+
+  if (width)
+    *width = xpad * 2 + layout_union.width;
+}
+
+static void
+gd_two_lines_renderer_render (GtkCellRenderer      *cell,
+                              cairo_t              *cr,
+                              GtkWidget            *widget,
+                              const GdkRectangle   *background_area,
+                              const GdkRectangle   *cell_area,
+                              GtkCellRendererState  flags)
+{
+  GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (cell);
+  GtkStyleContext *context;
+  gint line_one_height;
+  GtkStateFlags state;
+  GdkRectangle render_area = *cell_area;
+  gint xpad, ypad, x_offset, y_offset;
+  PangoLayout *layout_one, *layout_two;
+
+  context = gtk_widget_get_style_context (widget);
+  gd_two_lines_renderer_prepare_layouts (self, widget, &layout_one, &layout_two);
+  gd_two_lines_renderer_get_size (cell, widget,
+                                  layout_one, layout_two,
+                                  NULL, NULL,
+                                  cell_area, &x_offset, &y_offset);
+
+  gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
+  render_area.x += xpad + x_offset;
+  render_area.y += ypad;
+
+  pango_layout_set_width (layout_one,
+                          (cell_area->width - x_offset - 2 * xpad) * PANGO_SCALE);
+
+  gtk_render_layout (context, cr,
+                     render_area.x,
+                     render_area.y,
+                     layout_one);
+
+  if (layout_two != NULL)
+    {
+      pango_layout_get_pixel_size (layout_one,
+                                   NULL, &line_one_height);
+
+      gtk_style_context_save (context);
+      gtk_style_context_add_class (context, "dim-label");
+
+      state = gtk_cell_renderer_get_state (cell, widget, flags);
+      gtk_style_context_set_state (context, state);
+
+      pango_layout_set_width (layout_two,
+                              (cell_area->width - x_offset - 2 * xpad) * PANGO_SCALE);
+
+      gtk_render_layout (context, cr,
+                         render_area.x,
+                         render_area.y + line_one_height,
+                         layout_two);
+
+      gtk_style_context_restore (context);
+    }
+
+  g_clear_object (&layout_one);
+  g_clear_object (&layout_two);
+}
+
+static void
+gd_two_lines_renderer_get_preferred_width (GtkCellRenderer *cell,
+                                           GtkWidget       *widget,
+                                           gint            *minimum_size,
+                                           gint            *natural_size)
+{
+  PangoContext *context;
+  PangoFontMetrics *metrics;
+  const PangoFontDescription *font_desc;
+  GtkStyleContext *style_context;
+  gint nat_width, min_width;
+  gint xpad, char_width, wrap_width, text_width;
+  gint width_chars, ellipsize_chars;
+
+  g_object_get (cell,
+                "xpad", &xpad,
+                "width-chars", &width_chars,
+                "wrap-width", &wrap_width,
+                NULL);
+  style_context = gtk_widget_get_style_context (widget);
+  gtk_cell_renderer_get_padding (cell, &xpad, NULL);
+
+  gd_two_lines_renderer_get_size (cell, widget,
+                                  NULL, NULL,
+                                  &text_width, NULL,
+                                  NULL, NULL, NULL);
+
+  /* Fetch the average size of a charachter */
+  context = gtk_widget_get_pango_context (widget);
+  font_desc = gtk_style_context_get_font (style_context, 0);
+  metrics = pango_context_get_metrics (context, font_desc,
+                                       pango_context_get_language (context));
+
+  char_width = pango_font_metrics_get_approximate_char_width (metrics);
+
+  pango_font_metrics_unref (metrics);
+
+  /* enforce minimum width for ellipsized labels at ~3 chars */
+  ellipsize_chars = 3;
+
+  /* If no width-chars set, minimum for wrapping text will be the wrap-width */
+  if (wrap_width > -1)
+    min_width = xpad * 2 + MIN (text_width, wrap_width);
+  else
+    min_width = xpad * 2 +
+      MIN (text_width,
+           (PANGO_PIXELS (char_width) * MAX (width_chars, ellipsize_chars)));
+
+  if (width_chars > 0)
+    nat_width = xpad * 2 +
+      MAX ((PANGO_PIXELS (char_width) * width_chars), text_width);
+  else
+    nat_width = xpad * 2 + text_width;
+
+  nat_width = MAX (nat_width, min_width);
+
+  if (minimum_size)
+    *minimum_size = min_width;
+
+  if (natural_size)
+    *natural_size = nat_width;
+}
+
+static void
+gd_two_lines_renderer_get_preferred_height_for_width (GtkCellRenderer *cell,
+                                                      GtkWidget       *widget,
+                                                      gint             width,
+                                                      gint            *minimum_size,
+                                                      gint            *natural_size)
+{
+  gint text_height;
+  gint ypad;
+
+  gd_two_lines_renderer_get_size (cell, widget,
+                                  NULL, NULL,
+                                  NULL, &text_height,
+                                  NULL, NULL, NULL);
+
+  gtk_cell_renderer_get_padding (cell, NULL, &ypad);
+  text_height += 2 * ypad;
+
+  if (minimum_size != NULL)
+    *minimum_size = text_height;
+
+  if (natural_size != NULL)
+    *natural_size = text_height;
+}
+
+static void
+gd_two_lines_renderer_get_preferred_height (GtkCellRenderer *cell,
+                                            GtkWidget       *widget,
+                                            gint            *minimum_size,
+                                            gint            *natural_size)
+{
+  gint min_width;
+
+  gtk_cell_renderer_get_preferred_width (cell, widget, &min_width, NULL);
+  gd_two_lines_renderer_get_preferred_height_for_width (cell, widget, min_width,
+                                                        minimum_size, natural_size);
+}
+
+static void
+gd_two_lines_renderer_get_aligned_area (GtkCellRenderer      *cell,
+                                        GtkWidget            *widget,
+                                        GtkCellRendererState  flags,
+                                        const GdkRectangle   *cell_area,
+                                        GdkRectangle         *aligned_area)
+{
+  gint x_offset, y_offset;
+
+  gd_two_lines_renderer_get_size (cell, widget,
+                                  NULL, NULL,
+                                  &aligned_area->width, &aligned_area->height,
+                                  cell_area, &x_offset, &y_offset);
+
+  aligned_area->x = cell_area->x + x_offset;
+  aligned_area->y = cell_area->y;
+}
+
+static void
+gd_two_lines_renderer_set_line_two (GdTwoLinesRenderer *self,
+                                    const gchar *line_two)
+{
+  if (g_strcmp0 (self->priv->line_two, line_two) == 0)
+    return;
+
+  g_free (self->priv->line_two);
+  self->priv->line_two = g_strdup (line_two);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LINE_TWO]);
+}
+
+static void
+gd_two_lines_renderer_set_text_lines (GdTwoLinesRenderer *self,
+                                      gint text_lines)
+{
+  if (self->priv->text_lines == text_lines)
+    return;
+
+  self->priv->text_lines = text_lines;
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TEXT_LINES]);
+}
+
+static void
+gd_two_lines_renderer_set_property (GObject    *object,
+                                    guint       property_id,
+                                    const GValue     *value,
+                                    GParamSpec *pspec)
+{
+  GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (object);
+
+  switch (property_id)
+    {
+    case PROP_TEXT_LINES:
+      gd_two_lines_renderer_set_text_lines (self, g_value_get_int (value));
+      break;
+    case PROP_LINE_TWO:
+      gd_two_lines_renderer_set_line_two (self, g_value_get_string (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gd_two_lines_renderer_get_property (GObject    *object,
+                                    guint       property_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+  GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (object);
+
+  switch (property_id)
+    {
+    case PROP_TEXT_LINES:
+      g_value_set_int (value, self->priv->text_lines);
+      break;
+    case PROP_LINE_TWO:
+      g_value_set_string (value, self->priv->line_two);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gd_two_lines_renderer_finalize (GObject *object)
+{
+  GdTwoLinesRenderer *self = GD_TWO_LINES_RENDERER (object);
+
+  g_free (self->priv->line_two);
+
+  G_OBJECT_CLASS (gd_two_lines_renderer_parent_class)->finalize (object);
+}
+
+static void
+gd_two_lines_renderer_class_init (GdTwoLinesRendererClass *klass)
+{
+  GtkCellRendererClass *cclass = GTK_CELL_RENDERER_CLASS (klass);
+  GObjectClass *oclass = G_OBJECT_CLASS (klass);
+
+  cclass->render = gd_two_lines_renderer_render;
+  cclass->get_preferred_width = gd_two_lines_renderer_get_preferred_width;
+  cclass->get_preferred_height = gd_two_lines_renderer_get_preferred_height;
+  cclass->get_preferred_height_for_width = gd_two_lines_renderer_get_preferred_height_for_width;
+  cclass->get_aligned_area = gd_two_lines_renderer_get_aligned_area;
+
+  oclass->set_property = gd_two_lines_renderer_set_property;
+  oclass->get_property = gd_two_lines_renderer_get_property;
+  oclass->finalize = gd_two_lines_renderer_finalize;
+  
+  properties[PROP_TEXT_LINES] =
+    g_param_spec_int ("text-lines",
+                      "Lines of text",
+                      "The total number of lines to be displayed",
+                      2, G_MAXINT, 2,
+                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_LINE_TWO] =
+    g_param_spec_string ("line-two",
+                         "Second line",
+                         "Second line",
+                         NULL,
+                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  g_type_class_add_private (klass, sizeof (GdTwoLinesRendererPrivate));
+  g_object_class_install_properties (oclass, NUM_PROPERTIES, properties);
+}
+
+static void
+gd_two_lines_renderer_init (GdTwoLinesRenderer *self)
+{
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GD_TYPE_TWO_LINES_RENDERER,
+                                            GdTwoLinesRendererPrivate);
+}
+
+GtkCellRenderer *
+gd_two_lines_renderer_new (void)
+{
+  return g_object_new (GD_TYPE_TWO_LINES_RENDERER, NULL);
+}
diff --git a/lib/widgets/gd-two-lines-renderer.h b/lib/widgets/gd-two-lines-renderer.h
new file mode 100644
index 0000000..8dd3e51
--- /dev/null
+++ b/lib/widgets/gd-two-lines-renderer.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2011 Red Hat, Inc.
+ *
+ * Gnome Documents 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.
+ *
+ * Gnome Documents 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 Gnome Documents; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Cosimo Cecchi <cosimoc redhat com>
+ *
+ */
+
+#ifndef _GD_TWO_LINES_RENDERER_H
+#define _GD_TWO_LINES_RENDERER_H
+
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GD_TYPE_TWO_LINES_RENDERER gd_two_lines_renderer_get_type()
+
+#define GD_TWO_LINES_RENDERER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+   GD_TYPE_TWO_LINES_RENDERER, GdTwoLinesRenderer))
+
+#define GD_TWO_LINES_RENDERER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+   GD_TYPE_TWO_LINES_RENDERER, GdTwoLinesRendererClass))
+
+#define GD_IS_TWO_LINES_RENDERER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+   GD_TYPE_TWO_LINES_RENDERER))
+
+#define GD_IS_TWO_LINES_RENDERER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+   GD_TYPE_TWO_LINES_RENDERER))
+
+#define GD_TWO_LINES_RENDERER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+   GD_TYPE_TWO_LINES_RENDERER, GdTwoLinesRendererClass))
+
+typedef struct _GdTwoLinesRenderer GdTwoLinesRenderer;
+typedef struct _GdTwoLinesRendererClass GdTwoLinesRendererClass;
+typedef struct _GdTwoLinesRendererPrivate GdTwoLinesRendererPrivate;
+
+struct _GdTwoLinesRenderer
+{
+  GtkCellRendererText parent;
+
+  GdTwoLinesRendererPrivate *priv;
+};
+
+struct _GdTwoLinesRendererClass
+{
+  GtkCellRendererTextClass parent_class;
+};
+
+GType gd_two_lines_renderer_get_type (void) G_GNUC_CONST;
+
+GtkCellRenderer *gd_two_lines_renderer_new (void);
+
+G_END_DECLS
+
+#endif /* _GD_TWO_LINES_RENDERER_H */
diff --git a/src/ephy-window.c b/src/ephy-window.c
index 71c2f47..4540cbe 100644
--- a/src/ephy-window.c
+++ b/src/ephy-window.c
@@ -47,6 +47,7 @@
 #include "ephy-location-entry.h"
 #include "ephy-navigation-history-action.h"
 #include "ephy-notebook.h"
+#include "ephy-overview-store.h"
 #include "ephy-page-menu-action.h"
 #include "ephy-prefs.h"
 #include "ephy-settings.h"
@@ -61,6 +62,7 @@
 #include "ephy-zoom.h"
 #include "popup-commands.h"
 #include "window-commands.h"
+#include "gd-main-view.h"
 
 #include <gdk/gdkkeysyms.h>
 #include <gio/gio.h>
@@ -431,6 +433,7 @@ struct _EphyWindowPrivate
 	guint idle_worker;
 	GtkWidget *entry;
 	GtkWidget *downloads_box;
+	GtkWidget *main_view;
 
 	guint clear_progress_timeout_id;
 	gulong set_focus_handler;
@@ -3162,6 +3165,49 @@ setup_notebook (EphyWindow *window)
 }
 
 static void
+main_view_item_activated (GtkWidget *widget,
+			  gchar *id,
+			  GtkTreePath *path,
+			  EphyWindow *window)
+{
+	char *url;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+
+	model = gd_main_view_get_model (GD_MAIN_VIEW (widget));
+	gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_model_get (model, &iter,
+			    GD_MAIN_COLUMN_AUTHOR,
+			    &url, -1);
+	ephy_window_open_link (EPHY_LINK (window), url, NULL, 0);
+	gtk_widget_hide (window->priv->main_view);
+	gtk_widget_show (GTK_WIDGET (window->priv->notebook));
+}
+
+static void
+setup_main_view (EphyWindow *window)
+{
+	EphyOverviewStore *store;
+	GtkWidget *main_view = window->priv->main_view;
+	store = ephy_overview_store_new ();
+	/* ephy_overview_store_set_browse_history (store, */
+	/* 					EPHY_BROWSE_HISTORY (ephy_embed_shell_get_global_browse_history (embed_shell))); */
+	/* gtk_list_store_insert_with_values (GTK_LIST_STORE (store), */
+	/* 				   NULL, */
+	/* 				   G_MAXINT, */
+	/* 				   GD_MAIN_COLUMN_ID, "1", */
+	/* 				   GD_MAIN_COLUMN_TITLE, "Facebook", */
+	/* 				   GD_MAIN_COLUMN_AUTHOR, "http://www.facebook.com";, */
+	/* 				   -1); */
+
+	gd_main_view_set_model (GD_MAIN_VIEW (main_view),
+				GTK_TREE_MODEL (store));
+
+	g_signal_connect (main_view, "item-activated",
+			  G_CALLBACK (main_view_item_activated), window);
+}
+
+static void
 ephy_window_set_chrome (EphyWindow *window, EphyWebViewChrome mask)
 {
 	EphyWebViewChrome chrome_mask = mask;
@@ -3660,6 +3706,13 @@ ephy_window_constructor (GType type,
 	/* Setup the UI manager and connect verbs */
 	setup_ui_manager (window);
 
+	priv->main_view = gd_main_view_new (GD_MAIN_VIEW_ICON);
+	setup_main_view (window);
+	gtk_box_pack_start (GTK_BOX (priv->main_vbox),
+			    priv->main_view,
+			    TRUE, TRUE, 0);
+	gtk_widget_show (priv->main_view);
+
 	/* Create the notebook. */
 	/* FIXME: the notebook needs to exist before the toolbar,
 	 * because EphyLocationEntry uses it... */
@@ -3673,7 +3726,7 @@ ephy_window_constructor (GType type,
 	gtk_box_pack_start (GTK_BOX (priv->main_vbox),
 			    GTK_WIDGET (priv->notebook),
 			    TRUE, TRUE, 0);
-	gtk_widget_show (GTK_WIDGET (priv->notebook));
+	gtk_widget_hide (GTK_WIDGET (priv->notebook));
 	ephy_notebook_set_dnd_enabled (EPHY_NOTEBOOK (priv->notebook), !priv->is_popup);
 
 	priv->find_toolbar = ephy_find_toolbar_new (window);



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