]> www.fi.muni.cz Git - evince.git/blob - properties/ev-properties-view.c
e4bdd3f25252da824d74863b97ed1dcc46d13c0b
[evince.git] / properties / ev-properties-view.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /* this file is part of evince, a gnome document viewer
3  *
4  *  Copyright (C) 2005 Red Hat, Inc
5  *
6  * Evince is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Evince is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22
23 #include <string.h>
24 #include <sys/time.h>
25 #include <time.h>
26
27 #ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
28 #include <langinfo.h>
29 #endif
30
31 #include <glib/gi18n.h>
32 #include <gtk/gtk.h>
33 #include <glade/glade.h>
34
35 #include "ev-properties-view.h"
36 #include "ev-document-fonts.h"
37
38 typedef enum
39 {
40         TITLE_PROPERTY,
41         SUBJECT_PROPERTY,
42         AUTHOR_PROPERTY,
43         KEYWORDS_PROPERTY,
44         PRODUCER_PROPERTY,
45         CREATOR_PROPERTY,
46         CREATION_DATE_PROPERTY,
47         MOD_DATE_PROPERTY,
48         N_PAGES_PROPERTY,
49         LINEARIZED_PROPERTY,
50         FORMAT_PROPERTY,
51         SECURITY_PROPERTY,
52         PAPER_SIZE_PROPERTY
53 } Property;
54
55 typedef struct
56 {
57         Property property;
58         const char *label_id;
59 } PropertyInfo;
60
61 static const PropertyInfo properties_info[] = {
62         { TITLE_PROPERTY, "title" },
63         { SUBJECT_PROPERTY, "subject" },
64         { AUTHOR_PROPERTY, "author" },
65         { KEYWORDS_PROPERTY, "keywords" },
66         { PRODUCER_PROPERTY, "producer" },
67         { CREATOR_PROPERTY, "creator" },
68         { CREATION_DATE_PROPERTY, "created" },
69         { MOD_DATE_PROPERTY, "modified" },
70         { N_PAGES_PROPERTY, "pages" },
71         { LINEARIZED_PROPERTY, "optimized" },
72         { FORMAT_PROPERTY, "version" },
73         { SECURITY_PROPERTY, "security" },
74         { PAPER_SIZE_PROPERTY, "papersize" }
75 };
76
77 struct _EvPropertiesView {
78         GtkVBox base_instance;
79
80         GladeXML *xml;
81 };
82
83 struct _EvPropertiesViewClass {
84         GtkVBoxClass base_class;
85 };
86
87 G_DEFINE_TYPE (EvPropertiesView, ev_properties_view, GTK_TYPE_VBOX)
88
89 static void
90 ev_properties_view_dispose (GObject *object)
91 {
92         EvPropertiesView *properties = EV_PROPERTIES_VIEW (object);
93
94         if (properties->xml) {
95                 g_object_unref (properties->xml);
96                 properties->xml = NULL;
97         }
98
99         G_OBJECT_CLASS (ev_properties_view_parent_class)->dispose (object);
100 }
101
102 static void
103 ev_properties_view_class_init (EvPropertiesViewClass *properties_class)
104 {
105         GObjectClass *g_object_class = G_OBJECT_CLASS (properties_class);
106
107         g_object_class->dispose = ev_properties_view_dispose;
108 }
109
110 /* Returns a locale specific date and time representation */
111 static char *
112 ev_properties_view_format_date (GTime utime)
113 {
114         time_t time = (time_t) utime;
115         struct tm t;
116         char s[256];
117         const char *fmt_hack = "%c";
118         size_t len;
119
120         if (time == 0 || !localtime_r (&time, &t)) return NULL;
121
122         len = strftime (s, sizeof (s), fmt_hack, &t);
123         if (len == 0 || s[0] == '\0') return NULL;
124
125         return g_locale_to_utf8 (s, -1, NULL, NULL, NULL);
126 }
127
128 /* This is cut out of gconvert.c from glib (and mildly modified).  Not all
129    backends give valid UTF-8 for properties, so we make sure that is.
130  */
131 static gchar *
132 make_valid_utf8 (const gchar *name)
133 {
134   GString *string;
135   const gchar *remainder, *invalid;
136   gint remaining_bytes, valid_bytes;
137   
138   string = NULL;
139   remainder = name;
140   remaining_bytes = strlen (name);
141   
142   while (remaining_bytes != 0) 
143     {
144       if (g_utf8_validate (remainder, remaining_bytes, &invalid)) 
145         break;
146       valid_bytes = invalid - remainder;
147     
148       if (string == NULL) 
149         string = g_string_sized_new (remaining_bytes);
150
151       g_string_append_len (string, remainder, valid_bytes);
152       g_string_append_c (string, '?');
153       
154       remaining_bytes -= valid_bytes + 1;
155       remainder = invalid + 1;
156     }
157   
158   if (string == NULL)
159     return g_strdup (name);
160   
161   g_string_append (string, remainder);
162
163   g_assert (g_utf8_validate (string->str, -1, NULL));
164   
165   return g_string_free (string, FALSE);
166 }
167
168 static void
169 set_property (GladeXML *xml, Property property, const char *text)
170 {
171         GtkWidget *widget;
172         char *valid_text;
173
174         widget = glade_xml_get_widget (xml, properties_info[property].label_id);
175         g_return_if_fail (GTK_IS_LABEL (widget));
176
177         if (text == NULL || text[0] == '\000') {
178                 gchar *markup;
179
180                 markup = g_markup_printf_escaped ("<i>%s</i>", _("None"));
181                 gtk_label_set_markup (GTK_LABEL (widget), markup);
182                 g_free (markup);
183
184                 return;
185         }
186         text = text ? text : "";
187
188         valid_text = make_valid_utf8 (text);
189
190         gtk_label_set_text (GTK_LABEL (widget), valid_text);
191
192         g_free (valid_text);
193 }
194
195 static GtkUnit
196 get_default_user_units (void)
197 {
198         /* Translate to the default units to use for presenting
199          * lengths to the user. Translate to default:inch if you
200          * want inches, otherwise translate to default:mm.
201          * Do *not* translate it to "predefinito:mm", if it
202          * it isn't default:mm or default:inch it will not work
203          */
204         gchar *e = _("default:mm");
205
206 #ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
207         gchar *imperial = NULL;
208         
209         imperial = nl_langinfo (_NL_MEASUREMENT_MEASUREMENT);
210         if (imperial && imperial[0] == 2)
211                 return GTK_UNIT_INCH;  /* imperial */
212         if (imperial && imperial[0] == 1)
213                 return GTK_UNIT_MM;  /* metric */
214 #endif
215
216         if (strcmp (e, "default:mm") == 0)
217                 return GTK_UNIT_MM;
218         if (strcmp (e, "default:inch") == 0)
219                 return GTK_UNIT_INCH;
220         
221         g_warning ("Whoever translated default:mm did so wrongly.\n");
222                                 
223         return GTK_UNIT_MM;
224 }
225
226 static gdouble
227 get_tolerance (gdouble size)
228 {
229         if (size < 150.0f)
230                 return 1.5f;
231         else if (size >= 150.0f && size <= 600.0f)
232                 return 2.0f;
233         else
234                 return 3.0f;
235 }
236
237 static char *
238 ev_regular_paper_size (const EvDocumentInfo *info)
239 {
240         GList *paper_sizes, *l;
241         gchar *exact_size;
242         gchar *str = NULL;
243         GtkUnit units;
244
245         units = get_default_user_units ();
246
247         if (units == GTK_UNIT_MM) {
248                 exact_size = g_strdup_printf(_("%.0f x %.0f mm"),
249                                              info->paper_width,
250                                              info->paper_height);
251         } else {
252                 exact_size = g_strdup_printf (_("%.2f x %.2f inch"),
253                                               info->paper_width  / 25.4f,
254                                               info->paper_height / 25.4f);
255         }
256
257         paper_sizes = gtk_paper_size_get_paper_sizes (FALSE);
258         
259         for (l = paper_sizes; l && l->data; l = g_list_next (l)) {
260                 GtkPaperSize *size = (GtkPaperSize *) l->data;
261                 gdouble paper_width;
262                 gdouble paper_height;
263                 gdouble width_tolerance;
264                 gdouble height_tolerance;
265
266                 paper_width = gtk_paper_size_get_width (size, GTK_UNIT_MM);
267                 paper_height = gtk_paper_size_get_height (size, GTK_UNIT_MM);
268
269                 width_tolerance = get_tolerance (paper_width);
270                 height_tolerance = get_tolerance (paper_height);
271
272                 if (ABS (info->paper_height - paper_height) <= height_tolerance &&
273                     ABS (info->paper_width  - paper_width) <= width_tolerance) {
274                         /* Note to translators: first placeholder is the paper name (eg.
275                          * A4), second placeholder is the paper size (eg. 297x210 mm) */
276                         str = g_strdup_printf (_("%s, Portrait (%s)"),
277                                                gtk_paper_size_get_display_name (size),
278                                                exact_size);
279                 } else if (ABS (info->paper_width  - paper_height) <= height_tolerance &&
280                            ABS (info->paper_height - paper_width) <= width_tolerance) {
281                         /* Note to translators: first placeholder is the paper name (eg.
282                          * A4), second placeholder is the paper size (eg. 297x210 mm) */
283                         str = g_strdup_printf ( _("%s, Landscape (%s)"),
284                                                 gtk_paper_size_get_display_name (size),
285                                                 exact_size);
286                 }
287         }
288
289         g_list_foreach (paper_sizes, (GFunc) gtk_paper_size_free, NULL);
290         g_list_free (paper_sizes);
291
292         if (str != NULL) {
293                 g_free (exact_size);
294                 return str;
295         }
296         
297         return exact_size;
298 }
299
300 void
301 ev_properties_view_set_info (EvPropertiesView *properties, const EvDocumentInfo *info)
302 {
303         GladeXML *xml = properties->xml;
304         char *text;
305
306         if (info->fields_mask & EV_DOCUMENT_INFO_TITLE) {
307                 set_property (xml, TITLE_PROPERTY, info->title);
308         }
309         if (info->fields_mask & EV_DOCUMENT_INFO_SUBJECT) {
310                 set_property (xml, SUBJECT_PROPERTY, info->subject);
311         }
312         if (info->fields_mask & EV_DOCUMENT_INFO_AUTHOR) {
313                 set_property (xml, AUTHOR_PROPERTY, info->author);
314         }
315         if (info->fields_mask & EV_DOCUMENT_INFO_KEYWORDS) {
316                 set_property (xml, KEYWORDS_PROPERTY, info->keywords);
317         }
318         if (info->fields_mask & EV_DOCUMENT_INFO_PRODUCER) {
319                 set_property (xml, PRODUCER_PROPERTY, info->producer);
320         }
321         if (info->fields_mask & EV_DOCUMENT_INFO_CREATOR) {
322                 set_property (xml, CREATOR_PROPERTY, info->creator);
323         }
324         if (info->fields_mask & EV_DOCUMENT_INFO_CREATION_DATE) {
325                 text = ev_properties_view_format_date (info->creation_date);
326                 set_property (xml, CREATION_DATE_PROPERTY, text);
327                 g_free (text);
328         }
329         if (info->fields_mask & EV_DOCUMENT_INFO_MOD_DATE) {
330                 text = ev_properties_view_format_date (info->modified_date);
331                 set_property (xml, MOD_DATE_PROPERTY, text);
332                 g_free (text);
333         }
334         if (info->fields_mask & EV_DOCUMENT_INFO_FORMAT) {
335                 text = g_strdup_printf ("%s", info->format);
336                 set_property (xml, FORMAT_PROPERTY, text);
337                 g_free (text);
338         }
339         if (info->fields_mask & EV_DOCUMENT_INFO_N_PAGES) {
340                 text = g_strdup_printf ("%d", info->n_pages);
341                 set_property (xml, N_PAGES_PROPERTY, text);
342                 g_free (text);
343         }
344         if (info->fields_mask & EV_DOCUMENT_INFO_LINEARIZED) {
345                 set_property (xml, LINEARIZED_PROPERTY, info->linearized);
346         }
347         if (info->fields_mask & EV_DOCUMENT_INFO_SECURITY) {
348                 set_property (xml, SECURITY_PROPERTY, info->security);
349         }
350         if (info->fields_mask & EV_DOCUMENT_INFO_PAPER_SIZE) {
351                 text = ev_regular_paper_size (info);
352                 set_property (xml, PAPER_SIZE_PROPERTY, text);
353                 g_free (text);
354         }
355 }
356
357 static void
358 ev_properties_view_init (EvPropertiesView *properties)
359 {
360         GladeXML *xml;
361
362         /* Create a new GladeXML object from XML file glade_file */
363         xml = glade_xml_new (DATADIR "/evince-properties.glade", "general_page_root", GETTEXT_PACKAGE);
364         properties->xml = xml;
365         g_assert (xml != NULL);
366
367         gtk_box_pack_start (GTK_BOX (properties),
368                             glade_xml_get_widget (xml, "general_page_root"),
369                             TRUE, TRUE, 0);
370 }
371
372 void
373 ev_properties_view_register_type (GTypeModule *module)
374 {
375         ev_properties_view_get_type ();
376 }
377
378 GtkWidget *
379 ev_properties_view_new (void)
380 {
381         EvPropertiesView *properties;
382
383         properties = g_object_new (EV_TYPE_PROPERTIES, NULL);
384
385         return GTK_WIDGET (properties);
386 }