]> www.fi.muni.cz Git - evince.git/blob - properties/ev-properties-view.c
More #include cleanups. Again: reordering, single gtk.h includes and other
[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 #if GTK_CHECK_VERSION (2, 11, 0)
196 static GtkUnit
197 get_default_user_units (void)
198 {
199         /* Translate to the default units to use for presenting
200          * lengths to the user. Translate to default:inch if you
201          * want inches, otherwise translate to default:mm.
202          * Do *not* translate it to "predefinito:mm", if it
203          * it isn't default:mm or default:inch it will not work
204          */
205         gchar *e = _("default:mm");
206
207 #ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
208         gchar *imperial = NULL;
209         
210         imperial = nl_langinfo (_NL_MEASUREMENT_MEASUREMENT);
211         if (imperial && imperial[0] == 2)
212                 return GTK_UNIT_INCH;  /* imperial */
213         if (imperial && imperial[0] == 1)
214                 return GTK_UNIT_MM;  /* metric */
215 #endif
216
217         if (strcmp (e, "default:mm") == 0)
218                 return GTK_UNIT_MM;
219         if (strcmp (e, "default:inch") == 0)
220                 return GTK_UNIT_INCH;
221         
222         g_warning ("Whoever translated default:mm did so wrongly.\n");
223                                 
224         return GTK_UNIT_MM;
225 }
226
227 static gdouble
228 get_tolerance (gdouble size)
229 {
230         if (size < 150.0f)
231                 return 1.5f;
232         else if (size >= 150.0f && size <= 600.0f)
233                 return 2.0f;
234         else
235                 return 3.0f;
236 }
237
238 static char *
239 ev_regular_paper_size (const EvDocumentInfo *info)
240 {
241         GList *paper_sizes, *l;
242         gchar *exact_size;
243         gchar *str = NULL;
244         GtkUnit units;
245
246         units = get_default_user_units ();
247
248         if (units == GTK_UNIT_MM) {
249                 exact_size = g_strdup_printf(_("%.0f x %.0f mm"),
250                                              info->paper_width,
251                                              info->paper_height);
252         } else {
253                 exact_size = g_strdup_printf (_("%.2f x %.2f inch"),
254                                               info->paper_width  / 25.4f,
255                                               info->paper_height / 25.4f);
256         }
257
258         paper_sizes = gtk_paper_size_get_paper_sizes (FALSE);
259         
260         for (l = paper_sizes; l && l->data; l = g_list_next (l)) {
261                 GtkPaperSize *size = (GtkPaperSize *) l->data;
262                 gdouble paper_width;
263                 gdouble paper_height;
264                 gdouble width_tolerance;
265                 gdouble height_tolerance;
266
267                 paper_width = gtk_paper_size_get_width (size, GTK_UNIT_MM);
268                 paper_height = gtk_paper_size_get_height (size, GTK_UNIT_MM);
269
270                 width_tolerance = get_tolerance (paper_width);
271                 height_tolerance = get_tolerance (paper_height);
272
273                 if (ABS (info->paper_height - paper_height) <= height_tolerance &&
274                     ABS (info->paper_width  - paper_width) <= width_tolerance) {
275                         /* Note to translators: first placeholder is the paper name (eg.
276                          * A4), second placeholder is the paper size (eg. 297x210 mm) */
277                         str = g_strdup_printf (_("%s, Portrait (%s)"),
278                                                gtk_paper_size_get_display_name (size),
279                                                exact_size);
280                 } else if (ABS (info->paper_width  - paper_height) <= height_tolerance &&
281                            ABS (info->paper_height - paper_width) <= width_tolerance) {
282                         /* Note to translators: first placeholder is the paper name (eg.
283                          * A4), second placeholder is the paper size (eg. 297x210 mm) */
284                         str = g_strdup_printf ( _("%s, Landscape (%s)"),
285                                                 gtk_paper_size_get_display_name (size),
286                                                 exact_size);
287                 }
288         }
289
290         g_list_foreach (paper_sizes, (GFunc) gtk_paper_size_free, NULL);
291         g_list_free (paper_sizes);
292
293         if (str != NULL) {
294                 g_free (exact_size);
295                 return str;
296         }
297         
298         return exact_size;
299 }
300 #else /* ! GTK 2.11.0 */
301 /*
302  * All values are in mm. 
303  * Source: http://en.wikipedia.org/wiki/Paper_size
304  */
305 struct regular_paper_size {
306         double width;
307         double height;
308         double width_tolerance;
309         double height_tolerance;
310         const char *description;
311 } const regular_paper_sizes[] = {
312         // ISO 216 paper sizes
313         {  841.0f, 1189.0f, 3.0f, 3.0f, "A0"  },
314         {  594.0f,  841.0f, 2.0f, 3.0f, "A1"  },
315         {  420.0f,  594.0f, 2.0f, 2.0f, "A2"  },
316         {  297.0f,  420.0f, 2.0f, 2.0f, "A3"  },
317         {  210.0f,  297.0f, 2.0f, 2.0f, "A4"  },
318         {  148.0f,  210.0f, 1.5f, 2.0f, "A5"  },
319         {  105.0f,  148.0f, 1.5f, 1.5f, "A6"  },
320         {   74.0f,  105.0f, 1.5f, 1.5f, "A7"  },
321         {   52.0f,   74.0f, 1.5f, 1.5f, "A8"  },
322         {   37.0f,   52.0f, 1.5f, 1.5f, "A9"  },
323         {   26.0f,   37.0f, 1.5f, 1.5f, "A10" },
324         { 1000.0f, 1414.0f, 3.0f, 3.0f, "B0"  },
325         {  707.0f, 1000.0f, 3.0f, 3.0f, "B1"  },
326         {  500.0f,  707.0f, 2.0f, 3.0f, "B2"  },
327         {  353.0f,  500.0f, 2.0f, 2.0f, "B3"  },
328         {  250.0f,  353.0f, 2.0f, 2.0f, "B4"  },
329         {  176.0f,  250.0f, 2.0f, 2.0f, "B5"  },
330         {  125.0f,  176.0f, 1.5f, 2.0f, "B6"  },
331         {   88.0f,  125.0f, 1.5f, 1.5f, "B7"  },
332         {   62.0f,   88.0f, 1.5f, 1.5f, "B8"  },
333         {   44.0f,   62.0f, 1.5f, 1.5f, "B9"  },
334         {   31.0f,   44.0f, 1.5f, 1.5f, "B10" },
335         {  917.0f, 1297.0f, 3.0f, 3.0f, "C0"  },
336         {  648.0f,  917.0f, 3.0f, 3.0f, "C1"  },
337         {  458.0f,  648.0f, 2.0f, 3.0f, "C2"  },
338         {  324.0f,  458.0f, 2.0f, 2.0f, "C3"  },
339         {  229.0f,  324.0f, 2.0f, 2.0f, "C4"  },
340         {  162.0f,  229.0f, 2.0f, 2.0f, "C5"  },
341         {  114.0f,  162.0f, 1.5f, 2.0f, "C6"  },
342         {   81.0f,  114.0f, 1.5f, 1.5f, "C7"  },
343         {   57.0f,   81.0f, 1.5f, 1.5f, "C8"  },
344         {   40.0f,   57.0f, 1.5f, 1.5f, "C9"  },
345         {   28.0f,   40.0f, 1.5f, 1.5f, "C10" },
346
347         // US paper sizes
348         {  279.0f,  216.0f, 3.0f, 3.0f, "Letter" },
349         {  356.0f,  216.0f, 3.0f, 3.0f, "Legal"  },
350         {  432.0f,  279.0f, 3.0f, 3.0f, "Ledger" }
351 };
352
353 typedef enum {
354   EV_UNIT_INCH,
355   EV_UNIT_MM
356 } EvUnit; 
357
358 static EvUnit
359 ev_get_default_user_units (void)
360 {
361   /* Translate to the default units to use for presenting
362    * lengths to the user. Translate to default:inch if you
363    * want inches, otherwise translate to default:mm.
364    * Do *not* translate it to "predefinito:mm", if it
365    * it isn't default:mm or default:inch it will not work
366    */
367   gchar *e = _("default:mm");
368
369 #ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
370   gchar *imperial = NULL;
371
372   imperial = nl_langinfo (_NL_MEASUREMENT_MEASUREMENT);
373   if (imperial && imperial[0] == 2 )
374     return EV_UNIT_INCH;  /* imperial */
375   if (imperial && imperial[0] == 1 )
376     return EV_UNIT_MM;  /* metric */
377 #endif
378
379   if (strcmp (e, "default:inch")==0)
380     return EV_UNIT_INCH;
381   else if (strcmp (e, "default:mm"))
382     g_warning ("Whoever translated default:mm did so wrongly.\n");
383   return EV_UNIT_MM;
384 }
385
386 static char *
387 ev_regular_paper_size (const EvDocumentInfo *info)
388 {
389         const struct regular_paper_size *size;   
390         EvUnit unit;
391         char *exact_size = NULL;
392         char *str = NULL;
393         int i;
394
395         unit = ev_get_default_user_units ();    
396
397         if (unit == EV_UNIT_INCH)
398                 /* Imperial measurement (inches) */
399                 exact_size = g_strdup_printf( _("%.2f x %.2f in"),
400                                               info->paper_width  / 25.4f,
401                                               info->paper_height / 25.4f );
402         else
403                 /* Metric measurement (millimeters) */
404                 exact_size = g_strdup_printf( _("%.0f x %.0f mm"),
405                                               info->paper_width,
406                                               info->paper_height );
407         
408         for (i = G_N_ELEMENTS ( regular_paper_sizes ) - 1; i >= 0; i--) {
409                 size = &regular_paper_sizes[i];
410
411                 if ( ABS( info->paper_height - size->height ) <= size->height_tolerance &&
412                      ABS( info->paper_width  - size->width  ) <= size->width_tolerance ) {
413                         /* Note to translators: first placeholder is the paper name (eg.
414                          * A4), second placeholder is the paper size (eg. 297x210 mm) */
415                         str = g_strdup_printf ( _("%s, Portrait (%s)"),
416                                                 size->description,
417                                                 exact_size );
418                 } else if ( ABS( info->paper_width  - size->height ) <= size->height_tolerance &&
419                             ABS( info->paper_height - size->width  ) <= size->width_tolerance ) {
420                         /* Note to translators: first placeholder is the paper name (eg.
421                          * A4), second placeholder is the paper size (eg. 297x210 mm) */
422                         str = g_strdup_printf ( _("%s, Landscape (%s)"),
423                                                 size->description,
424                                                 exact_size );
425                 }
426         }
427
428         if (str != NULL) {
429                 g_free (exact_size);
430                 return str;
431         } else
432                 return exact_size;
433 }
434 #endif /* GTK 2.11.0 */
435
436 void
437 ev_properties_view_set_info (EvPropertiesView *properties, const EvDocumentInfo *info)
438 {
439         GladeXML *xml = properties->xml;
440         char *text;
441
442         if (info->fields_mask & EV_DOCUMENT_INFO_TITLE) {
443                 set_property (xml, TITLE_PROPERTY, info->title);
444         }
445         if (info->fields_mask & EV_DOCUMENT_INFO_SUBJECT) {
446                 set_property (xml, SUBJECT_PROPERTY, info->subject);
447         }
448         if (info->fields_mask & EV_DOCUMENT_INFO_AUTHOR) {
449                 set_property (xml, AUTHOR_PROPERTY, info->author);
450         }
451         if (info->fields_mask & EV_DOCUMENT_INFO_KEYWORDS) {
452                 set_property (xml, KEYWORDS_PROPERTY, info->keywords);
453         }
454         if (info->fields_mask & EV_DOCUMENT_INFO_PRODUCER) {
455                 set_property (xml, PRODUCER_PROPERTY, info->producer);
456         }
457         if (info->fields_mask & EV_DOCUMENT_INFO_CREATOR) {
458                 set_property (xml, CREATOR_PROPERTY, info->creator);
459         }
460         if (info->fields_mask & EV_DOCUMENT_INFO_CREATION_DATE) {
461                 text = ev_properties_view_format_date (info->creation_date);
462                 set_property (xml, CREATION_DATE_PROPERTY, text);
463                 g_free (text);
464         }
465         if (info->fields_mask & EV_DOCUMENT_INFO_MOD_DATE) {
466                 text = ev_properties_view_format_date (info->modified_date);
467                 set_property (xml, MOD_DATE_PROPERTY, text);
468                 g_free (text);
469         }
470         if (info->fields_mask & EV_DOCUMENT_INFO_FORMAT) {
471                 text = g_strdup_printf ("%s", info->format);
472                 set_property (xml, FORMAT_PROPERTY, text);
473                 g_free (text);
474         }
475         if (info->fields_mask & EV_DOCUMENT_INFO_N_PAGES) {
476                 text = g_strdup_printf ("%d", info->n_pages);
477                 set_property (xml, N_PAGES_PROPERTY, text);
478                 g_free (text);
479         }
480         if (info->fields_mask & EV_DOCUMENT_INFO_LINEARIZED) {
481                 set_property (xml, LINEARIZED_PROPERTY, info->linearized);
482         }
483         if (info->fields_mask & EV_DOCUMENT_INFO_SECURITY) {
484                 set_property (xml, SECURITY_PROPERTY, info->security);
485         }
486         if (info->fields_mask & EV_DOCUMENT_INFO_PAPER_SIZE) {
487                 text = ev_regular_paper_size (info);
488                 set_property (xml, PAPER_SIZE_PROPERTY, text);
489                 g_free (text);
490         }
491 }
492
493 static void
494 ev_properties_view_init (EvPropertiesView *properties)
495 {
496         GladeXML *xml;
497
498         /* Create a new GladeXML object from XML file glade_file */
499         xml = glade_xml_new (DATADIR "/evince-properties.glade", "general_page_root", GETTEXT_PACKAGE);
500         properties->xml = xml;
501         g_assert (xml != NULL);
502
503         gtk_box_pack_start (GTK_BOX (properties),
504                             glade_xml_get_widget (xml, "general_page_root"),
505                             TRUE, TRUE, 0);
506 }
507
508 void
509 ev_properties_view_register_type (GTypeModule *module)
510 {
511         ev_properties_view_get_type ();
512 }
513
514 GtkWidget *
515 ev_properties_view_new (void)
516 {
517         EvPropertiesView *properties;
518
519         properties = g_object_new (EV_TYPE_PROPERTIES, NULL);
520
521         return GTK_WIDGET (properties);
522 }