You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

410 lines
11 KiB

  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
  2. /* this file is part of xreader, a mate document viewer
  3. *
  4. * Copyright (C) 2005 Red Hat, Inc
  5. *
  6. * Xreader 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. * Xreader 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. #include "config.h"
  21. #include <string.h>
  22. #include <sys/time.h>
  23. #include <time.h>
  24. #ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
  25. #include <langinfo.h>
  26. #endif
  27. #include <glib/gi18n-lib.h>
  28. #include <gtk/gtk.h>
  29. #include "ev-properties-view.h"
  30. typedef enum {
  31. TITLE_PROPERTY,
  32. URI_PROPERTY,
  33. SUBJECT_PROPERTY,
  34. AUTHOR_PROPERTY,
  35. KEYWORDS_PROPERTY,
  36. PRODUCER_PROPERTY,
  37. CREATOR_PROPERTY,
  38. CREATION_DATE_PROPERTY,
  39. MOD_DATE_PROPERTY,
  40. N_PAGES_PROPERTY,
  41. LINEARIZED_PROPERTY,
  42. FORMAT_PROPERTY,
  43. SECURITY_PROPERTY,
  44. PAPER_SIZE_PROPERTY,
  45. N_PROPERTIES
  46. } Property;
  47. typedef struct {
  48. Property property;
  49. const char *label;
  50. } PropertyInfo;
  51. static const PropertyInfo properties_info[] = {
  52. { TITLE_PROPERTY, N_("Title:") },
  53. { URI_PROPERTY, N_("Location:") },
  54. { SUBJECT_PROPERTY, N_("Subject:") },
  55. { AUTHOR_PROPERTY, N_("Author:") },
  56. { KEYWORDS_PROPERTY, N_("Keywords:") },
  57. { PRODUCER_PROPERTY, N_("Producer:") },
  58. { CREATOR_PROPERTY, N_("Creator:") },
  59. { CREATION_DATE_PROPERTY, N_("Created:") },
  60. { MOD_DATE_PROPERTY, N_("Modified:") },
  61. { N_PAGES_PROPERTY, N_("Number of Pages:") },
  62. { LINEARIZED_PROPERTY, N_("Optimized:") },
  63. { FORMAT_PROPERTY, N_("Format:") },
  64. { SECURITY_PROPERTY, N_("Security:") },
  65. { PAPER_SIZE_PROPERTY, N_("Paper Size:") }
  66. };
  67. struct _EvPropertiesView {
  68. GtkVBox base_instance;
  69. GtkWidget *grid;
  70. GtkWidget *labels[N_PROPERTIES];
  71. gchar *uri;
  72. };
  73. struct _EvPropertiesViewClass {
  74. GtkVBoxClass base_class;
  75. };
  76. G_DEFINE_TYPE (EvPropertiesView, ev_properties_view, GTK_TYPE_VBOX)
  77. static void
  78. ev_properties_view_dispose (GObject *object)
  79. {
  80. EvPropertiesView *properties = EV_PROPERTIES_VIEW (object);
  81. if (properties->uri) {
  82. g_free (properties->uri);
  83. properties->uri = NULL;
  84. }
  85. G_OBJECT_CLASS (ev_properties_view_parent_class)->dispose (object);
  86. }
  87. static void
  88. ev_properties_view_class_init (EvPropertiesViewClass *properties_class)
  89. {
  90. GObjectClass *g_object_class = G_OBJECT_CLASS (properties_class);
  91. g_object_class->dispose = ev_properties_view_dispose;
  92. }
  93. /* This is cut out of gconvert.c from glib (and mildly modified). Not all
  94. backends give valid UTF-8 for properties, so we make sure that is.
  95. */
  96. static gchar *
  97. make_valid_utf8 (const gchar *name)
  98. {
  99. GString *string;
  100. const gchar *remainder, *invalid;
  101. gint remaining_bytes, valid_bytes;
  102. string = NULL;
  103. remainder = name;
  104. remaining_bytes = strlen (name);
  105. while (remaining_bytes != 0)
  106. {
  107. if (g_utf8_validate (remainder, remaining_bytes, &invalid))
  108. break;
  109. valid_bytes = invalid - remainder;
  110. if (string == NULL)
  111. string = g_string_sized_new (remaining_bytes);
  112. g_string_append_len (string, remainder, valid_bytes);
  113. g_string_append_c (string, '?');
  114. remaining_bytes -= valid_bytes + 1;
  115. remainder = invalid + 1;
  116. }
  117. if (string == NULL)
  118. return g_strdup (name);
  119. g_string_append (string, remainder);
  120. g_assert (g_utf8_validate (string->str, -1, NULL));
  121. return g_string_free (string, FALSE);
  122. }
  123. static void
  124. set_property (EvPropertiesView *properties,
  125. GtkGrid *grid,
  126. Property property,
  127. const gchar *text,
  128. gint *row)
  129. {
  130. GtkWidget *label;
  131. gchar *markup;
  132. gchar *valid_text;
  133. if (!properties->labels[property]) {
  134. label = gtk_label_new (NULL);
  135. g_object_set (G_OBJECT (label), "xalign", 0.0, NULL);
  136. markup = g_strdup_printf ("<b>%s</b>", _(properties_info[property].label));
  137. gtk_label_set_markup (GTK_LABEL (label), markup);
  138. g_free (markup);
  139. gtk_grid_attach (grid, label, 0, *row, 1, 1);
  140. gtk_widget_show (label);
  141. }
  142. if (!properties->labels[property]) {
  143. label = gtk_label_new (NULL);
  144. g_object_set (G_OBJECT (label),
  145. "xalign", 0.0,
  146. "width_chars", 25,
  147. "selectable", TRUE,
  148. "ellipsize", PANGO_ELLIPSIZE_END,
  149. NULL);
  150. } else {
  151. label = properties->labels[property];
  152. }
  153. if (text == NULL || text[0] == '\000') {
  154. markup = g_markup_printf_escaped ("<i>%s</i>", _("None"));
  155. gtk_label_set_markup (GTK_LABEL (label), markup);
  156. g_free (markup);
  157. } else {
  158. valid_text = make_valid_utf8 (text ? text : "");
  159. gtk_label_set_text (GTK_LABEL (label), valid_text);
  160. g_free (valid_text);
  161. }
  162. if (!properties->labels[property]) {
  163. gtk_grid_attach (grid, label, 1, *row, 1, 1);
  164. properties->labels[property] = label;
  165. }
  166. gtk_widget_show (label);
  167. *row += 1;
  168. }
  169. static GtkUnit
  170. get_default_user_units (void)
  171. {
  172. /* Translate to the default units to use for presenting
  173. * lengths to the user. Translate to default:inch if you
  174. * want inches, otherwise translate to default:mm.
  175. * Do *not* translate it to "predefinito:mm", if it
  176. * it isn't default:mm or default:inch it will not work
  177. */
  178. gchar *e = _("default:mm");
  179. #ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
  180. gchar *imperial = NULL;
  181. imperial = nl_langinfo (_NL_MEASUREMENT_MEASUREMENT);
  182. if (imperial && imperial[0] == 2)
  183. return GTK_UNIT_INCH; /* imperial */
  184. if (imperial && imperial[0] == 1)
  185. return GTK_UNIT_MM; /* metric */
  186. #endif
  187. if (strcmp (e, "default:mm") == 0)
  188. return GTK_UNIT_MM;
  189. if (strcmp (e, "default:inch") == 0)
  190. return GTK_UNIT_INCH;
  191. g_warning ("Whoever translated default:mm did so wrongly.\n");
  192. return GTK_UNIT_MM;
  193. }
  194. static gdouble
  195. get_tolerance (gdouble size)
  196. {
  197. if (size < 150.0f)
  198. return 1.5f;
  199. else if (size >= 150.0f && size <= 600.0f)
  200. return 2.0f;
  201. else
  202. return 3.0f;
  203. }
  204. static char *
  205. ev_regular_paper_size (const EvDocumentInfo *info)
  206. {
  207. GList *paper_sizes, *l;
  208. gchar *exact_size;
  209. gchar *str = NULL;
  210. GtkUnit units;
  211. units = get_default_user_units ();
  212. if (units == GTK_UNIT_MM) {
  213. exact_size = g_strdup_printf(_("%.0f × %.0f mm"),
  214. info->paper_width,
  215. info->paper_height);
  216. } else {
  217. exact_size = g_strdup_printf (_("%.2f × %.2f inch"),
  218. info->paper_width / 25.4f,
  219. info->paper_height / 25.4f);
  220. }
  221. paper_sizes = gtk_paper_size_get_paper_sizes (FALSE);
  222. for (l = paper_sizes; l && l->data; l = g_list_next (l)) {
  223. GtkPaperSize *size = (GtkPaperSize *) l->data;
  224. gdouble paper_width;
  225. gdouble paper_height;
  226. gdouble width_tolerance;
  227. gdouble height_tolerance;
  228. paper_width = gtk_paper_size_get_width (size, GTK_UNIT_MM);
  229. paper_height = gtk_paper_size_get_height (size, GTK_UNIT_MM);
  230. width_tolerance = get_tolerance (paper_width);
  231. height_tolerance = get_tolerance (paper_height);
  232. if (ABS (info->paper_height - paper_height) <= height_tolerance &&
  233. ABS (info->paper_width - paper_width) <= width_tolerance) {
  234. /* Note to translators: first placeholder is the paper name (eg.
  235. * A4), second placeholder is the paper size (eg. 297x210 mm) */
  236. str = g_strdup_printf (_("%s, Portrait (%s)"),
  237. gtk_paper_size_get_display_name (size),
  238. exact_size);
  239. } else if (ABS (info->paper_width - paper_height) <= height_tolerance &&
  240. ABS (info->paper_height - paper_width) <= width_tolerance) {
  241. /* Note to translators: first placeholder is the paper name (eg.
  242. * A4), second placeholder is the paper size (eg. 297x210 mm) */
  243. str = g_strdup_printf ( _("%s, Landscape (%s)"),
  244. gtk_paper_size_get_display_name (size),
  245. exact_size);
  246. }
  247. }
  248. g_list_foreach (paper_sizes, (GFunc) gtk_paper_size_free, NULL);
  249. g_list_free (paper_sizes);
  250. if (str != NULL) {
  251. g_free (exact_size);
  252. return str;
  253. }
  254. return exact_size;
  255. }
  256. void
  257. ev_properties_view_set_info (EvPropertiesView *properties, const EvDocumentInfo *info)
  258. {
  259. GtkWidget *grid;
  260. gchar *text;
  261. gint row = 0;
  262. grid = properties->grid;
  263. if (info->fields_mask & EV_DOCUMENT_INFO_TITLE) {
  264. set_property (properties, GTK_GRID (grid), TITLE_PROPERTY, info->title, &row);
  265. }
  266. set_property (properties, GTK_GRID (grid), URI_PROPERTY, properties->uri, &row);
  267. if (info->fields_mask & EV_DOCUMENT_INFO_SUBJECT) {
  268. set_property (properties, GTK_GRID (grid), SUBJECT_PROPERTY, info->subject, &row);
  269. }
  270. if (info->fields_mask & EV_DOCUMENT_INFO_AUTHOR) {
  271. set_property (properties, GTK_GRID (grid), AUTHOR_PROPERTY, info->author, &row);
  272. }
  273. if (info->fields_mask & EV_DOCUMENT_INFO_KEYWORDS) {
  274. set_property (properties, GTK_GRID (grid), KEYWORDS_PROPERTY, info->keywords, &row);
  275. }
  276. if (info->fields_mask & EV_DOCUMENT_INFO_PRODUCER) {
  277. set_property (properties, GTK_GRID (grid), PRODUCER_PROPERTY, info->producer, &row);
  278. }
  279. if (info->fields_mask & EV_DOCUMENT_INFO_CREATOR) {
  280. set_property (properties, GTK_GRID (grid), CREATOR_PROPERTY, info->creator, &row);
  281. }
  282. if (info->fields_mask & EV_DOCUMENT_INFO_CREATION_DATE) {
  283. text = ev_document_misc_format_date (info->creation_date);
  284. set_property (properties, GTK_GRID (grid), CREATION_DATE_PROPERTY, text, &row);
  285. g_free (text);
  286. }
  287. if (info->fields_mask & EV_DOCUMENT_INFO_MOD_DATE) {
  288. text = ev_document_misc_format_date (info->modified_date);
  289. set_property (properties, GTK_GRID (grid), MOD_DATE_PROPERTY, text, &row);
  290. g_free (text);
  291. }
  292. if (info->fields_mask & EV_DOCUMENT_INFO_FORMAT) {
  293. set_property (properties, GTK_GRID (grid), FORMAT_PROPERTY, info->format, &row);
  294. }
  295. if (info->fields_mask & EV_DOCUMENT_INFO_N_PAGES) {
  296. text = g_strdup_printf ("%d", info->n_pages);
  297. set_property (properties, GTK_GRID (grid), N_PAGES_PROPERTY, text, &row);
  298. g_free (text);
  299. }
  300. if (info->fields_mask & EV_DOCUMENT_INFO_LINEARIZED)
  301. {
  302. /* nice hack bro */
  303. if (info->linearized == 1)
  304. {
  305. set_property (properties, GTK_GRID (grid), LINEARIZED_PROPERTY, _("Yes"), &row);
  306. }
  307. else if (info->linearized == 0)
  308. {
  309. set_property (properties, GTK_GRID (grid), LINEARIZED_PROPERTY, _("No"), &row);
  310. }
  311. else
  312. {
  313. set_property (properties, GTK_GRID (grid), LINEARIZED_PROPERTY, info->linearized, &row);
  314. }
  315. }
  316. if (info->fields_mask & EV_DOCUMENT_INFO_SECURITY) {
  317. set_property (properties, GTK_GRID (grid), SECURITY_PROPERTY, info->security, &row);
  318. }
  319. if (info->fields_mask & EV_DOCUMENT_INFO_PAPER_SIZE) {
  320. text = ev_regular_paper_size (info);
  321. set_property (properties, GTK_GRID (grid), PAPER_SIZE_PROPERTY, text, &row);
  322. g_free (text);
  323. }
  324. }
  325. static void
  326. ev_properties_view_init (EvPropertiesView *properties)
  327. {
  328. properties->grid = gtk_grid_new ();
  329. gtk_grid_set_column_spacing (GTK_GRID (properties->grid), 12);
  330. gtk_grid_set_row_spacing (GTK_GRID (properties->grid), 6);
  331. gtk_container_set_border_width (GTK_CONTAINER (properties->grid), 12);
  332. gtk_box_pack_start (GTK_BOX (properties), properties->grid, TRUE, TRUE, 0);
  333. gtk_widget_show (properties->grid);
  334. }
  335. void
  336. ev_properties_view_register_type (GTypeModule *module)
  337. {
  338. ev_properties_view_get_type ();
  339. }
  340. GtkWidget *
  341. ev_properties_view_new (const gchar *uri)
  342. {
  343. EvPropertiesView *properties;
  344. properties = g_object_new (EV_TYPE_PROPERTIES, NULL);
  345. properties->uri = g_uri_unescape_string (uri, NULL);
  346. return GTK_WIDGET (properties);
  347. }