1 #include <glib.h>
2 #include <gio/gio.h>
3 #include <cairo.h>
4 #include <gtk/gtk.h>
5 #include <stdlib.h>
6 
7 #include <libgxps/gxps.h>
8 
9 typedef struct {
10 	GtkWidget *darea;
11 	GtkWidget *spin_button;
12 
13 	GXPSDocument *doc;
14 	cairo_surface_t *surface;
15 } GXPSView;
16 
17 static gboolean
drawing_area_draw(GtkWidget * drawing_area,cairo_t * cr,GXPSView * view)18 drawing_area_draw (GtkWidget *drawing_area,
19                    cairo_t   *cr,
20                    GXPSView  *view)
21 {
22 	if (!view->surface)
23 		return FALSE;
24 
25         cairo_set_source_rgb (cr, 1., 1., 1.);
26         cairo_rectangle (cr, 0, 0,
27                          cairo_image_surface_get_width (view->surface),
28                          cairo_image_surface_get_height (view->surface));
29 	cairo_fill (cr);
30 	cairo_set_source_surface (cr, view->surface, 0, 0);
31 	cairo_paint (cr);
32 
33 	return TRUE;
34 }
35 
36 static void
page_changed_callback(GtkSpinButton * button,GXPSView * view)37 page_changed_callback (GtkSpinButton *button,
38 		       GXPSView      *view)
39 {
40 	GXPSPage *xps_page;
41 	gint      page;
42 	gdouble   width, height;
43 	cairo_t  *cr;
44 	GError   *error = NULL;
45 
46 	page = gtk_spin_button_get_value_as_int (button);
47 
48 	xps_page = gxps_document_get_page (view->doc, page, &error);
49 	if (error) {
50 		g_printerr ("Error getting page %d: %s\n", page, error->message);
51 		g_error_free (error);
52 
53 		return;
54 	}
55 	gxps_page_get_size (xps_page, &width, &height);
56 
57 	cairo_surface_destroy (view->surface);
58 	view->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
59 						    width, height);
60 
61 	cr = cairo_create (view->surface);
62 	gxps_page_render (xps_page, cr, &error);
63 	if (error) {
64 		g_printerr ("Error rendering page: %d: %s\n", page, error->message);
65 		g_error_free (error);
66 	}
67 	cairo_destroy (cr);
68 
69 	gtk_widget_set_size_request (view->darea, width, height);
70 	gtk_widget_queue_draw (view->darea);
71 
72 	g_object_unref (xps_page);
73 }
74 
75 static gchar *
format_date(time_t utime)76 format_date (time_t utime)
77 {
78         time_t time = (time_t) utime;
79         char s[256];
80         const char *fmt_hack = "%c";
81         size_t len;
82 #ifdef HAVE_LOCALTIME_R
83         struct tm t;
84         if (time == 0 || !localtime_r (&time, &t))
85                 return NULL;
86         len = strftime (s, sizeof (s), fmt_hack, &t);
87 #else
88         struct tm *t;
89         if (time == 0 || !(t = localtime (&time)) )
90                 return NULL;
91 #pragma GCC diagnostic push
92 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
93         len = strftime (s, sizeof (s), fmt_hack, t);
94 #pragma GCC diagnostic pop
95 #endif
96 
97         if (len == 0 || s[0] == '\0')
98                 return NULL;
99 
100         return g_locale_to_utf8 (s, -1, NULL, NULL, NULL);
101 }
102 
103 
104 static void
append_row_to_table(GtkWidget * table,const gchar * key,const gchar * value)105 append_row_to_table (GtkWidget   *table,
106                      const gchar *key,
107                      const gchar *value)
108 {
109         GtkWidget *key_label;
110         GtkWidget *value_label;
111 
112         if (!value)
113                 return;
114 
115         key_label = gtk_label_new (NULL);
116         g_object_set (G_OBJECT (key_label), "xalign", 0.0, NULL);
117         gtk_label_set_markup (GTK_LABEL (key_label), key);
118         gtk_container_add (GTK_CONTAINER (table), key_label);
119         gtk_widget_show (key_label);
120 
121         value_label = gtk_label_new (value);
122         g_object_set (G_OBJECT (value_label),
123                       "xalign", 0.0,
124                       "selectable", TRUE,
125                       "ellipsize", PANGO_ELLIPSIZE_END,
126                       "hexpand", TRUE,
127                       NULL);
128         gtk_grid_attach_next_to (GTK_GRID (table),
129                                  value_label,
130                                  key_label,
131                                  GTK_POS_RIGHT,
132                                  1, 1);
133         gtk_widget_show (value_label);
134 }
135 
136 static void
properties_button_clicked(GtkWidget * button,GXPSFile * xps)137 properties_button_clicked (GtkWidget *button, GXPSFile *xps)
138 {
139         GtkWidget          *dialog;
140         GtkWidget          *table;
141         GXPSCoreProperties *core_props;
142         gchar              *date;
143         GError             *error = NULL;
144 
145         core_props = gxps_file_get_core_properties (xps, &error);
146         if (!core_props) {
147                 if (error)  {
148                         g_printerr ("Error getting core properties: %s\n", error->message);
149                         g_error_free (error);
150                 }
151                 return;
152         }
153 
154         dialog = gtk_dialog_new_with_buttons ("Document Properties",
155                                               GTK_WINDOW (gtk_widget_get_toplevel (button)),
156                                               GTK_DIALOG_DESTROY_WITH_PARENT,
157                                               "Close", GTK_RESPONSE_CLOSE,
158                                               NULL);
159         g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
160 
161         table = gtk_grid_new ();
162         gtk_container_set_border_width (GTK_CONTAINER (table), 5);
163         gtk_orientable_set_orientation (GTK_ORIENTABLE (table), GTK_ORIENTATION_VERTICAL);
164         gtk_grid_set_column_spacing (GTK_GRID (table), 6);
165         gtk_grid_set_row_spacing (GTK_GRID (table), 6);
166 
167         append_row_to_table (table, "<b>Title:</b>", gxps_core_properties_get_title (core_props));
168         append_row_to_table (table, "<b>Creator:</b>", gxps_core_properties_get_creator (core_props));
169         append_row_to_table (table, "<b>Description:</b>", gxps_core_properties_get_description (core_props));
170         append_row_to_table (table, "<b>Subject:</b>", gxps_core_properties_get_subject (core_props));
171         append_row_to_table (table, "<b>Keywords:</b>", gxps_core_properties_get_keywords (core_props));
172         append_row_to_table (table, "<b>Version:</b>", gxps_core_properties_get_version (core_props));
173         append_row_to_table (table, "<b>Revision:</b>", gxps_core_properties_get_revision (core_props));
174         append_row_to_table (table, "<b>Identifier:</b>", gxps_core_properties_get_identifier (core_props));
175         append_row_to_table (table, "<b>Language:</b>", gxps_core_properties_get_language (core_props));
176         append_row_to_table (table, "<b>Category:</b>", gxps_core_properties_get_category (core_props));
177         append_row_to_table (table, "<b>Content Status:</b>", gxps_core_properties_get_content_status (core_props));
178         append_row_to_table (table, "<b>Content Type:</b>", gxps_core_properties_get_content_type (core_props));
179         date = format_date (gxps_core_properties_get_created (core_props));
180         append_row_to_table (table, "<b>Created:</b>", date);
181         g_free (date);
182         append_row_to_table (table, "<b>Last Modified By:</b>", gxps_core_properties_get_last_modified_by (core_props));
183         date = format_date (gxps_core_properties_get_modified (core_props));
184         append_row_to_table (table, "<b>Modified:</b>", date);
185         g_free (date);
186         date = format_date (gxps_core_properties_get_last_printed (core_props));
187         append_row_to_table (table, "<b>Las Printed:</b>", date);
188         g_free (date);
189 
190         gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), table);
191         gtk_widget_show (table);
192 
193         gtk_widget_show (dialog);
194 
195         g_object_unref (core_props);
196 }
197 
main(gint argc,gchar ** argv)198 gint main (gint argc, gchar **argv)
199 {
200 	GFile     *file;
201 	GXPSFile  *xps;
202 	GXPSView  *view;
203 	GtkWidget *win;
204 	GtkWidget *hbox, *vbox, *sw;
205         GtkWidget *button;
206 	guint      page = 0;
207 	GError    *error = NULL;
208 
209 	if (argc < 2) {
210 		g_printerr ("Use: test-xps file\n");
211 
212 		return 1;
213 	}
214 
215 	gtk_init (&argc, &argv);
216 
217 	file = g_file_new_for_commandline_arg (argv[1]);
218 	xps = gxps_file_new (file, &error);
219 	g_object_unref (file);
220 
221 	if (error) {
222 		g_printerr ("Error creating file: %s\n", error->message);
223 		g_error_free (error);
224 		g_object_unref (xps);
225 
226 		return 1;
227 	}
228 
229 	view = g_new0 (GXPSView, 1);
230 	view->doc = gxps_file_get_document (xps, 0, &error);
231 	if (error) {
232 		g_printerr ("Error getting document 0: %s\n", error->message);
233 		g_error_free (error);
234 		g_object_unref (xps);
235 
236 		return 1;
237 	}
238 
239 	win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
240 	gtk_window_set_default_size (GTK_WINDOW (win), 600, 600);
241 	g_signal_connect (win, "delete-event",
242 			  G_CALLBACK (gtk_main_quit),
243 			  NULL);
244 
245 	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
246 
247 	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
248 	view->spin_button = gtk_spin_button_new_with_range  (0,
249 							     gxps_document_get_n_pages (view->doc) - 1,
250 							     1);
251 	g_signal_connect (view->spin_button,
252 			  "value-changed",
253 			  G_CALLBACK (page_changed_callback),
254 			  view);
255 	gtk_box_pack_end (GTK_BOX (hbox), view->spin_button, FALSE, TRUE, 0);
256 	gtk_widget_show (view->spin_button);
257 
258         button = gtk_button_new ();
259         g_signal_connect (button, "clicked",
260                           G_CALLBACK (properties_button_clicked),
261                           xps);
262         gtk_button_set_image (GTK_BUTTON (button),
263                               gtk_image_new_from_icon_name ("document-properties", GTK_ICON_SIZE_SMALL_TOOLBAR));
264         gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
265         gtk_widget_show (button);
266 
267 	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
268 	gtk_widget_show (hbox);
269 
270 	view->darea = gtk_drawing_area_new ();
271 	g_signal_connect (view->darea, "draw",
272 			  G_CALLBACK (drawing_area_draw),
273 			  view);
274 
275 	sw = gtk_scrolled_window_new (NULL, NULL);
276 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
277 					GTK_POLICY_AUTOMATIC,
278 					GTK_POLICY_AUTOMATIC);
279 	gtk_container_add (GTK_CONTAINER (sw), view->darea);
280 	gtk_widget_show (view->darea);
281 
282 	gtk_box_pack_end (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
283 	gtk_widget_show (sw);
284 
285 	gtk_container_add (GTK_CONTAINER (win), vbox);
286 	gtk_widget_show (vbox);
287 
288 	gtk_widget_show (win);
289 
290 	if (argc > 2)
291 		page = atoi (argv[2]);
292 	gtk_spin_button_set_value (GTK_SPIN_BUTTON (view->spin_button), page);
293 	if (page == 0)
294 		page_changed_callback (GTK_SPIN_BUTTON (view->spin_button), view);
295 
296 	gtk_main ();
297 
298 	g_object_unref (view->doc);
299 	g_object_unref (xps);
300 	cairo_surface_destroy (view->surface);
301 	g_free (view);
302 
303 	return 0;
304 }
305