1 /*
2  * Copyright (C) 2007 Carlos Garcia Campos  <carlosgc@gnome.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2, or (at your option)
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include <gtk/gtk.h>
20 
21 #include "outline.h"
22 #include "utils.h"
23 
24 enum
25 {
26     OUTLINE_TITLE_COLUMN,
27     OUTLINE_ACTION_TYPE_COLUMN,
28     OUTLINE_EXPAND_COLUMN,
29     OUTLINE_ACTION_COLUMN,
30     N_COLUMNS
31 };
32 
build_tree(PopplerDocument * document,GtkTreeModel * model,GtkTreeIter * parent,PopplerIndexIter * iter)33 static void build_tree(PopplerDocument *document, GtkTreeModel *model, GtkTreeIter *parent, PopplerIndexIter *iter)
34 {
35 
36     do {
37         GtkTreeIter tree_iter;
38         PopplerIndexIter *child;
39         PopplerAction *action;
40         gboolean expand;
41         gchar *markup;
42         GEnumValue *enum_value;
43 
44         action = poppler_index_iter_get_action(iter);
45         expand = poppler_index_iter_is_open(iter);
46 
47         if (!action)
48             continue;
49 
50         markup = g_markup_escape_text(action->any.title, -1);
51         enum_value = g_enum_get_value((GEnumClass *)g_type_class_ref(POPPLER_TYPE_ACTION_TYPE), action->type);
52 
53         if (action->type == POPPLER_ACTION_GOTO_DEST && action->goto_dest.dest->type == POPPLER_DEST_NAMED) {
54             /* TODO */
55         }
56 
57         gtk_tree_store_append(GTK_TREE_STORE(model), &tree_iter, parent);
58         gtk_tree_store_set(GTK_TREE_STORE(model), &tree_iter, OUTLINE_TITLE_COLUMN, markup, OUTLINE_ACTION_TYPE_COLUMN, enum_value->value_name, OUTLINE_EXPAND_COLUMN, expand, OUTLINE_ACTION_COLUMN, action, -1);
59         g_object_weak_ref(G_OBJECT(model), (GWeakNotify)poppler_action_free, action);
60 
61         g_free(markup);
62 
63         child = poppler_index_iter_get_child(iter);
64         if (child)
65             build_tree(document, model, &tree_iter, child);
66         poppler_index_iter_free(child);
67     } while (poppler_index_iter_next(iter));
68 }
69 
pgd_outline_create_model(PopplerDocument * document)70 GtkTreeModel *pgd_outline_create_model(PopplerDocument *document)
71 {
72     GtkTreeModel *model;
73     PopplerIndexIter *iter;
74 
75     iter = poppler_index_iter_new(document);
76     if (iter) {
77         model = GTK_TREE_MODEL(gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER));
78         build_tree(document, model, NULL, iter);
79         poppler_index_iter_free(iter);
80     } else {
81         GtkTreeIter tree_iter;
82         gchar *markup;
83 
84         model = GTK_TREE_MODEL(gtk_list_store_new(1, G_TYPE_STRING));
85         gtk_list_store_append(GTK_LIST_STORE(model), &tree_iter);
86         markup = g_strdup_printf("<span size=\"larger\" style=\"italic\">%s</span>", "The document doesn't contain outline");
87         gtk_list_store_set(GTK_LIST_STORE(model), &tree_iter, 0, markup, -1);
88         g_free(markup);
89     }
90 
91     return model;
92 }
93 
expand_open_links(GtkTreeView * tree_view,GtkTreeModel * model,GtkTreeIter * parent)94 static void expand_open_links(GtkTreeView *tree_view, GtkTreeModel *model, GtkTreeIter *parent)
95 {
96     GtkTreeIter iter;
97     gboolean expand;
98 
99     if (gtk_tree_model_iter_children(model, &iter, parent)) {
100         do {
101             gtk_tree_model_get(model, &iter, OUTLINE_EXPAND_COLUMN, &expand, -1);
102             if (expand) {
103                 GtkTreePath *path;
104 
105                 path = gtk_tree_model_get_path(model, &iter);
106                 gtk_tree_view_expand_row(tree_view, path, FALSE);
107                 gtk_tree_path_free(path);
108             }
109 
110             expand_open_links(tree_view, model, &iter);
111         } while (gtk_tree_model_iter_next(model, &iter));
112     }
113 }
114 
pgd_outline_selection_changed(GtkTreeSelection * treeselection,GtkWidget * action_view)115 static void pgd_outline_selection_changed(GtkTreeSelection *treeselection, GtkWidget *action_view)
116 {
117     GtkTreeModel *model;
118     GtkTreeIter iter;
119 
120     if (gtk_tree_selection_get_selected(treeselection, &model, &iter)) {
121         PopplerAction *action;
122 
123         gtk_tree_model_get(model, &iter, OUTLINE_ACTION_COLUMN, &action, -1);
124         pgd_action_view_set_action(action_view, action);
125     }
126 }
127 
pgd_outline_create_widget(PopplerDocument * document)128 GtkWidget *pgd_outline_create_widget(PopplerDocument *document)
129 {
130     GtkWidget *swindow;
131     GtkWidget *treeview;
132     GtkTreeModel *model;
133     GtkCellRenderer *renderer;
134     GtkTreeSelection *selection;
135     GtkWidget *hpaned, *action;
136 
137     hpaned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
138 
139     action = pgd_action_view_new(document);
140 
141     swindow = gtk_scrolled_window_new(NULL, NULL);
142     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
143 
144     model = pgd_outline_create_model(document);
145     treeview = gtk_tree_view_new_with_model(model);
146     g_object_unref(model);
147 
148     renderer = gtk_cell_renderer_text_new();
149     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), 0, "Title", renderer, "markup", OUTLINE_TITLE_COLUMN, NULL);
150     g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
151     g_object_set(G_OBJECT(gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 0)), "expand", TRUE, NULL);
152 
153     if (GTK_IS_TREE_STORE(model)) {
154         renderer = gtk_cell_renderer_text_new();
155         gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), 1, "Action Type", renderer, "text", OUTLINE_ACTION_TYPE_COLUMN, NULL);
156 
157         expand_open_links(GTK_TREE_VIEW(treeview), model, NULL);
158 
159         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
160         g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(pgd_outline_selection_changed), (gpointer)action);
161     } else {
162         gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), GTK_SELECTION_NONE);
163     }
164 
165     gtk_container_add(GTK_CONTAINER(swindow), treeview);
166     gtk_widget_show(treeview);
167 
168     gtk_paned_add1(GTK_PANED(hpaned), swindow);
169     gtk_widget_show(swindow);
170 
171     gtk_paned_add2(GTK_PANED(hpaned), action);
172     gtk_widget_show(action);
173 
174     gtk_paned_set_position(GTK_PANED(hpaned), 300);
175 
176     return hpaned;
177 }
178