1 /*
2 * Copyright © 2009-2018 Siyan Panayotov <contact@siyanpanayotov.com>
3 *
4 * This file is part of Viewnior.
5 *
6 * Viewnior is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Viewnior is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Viewnior. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <libintl.h>
21 #include <glib/gi18n.h>
22 #define _(String) gettext (String)
23
24 #include "vnr-properties-dialog.h"
25 #include "vnr-file.h"
26 #include "vnr-tools.h"
27 #include "uni-exiv2.hpp"
28
29 G_DEFINE_TYPE (VnrPropertiesDialog, vnr_properties_dialog, GTK_TYPE_DIALOG);
30
31 static void vnr_properties_dialog_update_metadata(VnrPropertiesDialog *dialog);
32
33 static gboolean
key_press_cb(GtkWidget * widget,GdkEventKey * event,gpointer user_data)34 key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
35 {
36 if(event->keyval == GDK_KEY_Escape)
37 {
38 gtk_widget_hide(widget);
39 return TRUE;
40 }
41 else
42 return FALSE;
43 }
44
45 static void
get_file_info(gchar * filename,goffset * size,const gchar ** type)46 get_file_info(gchar *filename, goffset *size, const gchar **type)
47 {
48 GFile *file;
49 GFileInfo *fileinfo;
50
51 file = g_file_new_for_path(filename);
52 fileinfo = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE","
53 G_FILE_ATTRIBUTE_STANDARD_SIZE,
54 0, NULL, NULL);
55
56 if (fileinfo == NULL)
57 {
58 return;
59 }
60
61 *size = g_file_info_get_size(fileinfo);
62 *type = g_strdup(g_file_info_get_content_type(fileinfo));
63
64 g_object_unref(file);
65 g_object_unref(fileinfo);
66 }
67
68 static void
set_new_pixbuf(VnrPropertiesDialog * dialog,GdkPixbuf * original)69 set_new_pixbuf(VnrPropertiesDialog *dialog, GdkPixbuf* original)
70 {
71 if(dialog->thumbnail != NULL)
72 {
73 g_object_unref(dialog->thumbnail);
74 dialog->thumbnail = NULL;
75 }
76
77 if(original == NULL)
78 {
79 gtk_image_set_from_stock(GTK_IMAGE(dialog->image), GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_DIALOG);
80 return;
81 }
82
83 int width, height;
84
85 width = gdk_pixbuf_get_width (original);
86 height = gdk_pixbuf_get_height (original);
87
88 vnr_tools_fit_to_size(&height, &width, 100,100);
89
90 dialog->thumbnail = gdk_pixbuf_scale_simple (original, width, height,
91 GDK_INTERP_NEAREST);
92 }
93
94 static void
vnr_properties_dialog_class_init(VnrPropertiesDialogClass * klass)95 vnr_properties_dialog_class_init (VnrPropertiesDialogClass * klass) {}
96
97 GtkWidget *
vnr_properties_dialog_new(VnrWindow * vnr_win,GtkAction * next_action,GtkAction * prev_action)98 vnr_properties_dialog_new (VnrWindow *vnr_win, GtkAction *next_action, GtkAction *prev_action)
99 {
100 VnrPropertiesDialog *dialog;
101
102 dialog = g_object_new (VNR_TYPE_PROPERTIES_DIALOG, NULL);
103
104 dialog->thumbnail = NULL;
105 dialog->vnr_win = vnr_win;
106
107 gtk_activatable_set_related_action (GTK_ACTIVATABLE(dialog->next_button), next_action);
108
109 gtk_activatable_set_related_action (GTK_ACTIVATABLE(dialog->prev_button), prev_action);
110
111 gtk_button_set_label (GTK_BUTTON(dialog->next_button), _("_Next"));
112 gtk_button_set_label (GTK_BUTTON(dialog->prev_button), _("_Previous"));
113 gtk_widget_grab_focus (dialog->close_button);
114
115 return (GtkWidget *) dialog;
116 }
117
118
119 static void
vnr_properties_dialog_init(VnrPropertiesDialog * dialog)120 vnr_properties_dialog_init (VnrPropertiesDialog * dialog)
121 {
122 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
123 GtkWidget *action_area = gtk_dialog_get_action_area(GTK_DIALOG(dialog));
124 GtkWidget *temp_box;
125 GtkWidget *temp_label;
126
127 gtk_window_set_title(GTK_WINDOW(dialog), _("Image Properties"));
128
129 /* VBox containing the Location labels */
130 temp_box = gtk_vbox_new(FALSE,0);
131 gtk_container_set_border_width (GTK_CONTAINER(temp_box), 10);
132 gtk_box_pack_start (GTK_BOX(content_area), temp_box, FALSE,FALSE,0);
133
134 temp_label = gtk_label_new(NULL);
135 gtk_label_set_markup(GTK_LABEL(temp_label), _("<b>Location:</b>"));
136 gtk_misc_set_alignment (GTK_MISC(temp_label), 0, 0);
137 gtk_box_pack_start (GTK_BOX (temp_box), temp_label, FALSE,FALSE,0);
138
139 dialog->location_label = gtk_label_new(NULL);
140 gtk_misc_set_alignment (GTK_MISC(dialog->location_label), 0, 0);
141 gtk_label_set_selectable (GTK_LABEL(dialog->location_label), TRUE);
142 gtk_label_set_ellipsize (GTK_LABEL(dialog->location_label), PANGO_ELLIPSIZE_END);
143 gtk_box_pack_start (GTK_BOX (temp_box), dialog->location_label, FALSE,FALSE,0);
144
145 /* VBox containing the image and meta data */
146 dialog->layout = gtk_vbox_new(FALSE,10);
147 gtk_container_set_border_width (GTK_CONTAINER(dialog->layout), 10);
148 gtk_box_pack_start ( GTK_BOX (content_area) , dialog->layout, FALSE,FALSE,0);
149
150 /* HBox containing the image and the two columns with labels */
151 dialog->image_layout = gtk_hbox_new(FALSE,10);
152 gtk_container_set_border_width (GTK_CONTAINER(dialog->image_layout), 10);
153 gtk_box_pack_start ( GTK_BOX (dialog->layout) , dialog->image_layout, FALSE,FALSE,0);
154
155 /* The frame around the image */
156 temp_box = gtk_frame_new(NULL);
157 gtk_widget_set_size_request (temp_box, 105, 105);
158 gtk_box_pack_start (GTK_BOX (dialog->image_layout), temp_box, FALSE,FALSE,0);
159
160 dialog->image = gtk_image_new_from_stock(GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_DIALOG);
161 gtk_container_add (GTK_CONTAINER (temp_box), dialog->image);
162
163
164 /* Buttons */
165 dialog->prev_button = gtk_button_new();
166 gtk_button_set_image (GTK_BUTTON(dialog->prev_button),
167 gtk_image_new_from_stock(GTK_STOCK_GO_BACK, GTK_ICON_SIZE_BUTTON));
168 gtk_container_add (GTK_CONTAINER (action_area), dialog->prev_button);
169
170 dialog->next_button = gtk_button_new();
171 gtk_button_set_image (GTK_BUTTON(dialog->next_button),
172 gtk_image_new_from_stock(GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON));
173 gtk_container_add (GTK_CONTAINER (action_area), dialog->next_button);
174
175 dialog->close_button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
176 gtk_container_add (GTK_CONTAINER (action_area), dialog->close_button);
177
178
179 /* Image Data Labels */
180 temp_box = gtk_vbox_new(FALSE,0);
181 gtk_box_pack_start (GTK_BOX (dialog->image_layout), temp_box, FALSE,FALSE,0);
182
183 temp_label = gtk_label_new(NULL);
184 gtk_label_set_markup(GTK_LABEL(temp_label), _("<b>Name:</b>"));
185 gtk_misc_set_alignment (GTK_MISC(temp_label), 0, 0);
186 gtk_box_pack_start (GTK_BOX (temp_box), temp_label, FALSE,FALSE,0);
187 temp_label = gtk_label_new(NULL);
188 gtk_label_set_markup(GTK_LABEL(temp_label), _("<b>Type:</b>"));
189 gtk_misc_set_alignment (GTK_MISC(temp_label), 0, 0);
190 gtk_box_pack_start (GTK_BOX (temp_box), temp_label, FALSE,FALSE,0);
191 temp_label = gtk_label_new(NULL);
192 gtk_label_set_markup(GTK_LABEL(temp_label), _("<b>Size:</b>"));
193 gtk_misc_set_alignment (GTK_MISC(temp_label), 0, 0);
194 gtk_box_pack_start (GTK_BOX (temp_box), temp_label, FALSE,FALSE,0);
195 temp_label = gtk_label_new(NULL);
196 gtk_label_set_markup(GTK_LABEL(temp_label), _("<b>Width:</b>"));
197 gtk_misc_set_alignment (GTK_MISC(temp_label), 0, 0);
198 gtk_box_pack_start (GTK_BOX (temp_box), temp_label, FALSE,FALSE,0);
199 temp_label = gtk_label_new(NULL);
200 gtk_label_set_markup(GTK_LABEL(temp_label), _("<b>Height:</b>"));
201 gtk_misc_set_alignment (GTK_MISC(temp_label), 0, 0);
202 gtk_box_pack_start (GTK_BOX (temp_box), temp_label, FALSE,FALSE,0);
203
204
205 temp_box = gtk_vbox_new(FALSE,0);
206 gtk_box_pack_start (GTK_BOX (dialog->image_layout), temp_box, FALSE,FALSE,0);
207
208 dialog->name_label = gtk_label_new(NULL);
209 gtk_label_set_selectable (GTK_LABEL(dialog->name_label), TRUE);
210 gtk_misc_set_alignment (GTK_MISC(dialog->name_label), 0, 0);
211 gtk_box_pack_start (GTK_BOX (temp_box), dialog->name_label, FALSE,FALSE,0);
212 dialog->type_label = gtk_label_new(NULL);
213 gtk_label_set_selectable (GTK_LABEL(dialog->type_label), TRUE);
214 gtk_misc_set_alignment (GTK_MISC(dialog->type_label), 0, 0);
215 gtk_box_pack_start (GTK_BOX (temp_box), dialog->type_label, FALSE,FALSE,0);
216 dialog->size_label = gtk_label_new(NULL);
217 gtk_label_set_selectable (GTK_LABEL(dialog->size_label), TRUE);
218 gtk_misc_set_alignment (GTK_MISC(dialog->size_label), 0, 0);
219 gtk_box_pack_start (GTK_BOX (temp_box), dialog->size_label, FALSE,FALSE,0);
220 dialog->width_label = gtk_label_new(NULL);
221 gtk_label_set_selectable (GTK_LABEL(dialog->width_label), TRUE);
222 gtk_misc_set_alignment (GTK_MISC(dialog->width_label), 0, 0);
223 gtk_box_pack_start (GTK_BOX (temp_box), dialog->width_label, FALSE,FALSE,0);
224 dialog->height_label = gtk_label_new(NULL);
225 gtk_label_set_selectable (GTK_LABEL(dialog->height_label), TRUE);
226 gtk_misc_set_alignment (GTK_MISC(dialog->height_label), 0, 0);
227 gtk_box_pack_start (GTK_BOX (temp_box), dialog->height_label, FALSE,FALSE,0);
228
229 /* Metadata Labels */
230
231 temp_box = gtk_hbox_new(FALSE,10);
232 gtk_box_pack_start (GTK_BOX (dialog->layout), temp_box, FALSE,FALSE,0);
233
234 dialog->meta_names_box = gtk_vbox_new(FALSE,0);
235 gtk_box_pack_start (GTK_BOX (temp_box), dialog->meta_names_box, FALSE,FALSE,0);
236
237 dialog->meta_values_box = gtk_vbox_new(FALSE,0);
238 gtk_box_pack_start (GTK_BOX (temp_box), dialog->meta_values_box, FALSE,FALSE,0);
239
240 /* Events and rest */
241
242 g_signal_connect(G_OBJECT(dialog), "delete-event",
243 G_CALLBACK(gtk_widget_hide_on_delete), NULL);
244 g_signal_connect_swapped(G_OBJECT(dialog->close_button), "clicked",
245 G_CALLBACK(gtk_widget_hide_on_delete), dialog);
246
247 g_signal_connect(G_OBJECT(dialog), "key-press-event", G_CALLBACK(key_press_cb), NULL);
248
249 gtk_widget_show_all(content_area);
250 gtk_widget_show_all(action_area);
251 }
252
253 void
vnr_properties_dialog_update(VnrPropertiesDialog * dialog)254 vnr_properties_dialog_update(VnrPropertiesDialog *dialog)
255 {
256 const gchar *filetype = NULL;
257 goffset filesize = 0;
258 gchar *filetype_desc = NULL;
259 gchar *filesize_str = NULL;
260
261 get_file_info ((gchar*)VNR_FILE(dialog->vnr_win->file_list->data)->path,
262 &filesize, &filetype);
263
264 if(filetype == NULL && filesize == 0)
265 {
266 vnr_properties_dialog_clear(dialog);
267 return;
268 }
269
270 vnr_properties_dialog_update_image(dialog);
271 vnr_properties_dialog_update_metadata(dialog);
272
273 filesize_str = g_format_size (filesize);
274
275 filetype_desc = g_content_type_get_description (filetype);
276
277 gtk_label_set_text(GTK_LABEL(dialog->name_label),
278 (gchar*)VNR_FILE(dialog->vnr_win->file_list->data)->display_name);
279
280 gtk_label_set_text(GTK_LABEL(dialog->location_label),
281 (gchar*)VNR_FILE(dialog->vnr_win->file_list->data)->path);
282
283 gtk_label_set_text(GTK_LABEL(dialog->type_label), filetype_desc);
284 gtk_label_set_text(GTK_LABEL(dialog->size_label), filesize_str);
285
286 g_free(filesize_str);
287 g_free((gchar*)filetype);
288 g_free(filetype_desc);
289 }
290
291 static void
vnr_properties_dialog_clear_metadata(VnrPropertiesDialog * dialog)292 vnr_properties_dialog_clear_metadata(VnrPropertiesDialog *dialog)
293 {
294 GList *children;
295 GList *iter;
296
297 children = gtk_container_get_children(GTK_CONTAINER(dialog->meta_values_box));
298 for(iter = children; iter != NULL; iter = g_list_next(iter)) {
299 gtk_widget_destroy(GTK_WIDGET(iter->data));
300 }
301 g_list_free(children);
302
303 children = gtk_container_get_children(GTK_CONTAINER(dialog->meta_names_box));
304 for(iter = children; iter != NULL; iter = g_list_next(iter)) {
305 gtk_widget_destroy(GTK_WIDGET(iter->data));
306 }
307 g_list_free(children);
308 }
309
310 static void
vnr_cb_add_metadata(const char * label,const char * value,void * user_data)311 vnr_cb_add_metadata(const char *label, const char *value, void *user_data) {
312 VnrPropertiesDialog *dialog = VNR_PROPERTIES_DIALOG(user_data);
313 GtkWidget *temp_label;
314 gchar *formatted_label;
315
316 // value
317 temp_label = gtk_label_new(NULL);
318 gtk_label_set_text(GTK_LABEL(temp_label), value);
319 gtk_label_set_selectable (GTK_LABEL(temp_label), TRUE);
320 gtk_misc_set_alignment (GTK_MISC(temp_label), 0, 0);
321 gtk_box_pack_start (GTK_BOX(dialog->meta_values_box), temp_label, FALSE,FALSE,0);
322
323 gtk_widget_show(temp_label);
324
325 // label
326 formatted_label = g_strdup_printf("<b>%s:</b>", label);
327
328 temp_label = gtk_label_new(NULL);
329 gtk_label_set_markup(GTK_LABEL(temp_label), formatted_label);
330 gtk_misc_set_alignment (GTK_MISC(temp_label), 0, 0);
331 gtk_box_pack_start (GTK_BOX(dialog->meta_names_box), temp_label, FALSE,FALSE,0);
332
333 g_free(formatted_label);
334 gtk_widget_show(temp_label);
335 }
336
337 static void
vnr_properties_dialog_update_metadata(VnrPropertiesDialog * dialog)338 vnr_properties_dialog_update_metadata(VnrPropertiesDialog *dialog)
339 {
340 vnr_properties_dialog_clear_metadata(dialog);
341
342 uni_read_exiv2_map(
343 VNR_FILE(dialog->vnr_win->file_list->data)->path,
344 vnr_cb_add_metadata,
345 (void*)dialog);
346 }
347
348 void
vnr_properties_dialog_update_image(VnrPropertiesDialog * dialog)349 vnr_properties_dialog_update_image(VnrPropertiesDialog *dialog)
350 {
351 gchar *width_str, *height_str;
352
353 set_new_pixbuf(dialog, uni_image_view_get_pixbuf(UNI_IMAGE_VIEW(dialog->vnr_win->view)));
354 gtk_image_set_from_pixbuf (GTK_IMAGE(dialog->image) , dialog->thumbnail);
355
356 width_str = g_strdup_printf("%i px", dialog->vnr_win->current_image_width);
357 height_str = g_strdup_printf("%i px", dialog->vnr_win->current_image_height);
358
359 gtk_label_set_text(GTK_LABEL(dialog->width_label), width_str);
360 gtk_label_set_text(GTK_LABEL(dialog->height_label), height_str);
361
362 g_free(width_str);
363 g_free(height_str);
364 }
365
366 void
vnr_properties_dialog_clear(VnrPropertiesDialog * dialog)367 vnr_properties_dialog_clear(VnrPropertiesDialog *dialog)
368 {
369 set_new_pixbuf(dialog, NULL);
370 vnr_properties_dialog_clear_metadata(dialog);
371
372 gtk_label_set_text(GTK_LABEL(dialog->name_label), _("None"));
373 gtk_label_set_text(GTK_LABEL(dialog->location_label), _("None"));
374 gtk_label_set_text(GTK_LABEL(dialog->type_label), _("None"));
375 gtk_label_set_text(GTK_LABEL(dialog->size_label), _("None"));
376 gtk_label_set_text(GTK_LABEL(dialog->width_label), _("None"));
377 gtk_label_set_text(GTK_LABEL(dialog->height_label), _("None"));
378 }
379
380 void
vnr_properties_dialog_show(VnrPropertiesDialog * dialog)381 vnr_properties_dialog_show (VnrPropertiesDialog *dialog)
382 {
383 vnr_properties_dialog_update(dialog);
384 gtk_window_present(GTK_WINDOW(dialog));
385 }
386