From: Jonathan Blandford Date: Fri, 24 Dec 2004 05:50:50 +0000 (+0000) Subject: * backend/ev-document-bookmarks.h: * pdf/xpdf/Makefile.am: * X-Git-Tag: EVINCE_0_1_0~56 X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=commitdiff_plain;ds=sidebyside;h=51a7800b9832073f1b1c640d7991e6495b2614e0;p=evince.git * backend/ev-document-bookmarks.h: * pdf/xpdf/Makefile.am: * Fri Dec 24 00:48:44 2004 Jonathan Blandford * backend/ev-document-bookmarks.c: (ev_document_bookmarks_get_child): * backend/ev-document-bookmarks.h: * pdf/xpdf/Makefile.am: * pdf/xpdf/pdf-document.cc: * pdf/xpdf/pdf-document.h: * shell/Makefile.am: * shell/ev-sidebar-bookmarks.c: (ev_sidebar_bookmarks_destroy), (ev_sidebar_bookmarks_class_init), (ev_sidebar_bookmarks_construct), (stack_data_free), (do_one_iteration), (populate_bookmarks_idle), (ev_sidebar_bookmarks_clear_document), (ev_sidebar_bookmarks_set_document): * shell/ev-sidebar-bookmarks.h: * shell/ev-sidebar.c: (ev_sidebar_add_page), (ev_sidebar_set_document): * shell/ev-window.c: (ev_window_open): Initial stab at a bookmarks sidebar. It doesn't navigate yet, but it displays both the topics and the page numbers. --- diff --git a/ChangeLog b/ChangeLog index 0a4b8b67..2f5e688f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +Fri Dec 24 00:48:44 2004 Jonathan Blandford + + * backend/ev-document-bookmarks.c: + (ev_document_bookmarks_get_child): * + backend/ev-document-bookmarks.h: * pdf/xpdf/Makefile.am: * + pdf/xpdf/pdf-document.cc: * pdf/xpdf/pdf-document.h: * + shell/Makefile.am: * shell/ev-sidebar-bookmarks.c: + (ev_sidebar_bookmarks_destroy), + (ev_sidebar_bookmarks_class_init), + (ev_sidebar_bookmarks_construct), (stack_data_free), + (do_one_iteration), (populate_bookmarks_idle), + (ev_sidebar_bookmarks_clear_document), + (ev_sidebar_bookmarks_set_document): * + shell/ev-sidebar-bookmarks.h: * shell/ev-sidebar.c: + (ev_sidebar_add_page), + (ev_sidebar_set_document): * shell/ev-window.c: (ev_window_open): + Initial stab at a bookmarks sidebar. It doesn't navigate yet, but + it displays both the topics and the page numbers. + 2004-12-23 Kristian Høgsberg * shell/ev-window.c (ev_window_view_sidebar_cb): Hook up sidebar diff --git a/backend/ev-document-bookmarks.c b/backend/ev-document-bookmarks.c index a98b1e6c..1806cd9a 100644 --- a/backend/ev-document-bookmarks.c +++ b/backend/ev-document-bookmarks.c @@ -62,6 +62,10 @@ ev_document_bookmarks_begin_read (EvDocumentBookmarks *document_bookmarks) return iface->begin_read (document_bookmarks); } + /* + * This function gets the values at a node. You need to g_free the title. + * Additionally, if page is -1, the link doesn't go anywhere. + */ gboolean ev_document_bookmarks_get_values (EvDocumentBookmarks *document_bookmarks, EvDocumentBookmarksIter *iter, @@ -75,12 +79,12 @@ ev_document_bookmarks_get_values (EvDocumentBookmarks *document_bookmarks, } EvDocumentBookmarksIter * -ev_document_bookmarks_has_child (EvDocumentBookmarks *document_bookmarks, +ev_document_bookmarks_get_child (EvDocumentBookmarks *document_bookmarks, EvDocumentBookmarksIter *iter) { EvDocumentBookmarksIface *iface = EV_DOCUMENT_BOOKMARKS_GET_IFACE (document_bookmarks); - return iface->has_child (document_bookmarks, iter); + return iface->get_child (document_bookmarks, iter); } diff --git a/backend/ev-document-bookmarks.h b/backend/ev-document-bookmarks.h index 430e2f64..98a53a64 100644 --- a/backend/ev-document-bookmarks.h +++ b/backend/ev-document-bookmarks.h @@ -67,7 +67,7 @@ struct _EvDocumentBookmarksIface gchar **title, EvDocumentBookmarksType *type, gint *page); - EvDocumentBookmarksIter *(* has_child) (EvDocumentBookmarks *document_bookmarks, + EvDocumentBookmarksIter *(* get_child) (EvDocumentBookmarks *document_bookmarks, EvDocumentBookmarksIter *iter); gboolean (* next) (EvDocumentBookmarks *document_bookmarks, EvDocumentBookmarksIter *iter); @@ -83,7 +83,7 @@ gboolean ev_document_bookmarks_get_values (EvDocumen char **title, EvDocumentBookmarksType *type, gint *page); -EvDocumentBookmarksIter *ev_document_bookmarks_has_child (EvDocumentBookmarks *document_bookmarks, +EvDocumentBookmarksIter *ev_document_bookmarks_get_child (EvDocumentBookmarks *document_bookmarks, EvDocumentBookmarksIter *iter); gboolean ev_document_bookmarks_next (EvDocumentBookmarks *document_bookmarks, EvDocumentBookmarksIter *iter); diff --git a/pdf/xpdf/Makefile.am b/pdf/xpdf/Makefile.am index ab814817..4e0f9287 100644 --- a/pdf/xpdf/Makefile.am +++ b/pdf/xpdf/Makefile.am @@ -110,6 +110,7 @@ test_gdk_output_dev_LDADD = \ $(top_builddir)/pdf/goo/libGoo.la \ $(top_builddir)/pdf/fofi/libfofi.la \ $(top_builddir)/pdf/splash/libsplash.la \ + $(top_builddir)/backend/libevbackend.la \ $(GTK_LIBS) libpdfdocument_la_SOURCES = \ diff --git a/pdf/xpdf/pdf-document.cc b/pdf/xpdf/pdf-document.cc index 50055f0c..e6e72c27 100644 --- a/pdf/xpdf/pdf-document.cc +++ b/pdf/xpdf/pdf-document.cc @@ -26,6 +26,10 @@ #include "GlobalParams.h" #include "GDKSplashOutputDev.h" #include "PDFDoc.h" +#include "Outline.h" +#include "UnicodeMap.h" +#include "GlobalParams.h" +#include "goo/GList.h" #include "PSOutputDev.h" typedef struct @@ -67,13 +71,15 @@ struct _PdfDocument GDKSplashOutputDev *out; PSOutputDev *ps_out; PDFDoc *doc; + UnicodeMap *umap; gboolean page_valid; PdfDocumentSearch *search; }; -static void pdf_document_document_iface_init (EvDocumentIface *iface); +static void pdf_document_document_bookmarks_iface_init (EvDocumentBookmarksIface *iface); +static void pdf_document_document_iface_init (EvDocumentIface *iface); static void pdf_document_ps_exporter_iface_init (EvPSExporterIface *iface); static void pdf_document_find_iface_init (EvDocumentFindIface *iface); static void pdf_document_search_free (PdfDocumentSearch *search); @@ -83,6 +89,8 @@ G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT, { G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT, pdf_document_document_iface_init); + G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_BOOKMARKS, + pdf_document_document_bookmarks_iface_init); G_IMPLEMENT_INTERFACE (EV_TYPE_PS_EXPORTER, pdf_document_ps_exporter_iface_init); G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND, @@ -97,7 +105,7 @@ document_validate_page (PdfDocument *pdf_document) 72 * pdf_document->scale, 72 * pdf_document->scale, 0, gTrue, gTrue); - + pdf_document->page_valid = TRUE; /* Update the search results available to the app since @@ -106,6 +114,8 @@ document_validate_page (PdfDocument *pdf_document) if (pdf_document->search) pdf_document_search_page_changed (pdf_document->search); } + + return pdf_document->page_valid; } static gboolean @@ -118,12 +128,20 @@ pdf_document_load (EvDocument *document, int err; char *filename; GString *filename_g; - + GString *enc; + if (!globalParams) { globalParams = new GlobalParams("/etc/xpdfrc"); globalParams->setupBaseFontsFc(NULL); } + if (! pdf_document->umap) { + enc = new GString("UTF-8"); + pdf_document->umap = globalParams->getUnicodeMap(enc); + pdf_document->umap->incRefCnt (); + delete enc; + } + filename = g_filename_from_uri (uri, NULL, error); if (!filename) return FALSE; @@ -144,7 +162,7 @@ pdf_document_load (EvDocument *document, "Failed to load document (error %d) '%s'\n", err, uri); - + return FALSE; } @@ -158,7 +176,7 @@ pdf_document_load (EvDocument *document, pdf_document->out->startDoc(pdf_document->doc->getXRef()); pdf_document->page_valid = FALSE; - + return TRUE; } @@ -207,11 +225,11 @@ pdf_document_set_target (EvDocument *document, GdkDrawable *target) { PdfDocument *pdf_document = PDF_DOCUMENT (document); - + if (pdf_document->target != target) { if (pdf_document->target) g_object_unref (pdf_document->target); - + pdf_document->target = target; if (pdf_document->target) @@ -240,7 +258,7 @@ pdf_document_set_scale (EvDocument *document, double scale) { PdfDocument *pdf_document = PDF_DOCUMENT (document); - + if (pdf_document->scale != scale) { pdf_document->scale = scale; pdf_document->page_valid = FALSE; @@ -253,7 +271,7 @@ pdf_document_set_page_offset (EvDocument *document, int y) { PdfDocument *pdf_document = PDF_DOCUMENT (document); - + pdf_document->page_x_offset = x; pdf_document->page_y_offset = y; } @@ -291,7 +309,7 @@ pdf_document_render (EvDocument *document, if (!document_validate_page (pdf_document) || !pdf_document->target) return; - + page.x = pdf_document->page_x_offset; page.y = pdf_document->page_y_offset; page.width = pdf_document->out->getBitmapWidth(); @@ -301,7 +319,7 @@ pdf_document_render (EvDocument *document, draw.y = clip_y; draw.width = clip_width; draw.height = clip_height; - + if (gdk_rectangle_intersect (&page, &draw, &draw)) pdf_document->out->redraw (draw.x - page.x, draw.y - page.y, pdf_document->target, @@ -400,16 +418,15 @@ pdf_document_search_page_changed (PdfDocumentSearch *search) result.highlight_area.height = yMax - yMin; g_array_append_val (search->current_page_results, result); - /* Now find further results */ while (pdf_document->out->findText (search->ucs4, search->ucs4_len, gFalse, gTrue, gTrue, gFalse, &xMin, &yMin, &xMax, &yMax)) { - + result.page_num = pdf_document->page; - + result.highlight_area.x = xMin; result.highlight_area.y = yMin; result.highlight_area.width = xMax - xMin; @@ -435,7 +452,6 @@ pdf_document_search_idle_callback (void *data) PdfDocument *pdf_document = search->document; int n_pages; double xMin, yMin, xMax, yMax; - gboolean found; /* Note that PDF page count is 1 through n_pages INCLUSIVE * like a real book. We are looking to add one result for each @@ -620,11 +636,211 @@ pdf_document_ps_export_end (EvPSExporter *exporter) document->ps_out = NULL; } + +/* EvDocumentBookmarks Implementation */ +typedef struct +{ + /* goo GList, not glib */ + GList *items; + int index; + int level; +} BookmarksIter; + +static gchar * +unicode_to_char (OutlineItem *outline_item, + UnicodeMap *uMap) +{ + GString gstr; + gchar buf[8]; /* 8 is enough for mapping an unicode char to a string */ + int i, n; + + for (i = 0; i < outline_item->getTitleLength(); ++i) { + n = uMap->mapUnicode(outline_item->getTitle()[i], buf, sizeof(buf)); + gstr.append(buf, n); + } + + return g_strdup (gstr.getCString ()); +} + + +static gboolean +pdf_document_bookmarks_has_document_bookmarks (EvDocumentBookmarks *document_bookmarks) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document_bookmarks); + Outline *outline; + + g_return_val_if_fail (PDF_IS_DOCUMENT (document_bookmarks), FALSE); + + outline = pdf_document->doc->getOutline(); + if (outline->getItems() != NULL && + outline->getItems()->getLength() > 0) + return TRUE; + + return FALSE; +} + +static EvDocumentBookmarksIter * +pdf_document_bookmarks_begin_read (EvDocumentBookmarks *document_bookmarks) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document_bookmarks); + Outline *outline; + BookmarksIter *iter; + GList *items; + + g_return_val_if_fail (PDF_IS_DOCUMENT (document_bookmarks), NULL); + + outline = pdf_document->doc->getOutline(); + items = outline->getItems(); + if (! items) + return NULL; + + iter = g_new0 (BookmarksIter, 1); + iter->items = items; + iter->index = 0; + iter->level = 0; + + return (EvDocumentBookmarksIter *) iter; +} + +static gboolean +pdf_document_bookmarks_get_values (EvDocumentBookmarks *document_bookmarks, + EvDocumentBookmarksIter *bookmarks_iter, + char **title, + EvDocumentBookmarksType *type, + gint *page) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document_bookmarks); + BookmarksIter *iter = (BookmarksIter *)bookmarks_iter; + OutlineItem *anItem; + LinkAction *link_action; + LinkDest *link_dest = NULL; + LinkURI *link_uri = NULL; + LinkGoTo *link_goto = NULL; + GString *named_dest; + Unicode *link_title; + Ref page_ref; + gint page_num = -1; + + g_return_val_if_fail (PDF_IS_DOCUMENT (document_bookmarks), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (title != NULL, FALSE); + g_return_val_if_fail (type != NULL, FALSE); + g_return_val_if_fail (page != NULL, FALSE); + + anItem = (OutlineItem *)iter->items->get(iter->index); + link_action = anItem->getAction (); + link_title = anItem->getTitle (); + + if (link_action) { + switch (link_action->getKind ()) { + + case actionGoTo: + link_goto = dynamic_cast (link_action); + link_dest = link_goto->getDest (); + named_dest = link_goto->getNamedDest (); + + /* Wow! This seems excessively slow on large + * documents. I need to investigate more... -jrb */ + if (link_dest != NULL) { + link_dest = link_dest->copy (); + } else if (named_dest != NULL) { + named_dest = named_dest->copy (); + link_dest = pdf_document->doc->findDest (named_dest); + delete named_dest; + } + if (link_dest != NULL) { + if (link_dest->isPageRef ()) { + page_ref = link_dest->getPageRef (); + page_num = pdf_document->doc->findPage (page_ref.num, page_ref.gen); + } else { + page_num = link_dest->getPageNum (); + } + + delete link_dest; + } + + break; + case actionURI: + link_uri = dynamic_cast (link_action); + break; + + case actionNamed: + /*Skip, for now */ + default: + g_warning ("Unknown link action type: %d", link_action->getKind ()); + } + + *title = g_strdup (unicode_to_char (anItem, pdf_document->umap)); + } else if (link_title) { + *title = g_strdup (unicode_to_char (anItem, pdf_document->umap)); + } + + *type = EV_DOCUMENT_BOOKMARKS_TYPE_LINK; + *page = page_num; + + return TRUE; +} + +static EvDocumentBookmarksIter * +pdf_document_bookmarks_get_child (EvDocumentBookmarks *document_bookmarks, + EvDocumentBookmarksIter *bookmarks_iter) +{ + BookmarksIter *iter = (BookmarksIter *)bookmarks_iter; + BookmarksIter *child_iter; + OutlineItem *anItem; + + g_return_val_if_fail (PDF_IS_DOCUMENT (document_bookmarks), FALSE); + + anItem = (OutlineItem *)iter->items->get(iter->index); + anItem->open (); + if (! (anItem->hasKids() && anItem->getKids()) ) + return NULL; + + child_iter = g_new0 (BookmarksIter, 1); + child_iter->index = 0; + child_iter->level = iter->level + 1; + child_iter->items = anItem->getKids (); + g_assert (child_iter->items); + + return (EvDocumentBookmarksIter *) child_iter; +} + +static gboolean +pdf_document_bookmarks_next (EvDocumentBookmarks *document_bookmarks, + EvDocumentBookmarksIter *bookmarks_iter) +{ + BookmarksIter *iter = (BookmarksIter *) bookmarks_iter; + + g_return_val_if_fail (PDF_IS_DOCUMENT (document_bookmarks), FALSE); + + iter->index++; + if (iter->index >= iter->items->getLength()) + return FALSE; + + return TRUE; +} + +static void +pdf_document_bookmarks_free_iter (EvDocumentBookmarks *document_bookmarks, + EvDocumentBookmarksIter *iter) +{ + g_return_if_fail (PDF_IS_DOCUMENT (document_bookmarks)); + g_return_if_fail (iter != NULL); + + /* FIXME: Should I close all the nodes?? Free them? */ + g_free (iter); +} + static void pdf_document_finalize (GObject *object) { PdfDocument *pdf_document = PDF_DOCUMENT (object); + if (pdf_document->umap) { + pdf_document->umap->decRefCnt (); + pdf_document->umap = NULL; + } + if (pdf_document->search) pdf_document_search_free (pdf_document->search); @@ -644,7 +860,7 @@ static void pdf_document_class_init (PdfDocumentClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - + gobject_class->finalize = pdf_document_finalize; } @@ -678,6 +894,18 @@ pdf_document_find_iface_init (EvDocumentFindIface *iface) iface->cancel = pdf_document_find_cancel; } +static void +pdf_document_document_bookmarks_iface_init (EvDocumentBookmarksIface *iface) +{ + iface->has_document_bookmarks = pdf_document_bookmarks_has_document_bookmarks; + iface->begin_read = pdf_document_bookmarks_begin_read; + iface->get_values = pdf_document_bookmarks_get_values; + iface->get_child = pdf_document_bookmarks_get_child; + iface->next = pdf_document_bookmarks_next; + iface->free_iter = pdf_document_bookmarks_free_iter; +} + + static void pdf_document_init (PdfDocument *pdf_document) { @@ -685,7 +913,7 @@ pdf_document_init (PdfDocument *pdf_document) pdf_document->page_x_offset = 0; pdf_document->page_y_offset = 0; pdf_document->scale = 1.; - + pdf_document->page_valid = FALSE; } diff --git a/pdf/xpdf/pdf-document.h b/pdf/xpdf/pdf-document.h index 5b119b4d..06a33162 100644 --- a/pdf/xpdf/pdf-document.h +++ b/pdf/xpdf/pdf-document.h @@ -20,6 +20,7 @@ #define __PDF_DOCUMENT_H__ #include "ev-document.h" +#include "ev-document-bookmarks.h" G_BEGIN_DECLS diff --git a/shell/Makefile.am b/shell/Makefile.am index 33e74832..dee7d1f6 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -44,10 +44,10 @@ evince_SOURCES= \ evince_LDADD= \ $(SHELL_LIBS) \ - $(top_builddir)/backend/libevbackend.la \ $(top_builddir)/pdf/xpdf/libpdfdocument.la \ $(top_builddir)/pixbuf/libpixbufdocument.la \ $(top_builddir)/ps/libgtkgs.la \ + $(top_builddir)/backend/libevbackend.la \ $(NULL) BUILT_SOURCES = ev-marshal.h ev-marshal.c diff --git a/shell/ev-sidebar-bookmarks.c b/shell/ev-sidebar-bookmarks.c index e29975a6..b215e1ed 100644 --- a/shell/ev-sidebar-bookmarks.c +++ b/shell/ev-sidebar-bookmarks.c @@ -28,16 +28,26 @@ #include #include "ev-sidebar-bookmarks.h" +#include "ev-document-bookmarks.h" + +/* Amount of time we devote to each iteration of the idle, in microseconds */ +#define IDLE_WORK_LENGTH 5000 + +typedef struct { + EvDocumentBookmarksIter *bookmarks_iter; + GtkTreeIter *tree_iter; +} IdleStackData; struct _EvSidebarBookmarksPrivate { GtkWidget *tree_view; GtkTreeModel *model; EvDocument *current_document; + GList *idle_stack; + guint idle_id; }; enum { BOOKMARKS_COLUMN_MARKUP, - BOOKMARKS_COLUMN_OUTLINE, BOOKMARKS_COLUMN_PAGE_NUM, BOOKMARKS_COLUMN_PAGE_VALID, BOOKMARKS_COLUMN_NUM_COLUMNS @@ -54,15 +64,28 @@ G_DEFINE_TYPE (EvSidebarBookmarks, ev_sidebar_bookmarks, GTK_TYPE_VBOX) #define EV_SIDEBAR_BOOKMARKS_GET_PRIVATE(object) \ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR_BOOKMARKS, EvSidebarBookmarksPrivate)) + +static void +ev_sidebar_bookmarks_destroy (GtkObject *object) +{ + EvSidebarBookmarks *ev_sidebar_bookmarks = (EvSidebarBookmarks *) object; + + g_print ("ev_sidebar_bookmarks_destroy!\n"); + ev_sidebar_bookmarks_clear_document (ev_sidebar_bookmarks); +} + static void ev_sidebar_bookmarks_class_init (EvSidebarBookmarksClass *ev_sidebar_bookmarks_class) { GObjectClass *g_object_class; + GtkObjectClass *gtk_object_class; g_object_class = G_OBJECT_CLASS (ev_sidebar_bookmarks_class); + gtk_object_class = GTK_OBJECT_CLASS (ev_sidebar_bookmarks_class); - g_type_class_add_private (g_object_class, sizeof (EvSidebarBookmarksPrivate)); + gtk_object_class->destroy = ev_sidebar_bookmarks_destroy; + g_type_class_add_private (g_object_class, sizeof (EvSidebarBookmarksPrivate)); } @@ -77,7 +100,6 @@ ev_sidebar_bookmarks_construct (EvSidebarBookmarks *ev_sidebar_bookmarks) priv = ev_sidebar_bookmarks->priv; priv->model = (GtkTreeModel *) gtk_tree_store_new (BOOKMARKS_COLUMN_NUM_COLUMNS, G_TYPE_STRING, - G_TYPE_POINTER, G_TYPE_INT, G_TYPE_BOOLEAN); @@ -89,14 +111,15 @@ ev_sidebar_bookmarks_construct (EvSidebarBookmarks *ev_sidebar_bookmarks) GTK_SHADOW_IN); /* Create tree view */ - priv->tree_view = gtk_tree_view_new (); + priv->tree_view = gtk_tree_view_new_with_model (priv->model); + g_object_unref (priv->model); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE); gtk_container_add (GTK_CONTAINER (swindow), priv->tree_view); gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (priv->tree_view), TRUE); gtk_box_pack_start (GTK_BOX (ev_sidebar_bookmarks), swindow, TRUE, TRUE, 0); gtk_widget_show_all (GTK_WIDGET (ev_sidebar_bookmarks)); - + column = gtk_tree_view_column_new (); gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE); gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), column); @@ -109,7 +132,7 @@ ev_sidebar_bookmarks_construct (EvSidebarBookmarks *ev_sidebar_bookmarks) gtk_tree_view_column_set_attributes (GTK_TREE_VIEW_COLUMN (column), renderer, "markup", BOOKMARKS_COLUMN_MARKUP, NULL); - + renderer = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_end (GTK_TREE_VIEW_COLUMN (column), renderer, FALSE); gtk_tree_view_column_set_cell_data_func (GTK_TREE_VIEW_COLUMN (column), renderer, @@ -167,18 +190,166 @@ ev_sidebar_bookmarks_new (void) return ev_sidebar_bookmarks; } +static void +stack_data_free (IdleStackData *stack_data, + EvDocumentBookmarks *document_bookmarks) +{ + g_assert (stack_data); + + if (stack_data->tree_iter) + gtk_tree_iter_free (stack_data->tree_iter); + if (stack_data->bookmarks_iter) + ev_document_bookmarks_free_iter (document_bookmarks, stack_data->bookmarks_iter); + g_free (stack_data); +} + +static gboolean +do_one_iteration (EvSidebarBookmarks *ev_sidebar_bookmarks) +{ + EvSidebarBookmarksPrivate *priv = ev_sidebar_bookmarks->priv; + IdleStackData *stack_data; + GtkTreeIter tree_iter; + gchar *title = NULL; + EvDocumentBookmarksType type; + EvDocumentBookmarksIter *child_iter; + gint page = -1; + + g_assert (priv->idle_stack); + + stack_data = (IdleStackData *) priv->idle_stack->data; + + if (! ev_document_bookmarks_get_values (EV_DOCUMENT_BOOKMARKS (priv->current_document), + stack_data->bookmarks_iter, + &title, + &type, + &page)) { + g_warning ("mismatch in model. No values available at current level.\n"); + return FALSE; + } + + gtk_tree_store_append (GTK_TREE_STORE (priv->model), &tree_iter, stack_data->tree_iter); + gtk_tree_store_set (GTK_TREE_STORE (priv->model), &tree_iter, + BOOKMARKS_COLUMN_MARKUP, title, + BOOKMARKS_COLUMN_PAGE_NUM, page, + /* FIXME: Handle links for real. */ + BOOKMARKS_COLUMN_PAGE_VALID, (page >= 0), + -1); + g_free (title); + + child_iter = ev_document_bookmarks_get_child (EV_DOCUMENT_BOOKMARKS (priv->current_document), + stack_data->bookmarks_iter); + if (child_iter) { + IdleStackData *child_stack_data; + + child_stack_data = g_new0 (IdleStackData, 1); + child_stack_data->tree_iter = gtk_tree_iter_copy (&tree_iter); + child_stack_data->bookmarks_iter = child_iter; + priv->idle_stack = g_list_prepend (priv->idle_stack, child_stack_data); + + return TRUE; + } + + /* We don't have children, so we need to walk to the next node */ + while (TRUE) { + if (ev_document_bookmarks_next (EV_DOCUMENT_BOOKMARKS (priv->current_document), + stack_data->bookmarks_iter)) + return TRUE; + + /* We're done with this level. Pop it off the idle stack and go + * to the next level */ + stack_data_free (stack_data, EV_DOCUMENT_BOOKMARKS (priv->current_document)); + priv->idle_stack = g_list_delete_link (priv->idle_stack, priv->idle_stack); + if (priv->idle_stack == NULL) + return FALSE; + stack_data = priv->idle_stack->data; + } +} + +static gboolean +populate_bookmarks_idle (gpointer data) +{ + GTimer *timer; + gint i; + gulong microseconds = 0; + + EvSidebarBookmarks *ev_sidebar_bookmarks = (EvSidebarBookmarks *)data; + EvSidebarBookmarksPrivate *priv = ev_sidebar_bookmarks->priv; + + if (priv->idle_stack == NULL) { + priv->idle_id = 0; + return FALSE; + } + + /* The amount of time that reading the next bookmark takes is wildly + * inconsistent, so we constrain it to IDLE_WORK_LENGTH microseconds per + * idle iteration. */ + timer = g_timer_new (); + i = 0; + g_timer_start (timer); + while (do_one_iteration (ev_sidebar_bookmarks)) { + i++; + g_timer_elapsed (timer, µseconds); + if (microseconds > IDLE_WORK_LENGTH) + break; + } + g_timer_destroy (timer); +#if 0 + g_print ("%d rows done this idle in %d\n", i, (int)microseconds); +#endif + return TRUE; +} + +void +ev_sidebar_bookmarks_clear_document (EvSidebarBookmarks *sidebar_bookmarks) +{ + EvSidebarBookmarksPrivate *priv; + + g_return_if_fail (EV_IS_SIDEBAR_BOOKMARKS (sidebar_bookmarks)); + + priv = sidebar_bookmarks->priv; + if (priv->current_document) { + g_object_unref (priv->current_document); + priv->current_document = NULL; + } + gtk_tree_store_clear (GTK_TREE_STORE (priv->model)); + + /* Clear the idle */ + if (priv->idle_id != 0) { + g_source_remove (priv->idle_id); + priv->idle_id = 0; + } + g_list_foreach (priv->idle_stack, (GFunc) stack_data_free, priv->current_document); + g_list_free (priv->idle_stack); + priv->idle_stack = NULL; + +} + void ev_sidebar_bookmarks_set_document (EvSidebarBookmarks *sidebar_bookmarks, EvDocument *document) { EvSidebarBookmarksPrivate *priv; + EvDocumentBookmarksIter *bookmarks_iter; g_return_if_fail (EV_IS_SIDEBAR_BOOKMARKS (sidebar_bookmarks)); g_return_if_fail (EV_IS_DOCUMENT (document)); priv = sidebar_bookmarks->priv; - g_assert (priv->current_document == NULL); + g_object_ref (document); + ev_sidebar_bookmarks_clear_document (sidebar_bookmarks); + priv->current_document = document; + bookmarks_iter = ev_document_bookmarks_begin_read (EV_DOCUMENT_BOOKMARKS (document)); + if (bookmarks_iter) { + IdleStackData *stack_data; + + stack_data = g_new0 (IdleStackData, 1); + stack_data->bookmarks_iter = bookmarks_iter; + stack_data->tree_iter = NULL; + + priv->idle_stack = g_list_prepend (priv->idle_stack, stack_data); + priv->idle_id = g_idle_add (populate_bookmarks_idle, sidebar_bookmarks); + } } diff --git a/shell/ev-sidebar-bookmarks.h b/shell/ev-sidebar-bookmarks.h index 92c5d41a..e3f3cc67 100644 --- a/shell/ev-sidebar-bookmarks.h +++ b/shell/ev-sidebar-bookmarks.h @@ -50,10 +50,11 @@ struct _EvSidebarBookmarksClass { GtkVBoxClass base_class; }; -GType ev_sidebar_bookmarks_get_type (void); -GtkWidget *ev_sidebar_bookmarks_new (void); -void ev_sidebar_bookmarks_set_document (EvSidebarBookmarks *ev_sidebar_bookmarks, - EvDocument *document); +GType ev_sidebar_bookmarks_get_type (void); +GtkWidget *ev_sidebar_bookmarks_new (void); +void ev_sidebar_bookmarks_set_document (EvSidebarBookmarks *ev_sidebar_bookmarks, + EvDocument *document); +void ev_sidebar_bookmarks_clear_document (EvSidebarBookmarks *sidebar_bookmarks); G_END_DECLS diff --git a/shell/ev-sidebar.c b/shell/ev-sidebar.c index 98beaa50..a1f41781 100644 --- a/shell/ev-sidebar.c +++ b/shell/ev-sidebar.c @@ -29,6 +29,7 @@ #include "ev-sidebar.h" #include "ev-document-thumbnails.h" +#include "ev-document-bookmarks.h" #include "ev-sidebar-bookmarks.h" #include "ev-sidebar-thumbnails.h" @@ -178,7 +179,7 @@ ev_sidebar_add_page (EvSidebar *ev_sidebar, /* Set the first item added as active */ if (gtk_combo_box_get_active (GTK_COMBO_BOX (ev_sidebar->priv->option_menu))) - gtk_combo_box_set_active (GTK_COMBO_BOX (ev_sidebar->priv->option_menu), 0); + gtk_combo_box_set_active (GTK_COMBO_BOX (ev_sidebar->priv->option_menu), 1); } void @@ -206,9 +207,9 @@ ev_sidebar_set_document (EvSidebar *sidebar, PAGE_COLUMN_MAIN_WIDGET, &widget, -1); - if (EV_IS_SIDEBAR_BOOKMARKS (widget)) - /* && EV_IS_BOOKMARKS (document) - && ev_bookmarks_has_bookmarks (document)... */ + if (EV_IS_SIDEBAR_BOOKMARKS (widget) + && EV_IS_DOCUMENT_BOOKMARKS (document) + && ev_document_bookmarks_has_document_bookmarks (EV_DOCUMENT_BOOKMARKS (document))) ev_sidebar_bookmarks_set_document (EV_SIDEBAR_BOOKMARKS (widget), document); else if (EV_IS_SIDEBAR_THUMBNAILS (widget) && diff --git a/shell/ev-window.c b/shell/ev-window.c index 2c7676fe..0fa95926 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -257,7 +257,9 @@ ev_window_open (EvWindow *ev_window, const char *uri) mime_type = gnome_vfs_get_mime_type (uri); - if (!strcmp (mime_type, "application/pdf")) + if (mime_type == NULL) + document = NULL; + else if (!strcmp (mime_type, "application/pdf")) document = g_object_new (PDF_TYPE_DOCUMENT, NULL); else if (!strcmp (mime_type, "application/postscript")) document = g_object_new (GTK_GS_TYPE, NULL); @@ -289,7 +291,7 @@ ev_window_open (EvWindow *ev_window, const char *uri) char *error_message; error_message = g_strdup_printf (_("Unhandled MIME type: '%s'"), - mime_type); + mime_type?mime_type:""); unable_to_load (ev_window, error_message); g_free (error_message); }