1 /* -*- Mode: C; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */
2
3 /*
4 * GImageView
5 * Copyright (C) 2001-2002 Takuro Ashie
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * $Id: gimv_dupl_win.c,v 1.5 2004/04/08 13:39:25 makeinu Exp $
22 */
23
24 #include "gimv_dupl_win.h"
25
26 #include "charset.h"
27 #include "fileutil.h"
28 #include "gimv_cell_pixmap.h"
29 #include "gimv_icon_stock.h"
30 #include "gimv_image_info.h"
31 #include "gimv_thumb.h"
32 #include "prefs.h"
33
34 struct GimvDuplWinPriv_Tag
35 {
36 gint thumbnail_size;
37
38 GList *thumb_list;
39
40 #ifdef USE_GTK2
41 GtkTreeViewColumn *pixmap_col;
42 GtkCellRenderer *pixmap_renderer;
43 #endif /* USE_GTK2 */
44 };
45
46 static void gimv_dupl_win_init (GimvDuplWin *sw);
47 static void gimv_dupl_win_class_init (GimvDuplWinClass *klass);
48 static void gimv_dupl_win_destroy (GtkObject *object);
49
50
51 static void cb_select_all_button (GtkButton *button,
52 GimvDuplWin *sw);
53 static void cb_finder_stop_button (GtkWidget *widget,
54 GimvDuplWin *sw);
55 static void cb_finder_start (GimvDuplFinder *finder,
56 GimvDuplWin *sw);
57 static void cb_finder_stop (GimvDuplFinder *finder,
58 GimvDuplWin *sw);
59 static void cb_finder_progress_update (GimvDuplFinder *finder,
60 GimvDuplWin *sw);
61 static void cb_finder_found (GimvDuplFinder *finder,
62 GimvDuplPair *pair,
63 GimvDuplWin *sw);
64 static void cb_select_thumb (GimvThumb *thumb,
65 GimvDuplWin *sw);
66
67 #ifdef ENABLE_TREEVIEW
68
69 typedef enum {
70 COLUMN_TERMINATOR = -1,
71 COLUMN_THUMBNAIL,
72 COLUMN_THUMBNAIL_MASK,
73 COLUMN_ICON,
74 COLUMN_ICON_MASK,
75 COLUMN_NAME,
76 COLUMN_ACCURACY,
77 COLUMN_SIZE,
78 COLUMN_MTIME,
79 COLUMN_THUMBDATA,
80 N_COLUMN
81 } TreeStoreColumn;
82
83 static void cb_tree_cursor_changed (GtkTreeView *treeview,
84 GimvDuplWin *sw);
85 static void cb_change_to_thumbnail_button (GtkButton *button,
86 GimvDuplWin *sw);
87 static void cb_change_to_icon_button (GtkButton *button,
88 GimvDuplWin *sw);
89 static gboolean find_row (GimvDuplWin *sw,
90 GimvThumb *thumb,
91 GtkTreeIter *iter,
92 GtkTreeIter *parent_iter);
93 static gboolean insert_node (GimvDuplWin *sw,
94 GtkTreeIter *iter,
95 GtkTreeIter *parent_iter,
96 GimvThumb *thumb,
97 gfloat similar);
98
99 #else /* ENABLE_TREEVIEW */
100
101 static void set_pixtext (GtkCTree *ctree,
102 GtkCTreeNode *node,
103 gpointer data);
104 static void cb_change_to_thumbnail_button (GtkButton *button,
105 GimvDuplWin *sw);
106 static void cb_change_to_icon_button (GtkButton *button,
107 GimvDuplWin *sw);
108 static void cb_ctree_select_row (GtkCTree *ctree,
109 GList *node,
110 gint column,
111 GimvDuplWin *sw);
112 static GtkCTreeNode *insert_node (GimvDuplWin *sw,
113 GtkCTreeNode *parent,
114 GimvThumb *thumb,
115 gfloat similar);
116
117 #endif /* ENABLE_TREEVIEW */
118
119
120 gchar *simwin_titles[4] = {
121 N_("Name"),
122 N_("Accuracy"),
123 N_("Size (byte)"),
124 N_("Modification Time")
125 };
126 gint simwin_column_num = sizeof (simwin_titles) / sizeof (gchar *);
127
128 static GtkDialogClass *parent_class = NULL;
129
130
131 GtkType
gimv_dupl_win_get_type(void)132 gimv_dupl_win_get_type (void)
133 {
134 static GtkType gimv_dupl_win_type = 0;
135
136 if (!gimv_dupl_win_type) {
137 static const GtkTypeInfo gimv_dupl_win_info = {
138 "GimvDuplWin",
139 sizeof (GimvDuplWin),
140 sizeof (GimvDuplWinClass),
141 (GtkClassInitFunc) gimv_dupl_win_class_init,
142 (GtkObjectInitFunc) gimv_dupl_win_init,
143 NULL,
144 NULL,
145 (GtkClassInitFunc) NULL,
146 };
147
148 gimv_dupl_win_type = gtk_type_unique (gtk_dialog_get_type (),
149 &gimv_dupl_win_info);
150 }
151
152 return gimv_dupl_win_type;
153 }
154
155
156 static void
gimv_dupl_win_init(GimvDuplWin * sw)157 gimv_dupl_win_init (GimvDuplWin *sw)
158 {
159 GtkWidget *hbox;
160 GtkWidget *scrolledwin, *radio, *button;
161 gint i;
162
163 sw->ctree = NULL;
164 sw->radio_thumb = NULL;
165 sw->radio_icon = NULL;
166 sw->select_button = NULL;
167 sw->progressbar = NULL;
168
169 sw->finder = gimv_dupl_finder_new (NULL);
170 sw->tv = NULL;
171
172 sw->priv = g_new0 (GimvDuplWinPriv, 1);
173 sw->priv->thumbnail_size = 96;
174 sw->priv->thumb_list = NULL;
175 #ifdef ENABLE_TREEVIEW
176 sw->priv->pixmap_col = NULL;
177 sw->priv->pixmap_renderer = NULL;
178 #endif /* ENABLE_TREEVIEW */
179
180 /* window */
181 gtk_window_set_title (GTK_WINDOW (sw), _("Find Duplicates - result"));
182 gtk_window_set_default_size (GTK_WINDOW (sw), 500, 400);
183 gtk_window_set_position (GTK_WINDOW (sw), GTK_WIN_POS_MOUSE);
184
185 /* ctree */
186 scrolledwin = gtk_scrolled_window_new (NULL, NULL);
187 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scrolledwin),
188 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
189 gtk_container_set_border_width (GTK_CONTAINER (scrolledwin), 5);
190
191 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (sw)->vbox),
192 scrolledwin, TRUE, TRUE, 0);
193
194 #ifdef ENABLE_TREEVIEW
195 {
196 GtkTreeStore *store;
197 GtkTreeViewColumn *col;
198 GtkCellRenderer *render;
199
200 store = gtk_tree_store_new (N_COLUMN,
201 GDK_TYPE_PIXMAP,
202 GDK_TYPE_PIXMAP,
203 GDK_TYPE_PIXMAP,
204 GDK_TYPE_PIXMAP,
205 G_TYPE_STRING,
206 G_TYPE_STRING,
207 G_TYPE_STRING,
208 G_TYPE_STRING,
209 G_TYPE_POINTER);
210 sw->ctree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
211 gtk_container_add (GTK_CONTAINER (scrolledwin), sw->ctree);
212
213 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (sw->ctree), TRUE);
214
215 /* name column */
216 col = gtk_tree_view_column_new();
217 sw->priv->pixmap_col = col;
218 gtk_tree_view_column_set_title (col, _(simwin_titles[0]));
219
220 render = gimv_cell_renderer_pixmap_new ();
221 sw->priv->pixmap_renderer = render;
222 gtk_tree_view_column_pack_start (col, render, FALSE);
223 gtk_tree_view_column_add_attribute (col, render,
224 "pixmap", COLUMN_ICON);
225 gtk_tree_view_column_add_attribute (col, render,
226 "mask", COLUMN_ICON_MASK);
227
228 render = gtk_cell_renderer_text_new ();
229 gtk_tree_view_column_pack_start (col, render, TRUE);
230 gtk_tree_view_column_add_attribute (col, render, "text", COLUMN_NAME);
231
232 gtk_tree_view_append_column (GTK_TREE_VIEW (sw->ctree), col);
233 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (sw->ctree), col);
234
235 /* other column */
236 for (i = 1; i < simwin_column_num; i++) {
237 col = gtk_tree_view_column_new();
238 gtk_tree_view_column_set_title (col, _(simwin_titles[i]));
239
240 render = gtk_cell_renderer_text_new ();
241 gtk_tree_view_column_pack_start (col, render, TRUE);
242 gtk_tree_view_column_add_attribute (col, render, "text",
243 COLUMN_NAME + i);
244
245 gtk_tree_view_append_column (GTK_TREE_VIEW (sw->ctree), col);
246 }
247
248 g_signal_connect (G_OBJECT (sw->ctree), "cursor_changed",
249 G_CALLBACK (cb_tree_cursor_changed), sw);
250 }
251 #else /* ENABLE_TREEVIEW */
252 {
253 for (i = 0; i < simwin_column_num; i++)
254 simwin_titles[i] = _(simwin_titles[i]);
255 sw->ctree = gtk_ctree_new_with_titles (simwin_column_num, 0, simwin_titles);
256 gtk_clist_set_column_width (GTK_CLIST (sw->ctree), 0, 250);
257 gtk_clist_set_column_width (GTK_CLIST (sw->ctree), 1, 50);
258 gtk_clist_set_column_width (GTK_CLIST (sw->ctree), 2, 50);
259 gtk_clist_set_column_width (GTK_CLIST (sw->ctree), 3, 150);
260 /*
261 for (i = 0; i < simwin_column_num; i++)
262 gtk_clist_set_column_auto_resize (GTK_CLIST (sw->ctree), i, TRUE);
263 */
264 gtk_clist_set_column_justification(GTK_CLIST (sw->ctree), 1,
265 GTK_JUSTIFY_CENTER);
266 gtk_clist_set_column_justification(GTK_CLIST (sw->ctree), 2,
267 GTK_JUSTIFY_RIGHT);
268 gtk_container_add (GTK_CONTAINER (scrolledwin), sw->ctree);
269
270 gtk_signal_connect (GTK_OBJECT (sw->ctree), "tree_select_row",
271 GTK_SIGNAL_FUNC (cb_ctree_select_row), sw);
272 }
273 #endif /* ENABLE_TREEVIEW */
274
275 /* button */
276 hbox = gtk_hbox_new (FALSE, 0);
277 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (sw)->action_area),
278 hbox, TRUE, TRUE, 0);
279
280 /* radio button */
281 radio = gtk_radio_button_new_with_label (NULL, _("Thumbnail"));
282 sw->radio_thumb = radio;
283 gtk_signal_connect (GTK_OBJECT (radio), "clicked",
284 GTK_SIGNAL_FUNC (cb_change_to_thumbnail_button), sw);
285 gtk_box_pack_start (GTK_BOX (hbox), radio, FALSE, FALSE, 0);
286
287 radio = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (radio),
288 _("Icon"));
289 sw->radio_icon = radio;
290 gtk_signal_connect (GTK_OBJECT (radio), "clicked",
291 GTK_SIGNAL_FUNC (cb_change_to_icon_button), sw);
292 gtk_box_pack_start (GTK_BOX (hbox), radio, FALSE, FALSE, 0);
293
294 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio), TRUE);
295
296 /* Select All */
297 button = gtk_button_new_with_label (_("Select All"));
298 sw->select_button = button;
299 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
300 gtk_signal_connect (GTK_OBJECT (button), "clicked",
301 GTK_SIGNAL_FUNC (cb_select_all_button), sw);
302 GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT);
303 gtk_widget_show (button);
304
305 /* close button */
306 button = gtk_button_new_with_label (_("Stop"));
307 sw->stop_button = button;
308 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
309 gtk_signal_connect (GTK_OBJECT (button), "clicked",
310 GTK_SIGNAL_FUNC (cb_finder_stop_button), sw);
311 GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT);
312 gtk_widget_show (button);
313
314 /* gtk_widget_grab_focus (button); */
315
316 /* progress bar */
317 sw->progressbar = gtk_progress_bar_new();
318 gtk_box_pack_end (GTK_BOX (hbox), sw->progressbar, FALSE, FALSE, 0);
319
320 /* finder */
321 gtk_signal_connect (GTK_OBJECT (sw->finder), "start",
322 GTK_SIGNAL_FUNC (cb_finder_start), sw);
323 gtk_signal_connect (GTK_OBJECT (sw->finder), "stop",
324 GTK_SIGNAL_FUNC (cb_finder_stop), sw);
325 gtk_signal_connect (GTK_OBJECT (sw->finder), "progress_update",
326 GTK_SIGNAL_FUNC (cb_finder_progress_update), sw);
327 gtk_signal_connect (GTK_OBJECT (sw->finder), "found",
328 GTK_SIGNAL_FUNC (cb_finder_found), sw);
329 }
330
331
332 static void
gimv_dupl_win_class_init(GimvDuplWinClass * klass)333 gimv_dupl_win_class_init (GimvDuplWinClass *klass)
334 {
335 GtkObjectClass *object_class;
336
337 object_class = (GtkObjectClass *) klass;
338 parent_class = gtk_type_class (gtk_dialog_get_type ());
339
340 object_class->destroy = gimv_dupl_win_destroy;
341 }
342
343
344 static void
gimv_dupl_win_destroy(GtkObject * object)345 gimv_dupl_win_destroy (GtkObject *object)
346 {
347 GimvDuplWin *sw = GIMV_DUPL_WIN (object);
348
349 g_return_if_fail (sw);
350
351 if (sw->priv) {
352 g_list_foreach (sw->priv->thumb_list, (GFunc) gtk_object_unref, NULL);
353 g_list_free (sw->priv->thumb_list);
354 sw->priv->thumb_list = NULL;
355 g_free (sw->priv);
356 sw->priv = NULL;
357 }
358
359 if (sw->finder) {
360 gtk_object_unref (GTK_OBJECT (sw->finder));
361 sw->finder = NULL;
362 }
363
364 if (GTK_OBJECT_CLASS (parent_class)->destroy)
365 (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
366 }
367
368
369 static void
ghfunc_select_thumb(GimvThumb * thumb)370 ghfunc_select_thumb (GimvThumb *thumb)
371 {
372 gimv_thumb_view_set_selection (thumb, TRUE);
373 }
374
375
376 static void
cb_select_all_button(GtkButton * button,GimvDuplWin * sw)377 cb_select_all_button (GtkButton *button, GimvDuplWin *sw)
378 {
379 g_return_if_fail (sw);
380 if (!sw->tv) return;
381
382 gimv_thumb_view_set_selection_all (sw->tv, FALSE);
383 g_list_foreach (sw->priv->thumb_list, (GFunc) ghfunc_select_thumb, NULL);
384 }
385
386
387 static void
cb_finder_stop_button(GtkWidget * widget,GimvDuplWin * sw)388 cb_finder_stop_button (GtkWidget *widget, GimvDuplWin *sw)
389 {
390 g_return_if_fail (sw);
391
392 if (sw->finder)
393 gimv_dupl_finder_stop (sw->finder);
394 }
395
396
397 static void
cb_finder_start(GimvDuplFinder * finder,GimvDuplWin * sw)398 cb_finder_start (GimvDuplFinder *finder, GimvDuplWin *sw)
399 {
400 gfloat progress;
401
402 g_return_if_fail (GIMV_IS_DUPL_FINDER (finder));
403 g_return_if_fail (sw);
404
405 gtk_widget_set_sensitive (sw->stop_button, TRUE);
406
407 gtk_progress_set_show_text (GTK_PROGRESS (sw->progressbar), TRUE);
408 gtk_progress_set_format_string (GTK_PROGRESS (sw->progressbar),
409 _("Finding similar images..."));
410 progress = gimv_dupl_finder_get_progress (finder);
411 gtk_progress_bar_update (GTK_PROGRESS_BAR (sw->progressbar), progress);
412 }
413
414
415 static void
cb_finder_stop(GimvDuplFinder * finder,GimvDuplWin * sw)416 cb_finder_stop (GimvDuplFinder *finder, GimvDuplWin *sw)
417 {
418 g_return_if_fail (GIMV_IS_DUPL_FINDER (finder));
419 g_return_if_fail (sw);
420
421 gtk_widget_set_sensitive (sw->stop_button, FALSE);
422
423 gtk_progress_bar_update (GTK_PROGRESS_BAR (sw->progressbar), 0.0);
424 /* gtk_progress_set_show_text (GTK_PROGRESS (sw->progressbar), FALSE); */
425 gtk_progress_set_format_string (GTK_PROGRESS (sw->progressbar),
426 _("Completed"));
427 }
428
429
430 static void
cb_finder_progress_update(GimvDuplFinder * finder,GimvDuplWin * sw)431 cb_finder_progress_update (GimvDuplFinder *finder, GimvDuplWin *sw)
432 {
433 gfloat progress;
434
435 g_return_if_fail (GIMV_IS_DUPL_FINDER (finder));
436 g_return_if_fail (sw);
437
438 progress = gimv_dupl_finder_get_progress (finder);
439 gtk_progress_bar_update (GTK_PROGRESS_BAR (sw->progressbar), progress);
440 }
441
442
443 static void
cb_finder_found(GimvDuplFinder * finder,GimvDuplPair * pair,GimvDuplWin * sw)444 cb_finder_found (GimvDuplFinder *finder, GimvDuplPair *pair, GimvDuplWin *sw)
445 {
446 g_return_if_fail (GIMV_IS_DUPL_FINDER (finder));
447 g_return_if_fail (sw);
448 g_return_if_fail (pair);
449
450 gimv_dupl_win_set_thumb (sw, pair->thumb1, pair->thumb2, pair->similarity);
451 }
452
453
454 static void
cb_select_thumb(GimvThumb * thumb,GimvDuplWin * sw)455 cb_select_thumb (GimvThumb *thumb, GimvDuplWin *sw)
456 {
457 g_return_if_fail (GIMV_IS_THUMB (thumb));
458 g_return_if_fail (sw);
459
460 if (conf.simwin_sel_thumbview) {
461 gimv_thumb_view_set_selection_all (sw->tv, FALSE);
462 gimv_thumb_view_set_selection (thumb, TRUE);
463 gimv_thumb_view_adjust (sw->tv, thumb);
464 }
465
466 if (conf.simwin_sel_preview)
467 gimv_thumb_view_open_image (sw->tv, thumb,
468 GIMV_THUMB_VIEW_OPEN_IMAGE_PREVIEW);
469 if (conf.simwin_sel_new_win)
470 gimv_thumb_view_open_image (sw->tv, thumb,
471 GIMV_THUMB_VIEW_OPEN_IMAGE_NEW_WIN);
472 if (conf.simwin_sel_shared_win)
473 gimv_thumb_view_open_image (sw->tv, thumb,
474 GIMV_THUMB_VIEW_OPEN_IMAGE_SHARED_WIN);
475 }
476
477
478 #ifdef ENABLE_TREEVIEW
479
480 static void
cb_tree_cursor_changed(GtkTreeView * treeview,GimvDuplWin * sw)481 cb_tree_cursor_changed (GtkTreeView *treeview, GimvDuplWin *sw)
482 {
483 GtkTreeSelection *selection;
484 GtkTreeModel *model;
485 GtkTreeIter iter;
486 GimvThumb *thumb;
487
488 g_return_if_fail (treeview);
489 g_return_if_fail (sw);
490
491 if (!sw->tv) return;
492
493 selection = gtk_tree_view_get_selection (treeview);
494 if (!gtk_tree_selection_get_selected (selection, &model, &iter)) return;
495 gtk_tree_model_get (model, &iter,
496 COLUMN_THUMBDATA, &thumb,
497 COLUMN_TERMINATOR);
498
499 g_return_if_fail (GIMV_IS_THUMB (thumb));
500
501 cb_select_thumb (thumb, sw);
502 }
503
504
505 static void
cb_change_to_thumbnail_button(GtkButton * button,GimvDuplWin * sw)506 cb_change_to_thumbnail_button (GtkButton *button, GimvDuplWin *sw)
507 {
508 g_return_if_fail (sw);
509
510 gtk_tree_view_column_clear_attributes (sw->priv->pixmap_col,
511 sw->priv->pixmap_renderer);
512 gtk_tree_view_column_add_attribute (sw->priv->pixmap_col,
513 sw->priv->pixmap_renderer,
514 "pixmap", COLUMN_THUMBNAIL);
515 gtk_tree_view_column_add_attribute (sw->priv->pixmap_col,
516 sw->priv->pixmap_renderer,
517 "mask", COLUMN_THUMBNAIL_MASK);
518 }
519
520
521 static void
cb_change_to_icon_button(GtkButton * button,GimvDuplWin * sw)522 cb_change_to_icon_button (GtkButton *button, GimvDuplWin *sw)
523 {
524 g_return_if_fail (sw);
525
526 gtk_tree_view_column_clear_attributes (sw->priv->pixmap_col,
527 sw->priv->pixmap_renderer);
528 gtk_tree_view_column_add_attribute (sw->priv->pixmap_col,
529 sw->priv->pixmap_renderer,
530 "pixmap", COLUMN_ICON);
531 gtk_tree_view_column_add_attribute (sw->priv->pixmap_col,
532 sw->priv->pixmap_renderer,
533 "mask", COLUMN_ICON_MASK);
534 }
535
536
537 static gboolean
find_row(GimvDuplWin * sw,GimvThumb * thumb,GtkTreeIter * iter,GtkTreeIter * parent_iter)538 find_row (GimvDuplWin *sw, GimvThumb *thumb,
539 GtkTreeIter *iter, GtkTreeIter *parent_iter)
540 {
541 GtkTreeModel *model;
542 GtkTreeIter tmp_iter;
543 GimvThumb *tmp_thumb;
544 gboolean go_next;
545
546 g_return_val_if_fail (sw && thumb && iter, FALSE);
547
548 model = gtk_tree_view_get_model (GTK_TREE_VIEW (sw->ctree));
549
550 if (!parent_iter)
551 go_next = gtk_tree_model_get_iter_first (model, iter);
552 else
553 go_next = gtk_tree_model_iter_children (model, iter, parent_iter);
554
555 for (; go_next; go_next = gtk_tree_model_iter_next (model, iter)) {
556 gtk_tree_model_get (model, iter,
557 COLUMN_THUMBDATA, &tmp_thumb,
558 COLUMN_TERMINATOR);
559
560 if (tmp_thumb == thumb)
561 return TRUE;
562
563 if (find_row (sw, thumb, &tmp_iter, iter)) {
564 *iter = tmp_iter;
565 return TRUE;
566 }
567 }
568
569 return FALSE;
570 }
571
572
573 static gboolean
insert_node(GimvDuplWin * sw,GtkTreeIter * iter,GtkTreeIter * parent_iter,GimvThumb * thumb,gfloat similar)574 insert_node (GimvDuplWin *sw,
575 GtkTreeIter *iter, GtkTreeIter *parent_iter,
576 GimvThumb *thumb, gfloat similar)
577 {
578 GtkTreeModel *model;
579 GdkPixmap *thumb_pixmap, *icon_pixmap;
580 GdkBitmap *thumb_mask, *icon_mask;
581 gchar *text[32], accuracy[32], *tmpstr;
582
583 g_return_val_if_fail (GIMV_IS_THUMB (thumb), FALSE);
584
585 gimv_thumb_get_thumb (thumb, &thumb_pixmap, &thumb_mask);
586 gimv_thumb_get_icon (thumb, &icon_pixmap, &icon_mask);
587
588 text[0] = (gchar *) gimv_image_info_get_path (thumb->info);
589 text[0] = charset_to_internal (text[0],
590 conf.charset_filename,
591 conf.charset_auto_detect_fn,
592 conf.charset_filename_mode);
593
594 if (similar > 0) {
595 g_snprintf (accuracy, 32, "%2.1f%%", similar * 100);
596 text[1] = accuracy;
597 } else {
598 text[1] = NULL;
599 }
600
601 tmpstr = fileutil_size2str (thumb->info->st.st_size, FALSE);
602 text[2] = charset_locale_to_internal (tmpstr);
603 g_free (tmpstr);
604
605 tmpstr = fileutil_time2str (thumb->info->st.st_mtime);
606 text[3] = charset_locale_to_internal (tmpstr);
607 g_free (tmpstr);
608
609 gtk_object_ref (GTK_OBJECT(thumb));
610 sw->priv->thumb_list = g_list_append (sw->priv->thumb_list, thumb);
611
612 model = gtk_tree_view_get_model (GTK_TREE_VIEW (sw->ctree));
613 gtk_tree_store_append (GTK_TREE_STORE (model), iter, parent_iter);
614 gtk_tree_store_set (GTK_TREE_STORE (model), iter,
615 COLUMN_THUMBNAIL, thumb_pixmap,
616 COLUMN_THUMBNAIL_MASK, thumb_mask,
617 COLUMN_ICON, icon_pixmap,
618 COLUMN_ICON_MASK, icon_mask,
619 COLUMN_NAME, text[0],
620 COLUMN_ACCURACY, text[1],
621 COLUMN_SIZE, text[2],
622 COLUMN_MTIME, text[3],
623 COLUMN_THUMBDATA, thumb,
624 COLUMN_TERMINATOR);
625
626 g_free (text[0]);
627 g_free (text[2]);
628 g_free (text[3]);
629
630 return TRUE;
631 }
632
633 #else /* ENABLE_TREEVIEW */
634
635 static void
set_pixtext(GtkCTree * ctree,GtkCTreeNode * node,gpointer data)636 set_pixtext (GtkCTree *ctree, GtkCTreeNode *node, gpointer data)
637 {
638 gboolean thumbnail = GPOINTER_TO_INT (data);
639 GimvThumb *thumb;
640 GdkPixmap *pixmap;
641 GdkBitmap *mask;
642 guint8 spacing;
643 gboolean is_leaf, expanded;
644 gchar *text;
645
646 g_return_if_fail (ctree);
647 g_return_if_fail (node);
648
649 thumb = gtk_ctree_node_get_row_data (ctree, node);
650 g_return_if_fail (GIMV_IS_THUMB (thumb));
651
652 if (thumbnail)
653 gimv_thumb_get_thumb (thumb, &pixmap, &mask);
654 else
655 gimv_thumb_get_icon (thumb, &pixmap, &mask);
656
657 gtk_ctree_get_node_info (ctree, node, &text, &spacing,
658 NULL, NULL, NULL, NULL,
659 &is_leaf, &expanded);
660 gtk_ctree_set_node_info (ctree, node,
661 text, spacing,
662 pixmap, mask, pixmap, mask,
663 is_leaf, expanded);
664 }
665
666
667 static void
cb_change_to_thumbnail_button(GtkButton * button,GimvDuplWin * sw)668 cb_change_to_thumbnail_button (GtkButton *button, GimvDuplWin *sw)
669 {
670 g_return_if_fail (sw);
671
672 gtk_clist_set_row_height (GTK_CLIST (sw->ctree), sw->priv->thumbnail_size);
673 gtk_ctree_post_recursive (GTK_CTREE (sw->ctree), NULL,
674 (GtkCTreeFunc) set_pixtext,
675 GINT_TO_POINTER (TRUE));
676 }
677
678
679 static void
cb_change_to_icon_button(GtkButton * button,GimvDuplWin * sw)680 cb_change_to_icon_button (GtkButton *button, GimvDuplWin *sw)
681 {
682 g_return_if_fail (sw);
683
684 gtk_clist_set_row_height (GTK_CLIST (sw->ctree), ICON_SIZE);
685 gtk_ctree_post_recursive (GTK_CTREE (sw->ctree), NULL,
686 (GtkCTreeFunc) set_pixtext,
687 GINT_TO_POINTER (FALSE));
688 }
689
690
691 static void
cb_ctree_select_row(GtkCTree * ctree,GList * node,gint column,GimvDuplWin * sw)692 cb_ctree_select_row (GtkCTree *ctree, GList *node, gint column, GimvDuplWin *sw)
693 {
694 GimvThumb *thumb;
695
696 g_return_if_fail (ctree);
697 g_return_if_fail (node);
698 g_return_if_fail (sw);
699
700 if (!sw->tv) return;
701
702 thumb = gtk_ctree_node_get_row_data (ctree, GTK_CTREE_NODE (node));
703 g_return_if_fail (GIMV_IS_THUMB (thumb));
704
705 cb_select_thumb (thumb, sw);
706 }
707
708
709 static GtkCTreeNode *
insert_node(GimvDuplWin * sw,GtkCTreeNode * parent,GimvThumb * thumb,gfloat similar)710 insert_node (GimvDuplWin *sw,
711 GtkCTreeNode *parent,
712 GimvThumb *thumb,
713 gfloat similar)
714 {
715 GtkCTreeNode *node;
716 GdkPixmap *pixmap;
717 GdkBitmap *mask;
718 gchar *text[32], accuracy[32], *tmpstr;
719
720 g_return_val_if_fail (GIMV_IS_THUMB (thumb), NULL);
721
722 if (GTK_TOGGLE_BUTTON (sw->radio_thumb)->active)
723 gimv_thumb_get_thumb (thumb, &pixmap, &mask);
724 else
725 gimv_thumb_get_icon (thumb, &pixmap, &mask);
726
727 text[0] = (gchar *) gimv_image_info_get_path (thumb->info);
728 text[0] = charset_to_internal (text[0],
729 conf.charset_filename,
730 conf.charset_auto_detect_fn,
731 conf.charset_filename_mode);
732
733 if (similar > 0) {
734 g_snprintf (accuracy, 32, "%2.1f%%", similar * 100);
735 text[1] = accuracy;
736 } else {
737 text[1] = NULL;
738 }
739
740 tmpstr = fileutil_size2str (thumb->info->st.st_size, FALSE);
741 text[2] = charset_locale_to_internal (tmpstr);
742 g_free (tmpstr);
743
744 tmpstr = fileutil_time2str (thumb->info->st.st_mtime);
745 text[3] = charset_locale_to_internal (tmpstr);
746 g_free (tmpstr);
747
748 node = gtk_ctree_insert_node (GTK_CTREE (sw->ctree),
749 parent, NULL, text, 4,
750 pixmap, mask,
751 pixmap, mask,
752 FALSE, FALSE);
753 gtk_object_ref (GTK_OBJECT(thumb));
754 sw->priv->thumb_list = g_list_append (sw->priv->thumb_list, thumb);
755 gtk_ctree_node_set_row_data (GTK_CTREE (sw->ctree), node, thumb);
756
757 g_free (text[0]);
758 g_free (text[2]);
759 g_free (text[3]);
760
761 return node;
762 }
763
764 #endif /* ENABLE_TREEVIEW */
765
766
767
768 /******************************************************************************
769 *
770 * Public Functions.
771 *
772 ******************************************************************************/
773 GimvDuplWin *
gimv_dupl_win_new(gint thumbnail_size)774 gimv_dupl_win_new (gint thumbnail_size)
775 {
776 GimvDuplWin *sw;
777
778 sw = GIMV_DUPL_WIN (gtk_type_new (gimv_dupl_win_get_type ()));
779
780 /* FIXME */
781 sw->priv->thumbnail_size = thumbnail_size;
782 gtk_widget_show_all (GTK_WIDGET (sw));
783 gimv_icon_stock_set_window_icon (GTK_WIDGET (sw)->window, "gimv_icon");
784 /* END FIXME */
785
786 return sw;
787 }
788
789
790 void
gimv_dupl_win_set_relation(GimvDuplWin * sw,GimvThumbView * tv)791 gimv_dupl_win_set_relation (GimvDuplWin *sw, GimvThumbView *tv)
792 {
793 g_return_if_fail (sw);
794 g_return_if_fail (tv);
795
796 sw->tv = tv;
797
798 gtk_widget_set_sensitive (sw->select_button, TRUE);
799 }
800
801
802 void
gimv_dupl_win_unset_relation(GimvDuplWin * sw)803 gimv_dupl_win_unset_relation (GimvDuplWin *sw)
804 {
805 g_return_if_fail (sw);
806
807 sw->tv = NULL;
808
809 gtk_widget_set_sensitive (sw->select_button, FALSE);
810 }
811
812
813 void
gimv_dupl_win_set_thumb(GimvDuplWin * sw,GimvThumb * thumb1,GimvThumb * thumb2,gfloat similar)814 gimv_dupl_win_set_thumb (GimvDuplWin *sw,
815 GimvThumb *thumb1,
816 GimvThumb*thumb2,
817 gfloat similar)
818 {
819 g_return_if_fail (sw);
820 g_return_if_fail (GIMV_IS_THUMB (thumb1));
821 g_return_if_fail (GIMV_IS_THUMB (thumb2));
822
823 #ifdef ENABLE_TREEVIEW
824 {
825 GtkTreeIter parent_iter, iter;
826 gboolean success;
827
828 success = find_row (sw, thumb1, &parent_iter, NULL);
829 if (!success) {
830 GtkTreeView *treeview = GTK_TREE_VIEW (sw->ctree);
831 GtkTreeModel *model;
832 GtkTreeSelection *selection;
833
834 success = insert_node (sw, &parent_iter, NULL, thumb1, -1);
835
836 selection = gtk_tree_view_get_selection (treeview);
837 if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
838 if (find_row (sw, thumb1, &iter, NULL)) {
839 GtkTreePath *treepath = gtk_tree_model_get_path (model, &parent_iter);
840
841 g_signal_handlers_block_by_func (sw->ctree,
842 cb_tree_cursor_changed,
843 sw);
844 gtk_tree_view_set_cursor (treeview, treepath, NULL, FALSE);
845 g_signal_handlers_unblock_by_func (sw->ctree,
846 cb_tree_cursor_changed,
847 sw);
848 gtk_tree_path_free (treepath);
849 }
850 }
851 }
852 if (success) {
853 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (sw->ctree));
854 GtkTreePath *treepath = gtk_tree_model_get_path (model, &parent_iter);
855
856 success = insert_node (sw, &iter, &parent_iter, thumb2, similar);
857 gtk_tree_view_expand_row (GTK_TREE_VIEW (sw->ctree), treepath, FALSE);
858 gtk_tree_path_free (treepath);
859 }
860 }
861 #else /* ENABLE_TREEVIEW */
862 {
863 GtkCTreeNode *parent, *node;
864
865 node = gtk_ctree_find_by_row_data (GTK_CTREE (sw->ctree), NULL, thumb1);
866 if (node)
867 parent = node;
868 else
869 parent = insert_node (sw, node, thumb1, -1);
870
871 node = insert_node (sw, parent, thumb2, similar);
872 gtk_ctree_expand (GTK_CTREE (sw->ctree), parent);
873 }
874 #endif /* ENABLE_TREEVIEW */
875 }
876