Merged older cs.po file with newest pot file.
[gliv/czech_localization.git] / src / images_menus.c
blob1aa7cad054ece81927bccbad80bab1db59e2a763
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 * See the COPYING file for license information.
18 * Guillaume Chazarain <guichaz@yahoo.fr>
21 /************************************
22 * The Images and Directories menus *
23 ************************************/
25 #include <string.h> /* strlen() */
27 #include "gliv.h"
28 #include "images_menus.h"
29 #include "options.h"
30 #include "menus.h"
31 #include "messages.h"
32 #include "next_image.h"
33 #include "mnemonics.h"
34 #include "loading.h"
35 #include "thumbnails.h"
36 #include "callbacks.h"
37 #include "tree.h"
38 #include "timestamp.h"
39 #include "dirty_gtk.h"
40 #include "gliv-image.h"
41 #include "tree_browser.h"
43 extern options_struct *options;
44 extern GlivImage *current_image;
46 /* The progress indicator. */
47 static GtkMenuItem *rebuilding_entry;
49 /* The menu entry to cancel the rebuilding. */
50 static GtkMenuItem *cancel_menu_item;
53 * Association between a directory and its GtkMenu.
54 * Used by Directories->"Current image directory...".
56 static GHashTable *dir_menu_hash = NULL;
58 /* Menus timestamps */
59 static DECLARE_TIMESTAMP(directories_timestamp);
60 static DECLARE_TIMESTAMP(images_timestamp);
62 /*** Functions for both menus. ***/
64 /* Called at menu creation time. */
65 void set_rebuilding_entry(GtkMenuItem * item)
67 rebuilding_entry = item;
70 /* Refresh the percent indicator. */
71 static void set_menu_indicator(const gchar * name, gint percent)
73 static gchar *rebuilding = NULL;
75 if (name == NULL)
76 set_menu_label(rebuilding_entry, "", FALSE);
77 else {
78 gchar *label;
80 if (rebuilding == NULL)
81 /* First time. */
82 rebuilding = _("Rebuilding:");
84 label = g_strdup_printf("%s %s (%d%%)", rebuilding, name, percent);
85 set_menu_label(rebuilding_entry, label, FALSE);
87 g_free(label);
91 /* Update the percent indicator. */
92 void set_progress(const gchar * menu, gint * percent, gint number)
94 static gint total_length;
96 /* Yes, that's ugly */
97 if (number == -1) {
98 /* First time for the menu */
99 total_length = tree_count_files();
100 return;
103 if (menu == NULL) {
104 /* Last time for the menu */
105 set_menu_indicator(NULL, 0);
106 return;
109 if ((*percent + 1) * total_length <= 100 * number) {
110 *percent = (100 * number) / total_length;
111 set_menu_indicator(menu, *percent);
115 /* We don't want to perform the signal lookup for each file. */
116 static void connect_activate(GtkMenuItem * instance, const gchar * filename)
118 static guint signal_id = 0;
119 GClosure *closure;
121 if (signal_id == 0)
122 /* First time. */
123 signal_id = g_signal_lookup("activate", G_TYPE_FROM_INSTANCE(instance));
125 closure = g_cclosure_new_swap(G_CALLBACK(menu_load),
126 (gpointer) filename, NULL);
128 g_signal_connect_closure_by_id(instance, signal_id, 0, closure, FALSE);
131 typedef enum {
132 MENU_FILE, /* From both menus. */
133 MENU_DIR, /* From the Images menu. */
134 MENU_SUBMENU /* From the Directories menu. */
135 } menu_type;
137 /* Add also a mnemonic and a thumbnail. */
138 static GtkMenuItem *add_menu_item(DirtyGtkMenu * menu,
139 tree_item * item, menu_type type)
141 const gchar *name;
142 GtkMenuItem *menu_item;
143 GtkImage *thumbnail = NULL;
145 if (options->thumbnails && type == MENU_FILE && fill_thumbnail(item))
146 thumbnail = GTK_IMAGE(gtk_image_new_from_pixbuf(item->thumb));
147 else
148 /* Simulate the do_threaded() effect of fill_thumbnail(). */
149 process_events();
151 if (type == MENU_DIR)
152 name = item->path;
153 else
154 name = item->name;
156 if (options->mnemonics && type != MENU_DIR) {
157 name = add_mnemonic(name);
159 if (thumbnail)
160 menu_item =
161 GTK_MENU_ITEM(gtk_image_menu_item_new_with_mnemonic(name));
162 else
163 menu_item = GTK_MENU_ITEM(gtk_menu_item_new_with_mnemonic(name));
165 } else {
166 if (thumbnail)
167 menu_item = GTK_MENU_ITEM(gtk_image_menu_item_new_with_label(name));
168 else
169 menu_item = GTK_MENU_ITEM(gtk_menu_item_new_with_label(name));
172 if (thumbnail)
173 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
174 GTK_WIDGET(thumbnail));
176 dirty_gtk_menu_append(menu, GTK_WIDGET(menu_item));
178 switch (type) {
179 case MENU_FILE:
180 connect_activate(menu_item, item->path);
181 break;
183 case MENU_DIR:
184 gtk_widget_set_sensitive(GTK_WIDGET(menu_item), FALSE);
185 break;
187 case MENU_SUBMENU:
188 break;
191 return menu_item;
194 /*** Directories menu. ***/
196 static void add_file_from_tree(DirtyGtkMenu * menu, tree_item * item)
198 static gchar *directories = NULL;
199 static gint number = 0, percent = 0;
201 if (canceled_using_tree())
202 return;
204 if (menu == NULL) {
205 /* First time for this menu. */
207 if (directories == NULL)
208 /* First time. */
209 directories = _("Directories");
211 number = 0;
212 percent = 0;
213 return;
216 add_menu_item(menu, item, MENU_FILE);
218 set_progress(directories, &percent, number);
219 number++;
222 static DirtyGtkMenu *add_sub_menu(DirtyGtkMenu * parent, tree_item * item)
224 DirtyGtkMenu *menu;
225 GtkMenuItem *menu_item;
227 menu_item = add_menu_item(parent, item, MENU_SUBMENU);
229 menu = dirty_gtk_menu_new();
230 gtk_menu_item_set_submenu(menu_item, GTK_WIDGET(menu->gtk_menu));
232 g_hash_table_insert(dir_menu_hash, item->path,
233 dirty_gtk_menu_get_tearoff(menu));
235 return menu;
238 static void make_menu_from_tree_rec(GNode * tree, DirtyGtkMenu * parent)
240 tree_item *item;
241 DirtyGtkMenu *menu;
243 if (canceled_using_tree())
244 return;
246 if (G_NODE_IS_LEAF(tree)) {
247 add_file_from_tree(parent, tree->data);
248 return;
251 item = tree->data;
252 menu = add_sub_menu(parent, item);
254 push_mnemonics();
256 g_node_children_foreach(tree, G_TRAVERSE_ALL,
257 (GNodeForeachFunc) make_menu_from_tree_rec, menu);
259 dirty_gtk_menu_release(menu);
260 pop_mnemonics();
263 static gboolean open_current_dir_menu(void)
265 if (dir_menu_hash && current_image && current_image->node) {
266 gchar *path = g_strdup(current_image->node->data);
267 GtkTearoffMenuItem *tearoff;
269 do {
270 gchar *new_path = g_path_get_dirname(path);
272 g_free(path);
273 path = new_path;
275 tearoff = g_hash_table_lookup(dir_menu_hash, path);
276 } while (!tearoff && !g_str_equal(path, "/") &&
277 !g_str_equal(path, "."));
279 g_free(path);
281 if (tearoff) {
282 GtkWidget *parent_menu = gtk_widget_get_parent(GTK_WIDGET(tearoff));
283 gtk_widget_realize(parent_menu);
284 gtk_menu_item_activate(GTK_MENU_ITEM(tearoff));
288 return FALSE;
291 static void add_current_dir_entry(DirtyGtkMenu * menu)
293 GtkMenuItem *item;
294 const gchar *label;
296 label = add_mnemonic(_("Current image directory..."));
298 item = GTK_MENU_ITEM(gtk_menu_item_new_with_mnemonic(label));
299 g_signal_connect_swapped(item, "activate",
300 G_CALLBACK(open_current_dir_menu), NULL);
302 gtk_widget_show(GTK_WIDGET(item));
303 dirty_gtk_menu_append(menu, GTK_WIDGET(item));
305 if (dir_menu_hash)
306 g_hash_table_destroy(dir_menu_hash);
308 dir_menu_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
310 g_hash_table_insert(dir_menu_hash, ".", dirty_gtk_menu_get_tearoff(menu));
311 g_hash_table_insert(dir_menu_hash, "/", dirty_gtk_menu_get_tearoff(menu));
314 /*** Images menu. ***/
316 static gboolean add_file_item(GNode * tree, DirtyGtkMenu * parent_menu)
318 static gchar *images = NULL;
319 static gint number = 0, percent = 0;
320 GNode *sibling;
322 if (canceled_using_tree())
323 return TRUE;
325 if (parent_menu == NULL) {
326 /* First time for this menu. */
328 if (images == NULL)
329 /* First time. */
330 images = _("Images");
332 number = 0;
333 percent = 0;
334 return FALSE;
337 /* Check if it is the first image in its directory. */
338 sibling = g_node_prev_sibling(tree);
339 if (sibling == NULL && tree->parent != NULL)
340 add_menu_item(parent_menu, tree->parent->data, MENU_DIR);
342 add_menu_item(parent_menu, tree->data, MENU_FILE);
344 set_progress(images, &percent, number);
345 number++;
347 return FALSE;
350 /*** Menus builders. ***/
352 static DirtyGtkMenu *begin_rebuild(GtkMenuItem * root, GCallback func)
354 static DirtyGtkMenu *menu;
355 GtkWidget *rebuilder, *browser;
357 if (root != NULL)
358 gtk_menu_item_deselect(root);
360 menu = dirty_gtk_menu_new();
362 rebuilder =
363 gtk_menu_item_new_with_mnemonic(add_mnemonic(_("Rebuild this menu")));
365 g_signal_connect_swapped(rebuilder, "activate", func, NULL);
366 dirty_gtk_menu_append(menu, rebuilder);
368 browser =
369 gtk_menu_item_new_with_mnemonic(add_mnemonic
370 (_("Open thumbnails browser...")));
372 g_signal_connect(browser, "activate", show_tree_browser, NULL);
373 dirty_gtk_menu_append(menu, browser);
375 gtk_menu_item_set_submenu(root, GTK_WIDGET(menu->gtk_menu));
377 return menu;
380 GNode *get_tree(void)
382 if (currently_loading())
384 * There is no problem in rebuilding the images menus during
385 * a loading, it would just make the loading too long.
387 return NULL;
389 return make_tree();
392 #define REBUILD_START(name, func, timestamp) \
393 do { \
394 if (root != NULL) { \
395 menu_item = root; \
396 return TRUE; \
399 if (more_recent_than_tree(timestamp)) \
400 /* The menu is already up to date. */ \
401 return TRUE; \
403 tree = get_tree(); \
404 if (tree == NULL) { \
405 touch(&timestamp); \
406 return TRUE; \
409 gtk_widget_set_sensitive(GTK_WIDGET(cancel_menu_item), TRUE); \
410 reset_mnemonics(); \
411 menu = begin_rebuild(menu_item, G_CALLBACK(func)); \
412 set_menu_indicator(name, 0); \
413 set_progress(NULL, NULL, -1); \
414 } while (0)
416 static gboolean rebuild_end(GtkMenuItem * root, timestamp_t * ts,
417 GtkMenuItem * menu_item, DirtyGtkMenu * menu)
419 if (root != NULL)
420 gtk_menu_item_deselect(root);
422 dirty_gtk_menu_append(menu, gtk_tearoff_menu_item_new());
424 set_progress(NULL, NULL, 0);
425 gtk_widget_set_sensitive(GTK_WIDGET(cancel_menu_item), FALSE);
427 if (canceled_using_tree())
428 reset_timestamp(ts);
429 else
430 touch(ts);
432 end_using_tree();
433 reset_mnemonics();
434 gtk_widget_show_all(GTK_WIDGET(menu_item));
435 dirty_gtk_menu_release(menu);
436 return *ts != 0;
439 gboolean rebuild_directories(GtkMenuItem * root)
441 static GtkMenuItem *menu_item;
442 DirtyGtkMenu *menu;
443 GNode *tree, *child;
444 gchar *prefix, *old_name;
445 tree_item *item;
447 REBUILD_START(_("Directories"), rebuild_directories, directories_timestamp);
448 add_current_dir_entry(menu);
450 /* Build the menu. */
451 add_file_from_tree(NULL, NULL);
453 item = tree->data;
454 prefix = item->path;
456 if (prefix[0] == '\0' || prefix[1] == '\0') {
457 for (child = g_node_first_child(tree); child; child = child->next) {
458 item = child->data;
459 old_name = item->name;
460 item->name = g_build_filename(prefix, item->name, NULL);
462 make_menu_from_tree_rec(child, menu);
464 g_free(item->name);
465 item->name = old_name;
467 } else
468 make_menu_from_tree_rec(tree, menu);
470 return rebuild_end(root, &directories_timestamp, menu_item, menu);
473 gboolean rebuild_images(GtkMenuItem * root)
475 static GtkMenuItem *menu_item;
476 DirtyGtkMenu *menu;
477 GNode *tree;
479 REBUILD_START(_("Images"), rebuild_images, images_timestamp);
481 /* Build the menu. */
482 add_file_item(NULL, NULL);
483 g_node_traverse(tree, G_PRE_ORDER, G_TRAVERSE_LEAFS, -1,
484 (GNodeTraverseFunc) add_file_item, menu);
486 return rebuild_end(root, &images_timestamp, menu_item, menu);
489 /* Rebuild both menus. */
490 gboolean rebuild_images_menus(void)
492 return rebuild_directories(NULL) && rebuild_images(NULL);
495 void set_stop_rebuilding_menu(GtkMenuItem * item)
497 cancel_menu_item = item;
498 gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE);
501 void obsolete_menus(void)
503 reset_timestamp(&directories_timestamp);
504 reset_timestamp(&images_timestamp);
507 void cond_rebuild_menus(void)
509 if (directories_timestamp)
510 rebuild_directories(NULL);
512 if (images_timestamp)
513 rebuild_images(NULL);
515 cond_rebuild_tree_browser();