+2007-01-28 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
+
+ * NOTES:
+ * backend/djvu/djvu-links.c: (djvu_links_get_links_model):
+ * backend/pdf/ev-poppler.cc:
+ * libdocument/ev-document-links.h:
+ * libdocument/ev-link.c: (ev_link_get_page):
+ * libdocument/ev-link.h:
+ * shell/ev-history.c: (ev_history_init), (ev_history_class_init),
+ (ev_history_add_link):
+ * shell/ev-history.h:
+ * shell/ev-navigation-action.c: (activate_menu_item_cb),
+ (new_history_menu_item), (build_menu):
+ * shell/ev-page-cache.c: (ev_page_cache_set_current_page_history):
+ * shell/ev-sidebar-links.c: (create_loading_model),
+ (print_section_cb), (ev_sidebar_links_construct),
+ (fill_page_labels), (update_page_callback_foreach),
+ (update_page_callback), (job_finished_callback):
+ * shell/ev-view.c: (ev_view_handle_link):
+ * shell/ev-window.c: (ev_window_find_chapter),
+ (ev_window_add_history), (view_handle_link_cb),
+ (history_changed_cb):
+
+ Implements another history variant
+
2007-01-28 Carlos Garcia Campos <carlosgc@gnome.org>
* shell/ev-window.c: (view_external_link_cb):
* click-drag, dbl click, triple click, shift-click, search, shift-cursor move
+
+THOUGHTS ON HISTORY:
+====================
+
+ * We need single history button, back/forward will complicate things.
+
+ * When we jump on dest link we should add current page and link to the history.
+
+ * When we jump on external link we should just add external link.
+
+ * It's enough to have 7 entries in history, too many entries complicates things.
+
+ * We should avoid duplicate entries in history. If we'll activate entry
+ that already exists (have the same title) we can just move it to the top.
+
+
+
+
+
+
+
+
+
model = (GtkTreeModel *) gtk_tree_store_new (EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS,
G_TYPE_STRING,
G_TYPE_OBJECT,
- G_TYPE_BOOLEAN);
+ G_TYPE_BOOLEAN,
+ G_TYPE_STRING);
build_tree (djvu_document, model, NULL, outline);
ddjvu_miniexp_release (djvu_document->d_document, outline);
model = (GtkTreeModel *) gtk_tree_store_new (EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS,
G_TYPE_STRING,
G_TYPE_OBJECT,
- G_TYPE_BOOLEAN);
+ G_TYPE_BOOLEAN,
+ G_TYPE_STRING);
build_tree (pdf_document, model, NULL, iter);
poppler_index_iter_free (iter);
}
EV_DOCUMENT_LINKS_COLUMN_MARKUP,
EV_DOCUMENT_LINKS_COLUMN_LINK,
EV_DOCUMENT_LINKS_COLUMN_EXPAND,
+ EV_DOCUMENT_LINKS_COLUMN_PAGE_LABEL,
EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS
};
return link;
}
+gint
+ev_link_get_page (EvLink *link)
+{
+ EvLinkAction *action;
+ EvLinkDest *dest;
+
+ action = ev_link_get_action (link);
+ if (!action)
+ return -1;
+
+ if (ev_link_action_get_action_type (action) !=
+ EV_LINK_ACTION_TYPE_GOTO_DEST)
+ return -1;
+
+ dest = ev_link_action_get_dest (action);
+ if (dest)
+ return ev_link_dest_get_page (dest);
+
+ return -1;
+}
const gchar *ev_link_get_title (EvLink *self);
EvLinkAction *ev_link_get_action (EvLink *self);
+gint ev_link_get_page (EvLink *link);
/* Link Mapping stuff */
typedef struct _EvLinkMapping EvLinkMapping;
#include "config.h"
#include <glib/gi18n.h>
+#include <string.h>
#include "ev-history.h"
struct _EvHistoryPrivate
{
GList *links;
- int current_index;
-};
-
-enum {
- PROP_0,
- PROP_INDEX
};
static void ev_history_init (EvHistory *history);
history->priv = EV_HISTORY_GET_PRIVATE (history);
history->priv->links = NULL;
- history->priv->current_index = -1;
}
static void
G_OBJECT_CLASS (ev_history_parent_class)->finalize (object);
}
-static void
-ev_history_get_property (GObject *object, guint prop_id, GValue *value,
- GParamSpec *param_spec)
-{
- EvHistory *self;
-
- self = EV_HISTORY (object);
-
- switch (prop_id) {
- case PROP_INDEX:
- g_value_set_int (value, self->priv->current_index);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
- prop_id,
- param_spec);
- break;
- }
-}
-
-static void
-ev_history_set_property (GObject *object, guint prop_id, const GValue *value,
- GParamSpec *param_spec)
-{
- EvHistory *self;
-
- self = EV_HISTORY (object);
-
- switch (prop_id) {
- case PROP_INDEX:
- ev_history_set_current_index (self, g_value_get_int (value));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
- prop_id,
- param_spec);
- break;
- }
-}
-
static void
ev_history_class_init (EvHistoryClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = ev_history_finalize;
- object_class->set_property = ev_history_set_property;
- object_class->get_property = ev_history_get_property;
-
- g_object_class_install_property (object_class,
- PROP_INDEX,
- g_param_spec_int ("index",
- "Current Index",
- "The current index",
- -1,
- G_MAXINT,
- 0,
- G_PARAM_READWRITE));
g_type_class_add_private (object_class, sizeof (EvHistoryPrivate));
}
+#define HISTORY_LENGTH 7
+
void
ev_history_add_link (EvHistory *history, EvLink *link)
{
- int length;
+ GList *l;
g_return_if_fail (EV_IS_HISTORY (history));
g_return_if_fail (EV_IS_LINK (link));
+ for (l = history->priv->links; l; l = l->next) {
+ if (!strcmp (ev_link_get_title (EV_LINK (l->data)), ev_link_get_title (link))) {
+ g_object_unref (G_OBJECT (l->data));
+ history->priv->links = g_list_delete_link (history->priv->links, l);
+ break;
+ }
+ }
g_object_ref (link);
history->priv->links = g_list_append (history->priv->links,
link);
-
- length = g_list_length (history->priv->links);
- history->priv->current_index = length - 1;
-}
-
-void
-ev_history_add_page (EvHistory *history, int page, const gchar *label)
-{
- EvLink *link;
- EvLinkDest *dest;
- EvLinkAction *action;
- gchar *title;
-
- g_return_if_fail (EV_IS_HISTORY (history));
-
- title = g_strdup_printf (_("Page: %s"), label);
-
- dest = ev_link_dest_new_page (page);
- action = ev_link_action_new_dest (dest);
- link = ev_link_new (title, action);
- g_free (title);
-
- ev_history_add_link (history, link);
+
+ if (g_list_length (history->priv->links) > HISTORY_LENGTH) {
+ g_object_unref (G_OBJECT (history->priv->links->data));
+ history->priv->links = g_list_delete_link (history->priv->links,
+ history->priv->links);
+ }
}
EvLink *
return g_list_length (history->priv->links);
}
-int
-ev_history_get_current_index (EvHistory *history)
-{
- g_return_val_if_fail (EV_IS_HISTORY (history), -1);
-
- return history->priv->current_index;
-}
-
-void
-ev_history_set_current_index (EvHistory *history, int index)
-{
- g_return_if_fail (EV_IS_HISTORY (history));
-
- history->priv->current_index = index;
-
- g_object_notify (G_OBJECT (history), "index");
-}
-
EvHistory *
ev_history_new (void)
{
return EV_HISTORY (g_object_new (EV_TYPE_HISTORY, NULL));
}
+
EvHistory *ev_history_new (void);
void ev_history_add_link (EvHistory *history,
EvLink *linkk);
-void ev_history_add_page (EvHistory *history,
- int page,
- const gchar *label);
EvLink *ev_history_get_link_nth (EvHistory *history,
int index);
int ev_history_get_n_links (EvHistory *history);
-int ev_history_get_current_index (EvHistory *history);
-void ev_history_set_current_index (EvHistory *history,
- int index);
G_END_DECLS
g_return_if_fail (EV_IS_HISTORY (action->priv->history));
index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "index"));
- ev_history_set_current_index (action->priv->history, index);
if (action->priv->history) {
EvLink *link;
title = ev_link_get_title (link);
item = gtk_image_menu_item_new_with_label (title);
+ gtk_label_set_use_markup (GTK_LABEL (gtk_bin_get_child (GTK_BIN (item))), TRUE);
g_object_set_data (G_OBJECT (item), "index",
GINT_TO_POINTER (index));
return GTK_WIDGET (menu);
}
- start = MAX (ev_history_get_current_index (action->priv->history) - 5, 0);
- end = MIN (ev_history_get_n_links (history), start + 7);
+ start = 0;
+ end = ev_history_get_n_links (history);
for (i = start; i < end; i++) {
link = ev_history_get_link_nth (history, i);
int page)
{
if (abs (page - page_cache->current_page) > 1)
- g_signal_emit (page_cache, signals [HISTORY_CHANGED], 0, page_cache->current_page);
-
+ g_signal_emit (page_cache, signals [HISTORY_CHANGED], 0, page);
+
ev_page_cache_set_current_page (page_cache, page);
}
N_SIGNALS
};
-static void links_page_num_func (GtkTreeViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- EvSidebarLinks *sidebar_links);
static void update_page_callback (EvPageCache *page_cache,
gint current_page,
EvSidebarLinks *sidebar_links);
retval = (GtkTreeModel *)gtk_list_store_new (EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS,
G_TYPE_STRING,
G_TYPE_OBJECT,
- G_TYPE_BOOLEAN);
+ G_TYPE_BOOLEAN,
+ G_TYPE_STRING);
gtk_list_store_append (GTK_LIST_STORE (retval), &iter);
markup = g_strdup_printf ("<span size=\"larger\" style=\"italic\">%s</span>", _("Loading..."));
return retval;
}
-static gint
-get_page_from_link (EvLink *link)
-{
- EvLinkAction *action;
- EvLinkDest *dest;
-
- action = ev_link_get_action (link);
- if (!action)
- return -1;
-
- if (ev_link_action_get_action_type (action) !=
- EV_LINK_ACTION_TYPE_GOTO_DEST)
- return -1;
-
- dest = ev_link_action_get_dest (action);
- if (dest)
- return ev_link_dest_get_page (dest);
-
- return -1;
-}
-
static void
print_section_cb (GtkWidget *menuitem, EvSidebarLinks *sidebar)
{
if (!link)
return;
- first_page = get_page_from_link (link);
+ first_page = ev_link_get_page (link);
if (first_page == -1) {
g_object_unref (link);
return;
-1);
if (link) {
- last_page = get_page_from_link (link);
+ last_page = ev_link_get_page (link);
g_object_unref (link);
}
} else {
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,
- (GtkTreeCellDataFunc) links_page_num_func,
- ev_sidebar_links, NULL);
+ gtk_tree_view_column_set_attributes (GTK_TREE_VIEW_COLUMN (column), renderer,
+ "markup", EV_DOCUMENT_LINKS_COLUMN_PAGE_LABEL,
+ NULL);
g_signal_connect (GTK_TREE_VIEW (priv->tree_view),
"button_press_event",
ev_sidebar_links_construct (ev_sidebar_links);
}
-static void
-links_page_num_func (GtkTreeViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- EvSidebarLinks *sidebar_links)
+static gboolean
+fill_page_labels (GtkTreeModel *tree_model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ EvSidebarLinks *sidebar_links)
{
EvLink *link;
gint page;
+ gchar *page_label;
+ gchar *page_string;
+
gtk_tree_model_get (tree_model, iter,
EV_DOCUMENT_LINKS_COLUMN_LINK, &link,
-1);
- if (!link) {
- g_object_set (cell,
- "visible", FALSE,
- NULL);
- return;
- }
-
- page = get_page_from_link (link);
+ if (!link)
+ return FALSE;
- if (page >= 0) {
- gchar *page_label;
- gchar *page_string;
+ page = ev_link_get_page (link);
- page_label = ev_page_cache_get_page_label (sidebar_links->priv->page_cache,
- page);
- page_string = g_markup_printf_escaped ("<i>%s</i>", page_label);
-
- g_object_set (cell,
- "markup", page_string,
- "visible", TRUE,
- NULL);
+ if (page < 0)
+ return FALSE;
+
+ page_label = ev_page_cache_get_page_label (sidebar_links->priv->page_cache,
+ page);
+ page_string = g_markup_printf_escaped ("<i>%s</i>", page_label);
+
+ gtk_tree_store_set (GTK_TREE_STORE (tree_model), iter,
+ EV_DOCUMENT_LINKS_COLUMN_PAGE_LABEL, page_string,
+ -1);
- g_free (page_label);
- g_free (page_string);
- } else {
- g_object_set (cell,
- "visible", FALSE,
- NULL);
- }
+ g_free (page_label);
+ g_free (page_string);
g_object_unref (link);
+ return FALSE;
}
/* Public Functions */
int current_page;
int dest_page;
- dest_page = get_page_from_link (link);
+ dest_page = ev_link_get_page (link);
g_object_unref (link);
current_page = ev_page_cache_get_current_page (sidebar_links->priv->page_cache);
if (link) {
gint dest_page;
- dest_page = get_page_from_link (link);
+ dest_page = ev_link_get_page (link);
g_object_unref (link);
if (dest_page == current_page)
priv->model = job->model;
g_object_notify (G_OBJECT (sidebar_links), "model");
+
+ gtk_tree_model_foreach (priv->model, (GtkTreeModelForeachFunc)fill_page_labels, sidebar_links);
gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), job->model);
if (!action)
return;
- g_signal_emit (view, signals[SIGNAL_HANDLE_LINK], 0, link);
type = ev_link_action_get_action_type (action);
case EV_LINK_ACTION_TYPE_GOTO_DEST: {
EvLinkDest *dest;
+ g_signal_emit (view, signals[SIGNAL_HANDLE_LINK], 0, link);
+
dest = ev_link_action_get_dest (action);
ev_view_goto_dest (view, dest);
}
if (!ev_window_is_empty (ev_window))
ev_metadata_manager_set_int (ev_window->priv->uri, "page", page);
}
+
+typedef struct _FindTask {
+ gchar *page_label;
+ gchar *chapter;
+} FindTask;
+
+static gboolean
+ev_window_find_chapter (GtkTreeModel *tree_model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ FindTask *task = (FindTask *)data;
+ gchar *page_string;
+
+ gtk_tree_model_get (tree_model, iter,
+ EV_DOCUMENT_LINKS_COLUMN_PAGE_LABEL, &page_string,
+ -1);
+
+ if (!page_string)
+ return FALSE;
+
+ if (!strncmp (page_string + strlen ("<i>"), task->page_label, strlen (task->page_label))) {
+ gtk_tree_model_get (tree_model, iter,
+ EV_DOCUMENT_LINKS_COLUMN_MARKUP, &task->chapter,
+ -1);
+ g_free (page_string);
+ return TRUE;
+ }
+
+ g_free (page_string);
+ return FALSE;
+}
+
+static void
+ev_window_add_history (EvWindow *window, gint page, EvLink *link)
+{
+ gchar *page_label;
+ gchar *link_title;
+ FindTask find_task;
+
+ EvLink *real_link;
+ EvLinkAction *action;
+ EvLinkDest *dest;
+
+ if (link) {
+ action = g_object_ref (ev_link_get_action (link));
+ dest = ev_link_action_get_dest (action);
+ page = ev_link_dest_get_page (dest);
+ } else {
+ dest = ev_link_dest_new_page (page);
+ action = ev_link_action_new_dest (dest);
+ }
+
+ if (page < 0)
+ return;
+
+ page_label = ev_page_cache_get_page_label (window->priv->page_cache, page);
+
+ find_task.page_label = page_label;
+ find_task.chapter = NULL;
+
+ if (EV_IS_DOCUMENT_LINKS (window->priv->document)) {
+ GtkTreeModel *model;
+
+ g_object_get (G_OBJECT (window->priv->sidebar_links), "model", &model, NULL);
+
+ gtk_tree_model_foreach (model,
+ ev_window_find_chapter,
+ &find_task);
+
+ g_object_unref (model);
+ }
+
+ if (find_task.chapter)
+ link_title = g_strdup_printf (_("Page %s - %s"), page_label, find_task.chapter);
+ else
+ link_title = g_strdup_printf (_("Page %s"), page_label);
+
+ real_link = ev_link_new (link_title, action);
+
+ ev_history_add_link (window->priv->history, real_link);
+
+ g_free (link_title);
+ g_object_unref (real_link);
+}
+
+static void
+view_handle_link_cb (EvView *view, EvLink *link, EvWindow *window)
+{
+ int current_page = ev_page_cache_get_current_page (window->priv->page_cache);
+
+ ev_window_add_history (window, 0, link);
+ ev_window_add_history (window, current_page, NULL);
+}
+
static void
history_changed_cb (EvPageCache *page_cache,
gint page,
- EvWindow *ev_window)
+ EvWindow *window)
{
- ev_history_add_page (ev_window->priv->history, page,
- ev_page_cache_get_page_label (ev_window->priv->page_cache, page));
+ int current_page = ev_page_cache_get_current_page (window->priv->page_cache);
+
+ ev_window_add_history (window, page, NULL);
+ ev_window_add_history (window, current_page, NULL);
+
return;
}
navigation_action_activate_link_cb (EvNavigationAction *action, EvLink *link, EvWindow *window)
{
- g_signal_handlers_block_by_func
- (window->priv->view, G_CALLBACK (view_handle_link_cb), window);
ev_view_handle_link (EV_VIEW (window->priv->view), link);
- g_signal_handlers_unblock_by_func
- (window->priv->view, G_CALLBACK (view_handle_link_cb), window);
gtk_widget_grab_focus (window->priv->view);
}
}
}
-static void
-view_handle_link_cb (EvView *view, EvLink *link, EvWindow *window)
-{
- int current_page = ev_page_cache_get_current_page (window->priv->page_cache);
- ev_history_add_page (window->priv->history,
- current_page,
- ev_page_cache_get_page_label (window->priv->page_cache, current_page));
-}
-
static void
view_external_link_cb (EvView *view, EvLinkAction *action, EvWindow *window)
{