aboutsummaryrefslogtreecommitdiff
path: root/src/fs/gnunet-fs-gtk_publish-dialog.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs/gnunet-fs-gtk_publish-dialog.c')
-rw-r--r--src/fs/gnunet-fs-gtk_publish-dialog.c1596
1 files changed, 1596 insertions, 0 deletions
diff --git a/src/fs/gnunet-fs-gtk_publish-dialog.c b/src/fs/gnunet-fs-gtk_publish-dialog.c
new file mode 100644
index 00000000..1dd67f62
--- /dev/null
+++ b/src/fs/gnunet-fs-gtk_publish-dialog.c
@@ -0,0 +1,1596 @@
1/*
2 This file is part of GNUnet
3 (C) 2005, 2006, 2010 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file src/fs/gnunet-fs-gtk_publish-dialog.c
23 * @author Christian Grothoff
24 */
25#include "gnunet-fs-gtk-common.h"
26#include "gnunet-fs-gtk.h"
27#include "gnunet-fs-gtk-edit_publish_dialog.h"
28#include <gnunet/gnunet_util_lib.h>
29#include <gnunet/gnunet_fs_service.h>
30
31#define MARKER_DIR_FILE_SIZE "-"
32
33#define VERBOSE_PROGRESS GNUNET_NO
34
35struct AddDirClientContext;
36
37struct MainPublishingDialogContext
38{
39 GtkBuilder *builder;
40 GtkBuilder *main_window_builder;
41 GtkTreeView *pseudonym_treeview;
42 GtkTreeSelection *pseudonym_selection;
43 GtkTreeModel *pseudonym_treemodel;
44 GtkWidget *up_button;
45 GtkWidget *down_button;
46 GtkWidget *left_button;
47 GtkWidget *right_button;
48 GtkWidget *delete_button;
49 GtkWidget *edit_button;
50 GtkWidget *execute_button;
51 GtkWidget *cancel_button;
52 GtkTreeView *file_info_treeview;
53 GtkTreeSelection *file_info_selection;
54 GtkTreeModel *file_info_treemodel;
55 GtkWindow *master_pubdialog;
56
57 gulong open_directory_handler_id;
58 GtkBuilder *open_directory_builder;
59
60 gulong open_file_handler_id;
61 GtkBuilder *open_file_builder;
62
63 /* To keep multiple scanners running */
64 struct AddDirClientContext *adddir_head;
65 struct AddDirClientContext *adddir_tail;
66};
67
68/* One of these is kept for every directory being opened */
69struct AddDirClientContext
70{
71 struct AddDirClientContext *prev;
72 struct AddDirClientContext *next;
73
74 struct GNUNET_FS_ProcessMetadataContext *pmc;
75
76 struct MainPublishingDialogContext *ctx;
77 struct GNUNET_FS_DirScanner *ds;
78
79 struct GNUNET_FS_ShareTreeItem *directory_scan_result;
80
81 struct GNUNET_FS_BlockOptions directory_scan_bo;
82 int directory_scan_do_index;
83
84 GtkBuilder *progress_dialog_builder;
85 GtkWidget *progress_dialog;
86 GtkProgressBar *progress_dialog_bar;
87 GtkButton *progress_dialog_cancel;
88 GtkTextView *progress_dialog_textview;
89 GtkTextBuffer *progress_dialog_textbuffer;
90 GtkTextMark *progress_dialog_textmark;
91 GtkAdjustment *textview_vertial_adjustment;
92
93 unsigned int done;
94 unsigned int total;
95};
96
97
98static void
99selection_changed_cb (GtkTreeSelection * ts, struct MainPublishingDialogContext *ctx);
100
101
102/**
103 * Check if two GtkTreeIters refer to the same element.
104 *
105 * @param tm tree model of the iterators
106 * @param i1 first iterator
107 * @param i2 second iterator
108 * @return GNUNET_YES if they are equal
109 */
110static int
111gtk_tree_iter_equals (GtkTreeModel * tm, GtkTreeIter * i1, GtkTreeIter * i2)
112{
113 GtkTreePath *p1;
114 GtkTreePath *p2;
115 int ret;
116
117 p1 = gtk_tree_model_get_path (tm, i1);
118 p2 = gtk_tree_model_get_path (tm, i2);
119 ret = gtk_tree_path_compare (p1, p2);
120 gtk_tree_path_free (p1);
121 gtk_tree_path_free (p2);
122 return (0 == ret) ? GNUNET_YES : GNUNET_NO;
123}
124
125/* Fill out the main publishing dialog context structure */
126static void
127init_ctx (struct MainPublishingDialogContext *ctx)
128{
129 ctx->pseudonym_treeview = GTK_TREE_VIEW (gtk_builder_get_object
130 (ctx->builder, "GNUNET_GTK_master_publish_dialog_pseudonym_tree_view"));
131
132 ctx->up_button = GTK_WIDGET (gtk_builder_get_object
133 (ctx->builder, "GNUNET_GTK_master_publish_dialog_up_button"));
134 ctx->down_button = GTK_WIDGET (gtk_builder_get_object
135 (ctx->builder, "GNUNET_GTK_master_publish_dialog_down_button"));
136 ctx->left_button = GTK_WIDGET (gtk_builder_get_object
137 (ctx->builder, "GNUNET_GTK_master_publish_dialog_left_button"));
138 ctx->right_button = GTK_WIDGET (gtk_builder_get_object
139 (ctx->builder, "GNUNET_GTK_master_publish_dialog_right_button"));
140 ctx->delete_button = GTK_WIDGET (gtk_builder_get_object
141 (ctx->builder, "GNUNET_GTK_master_publish_dialog_delete_button"));
142 ctx->edit_button = GTK_WIDGET (gtk_builder_get_object
143 (ctx->builder, "GNUNET_GTK_master_publish_dialog_edit_button"));
144 ctx->execute_button = GTK_WIDGET (gtk_builder_get_object
145 (ctx->builder, "GNUNET_GTK_master_publish_dialog_execute_button"));
146 ctx->cancel_button = GTK_WIDGET (gtk_builder_get_object
147 (ctx->builder , "GNUNET_GTK_master_publish_dialog_cancel_button"));
148 ctx->file_info_treeview = GTK_TREE_VIEW (gtk_builder_get_object
149 (ctx->builder, "GNUNET_GTK_master_publish_dialog_file_information_tree_view"));
150
151 ctx->master_pubdialog =
152 GTK_WINDOW (gtk_builder_get_object
153 (ctx->builder, "GNUNET_GTK_master_publish_dialog"));
154
155 ctx->file_info_selection = gtk_tree_view_get_selection (ctx->file_info_treeview);
156 ctx->file_info_treemodel = gtk_tree_view_get_model (ctx->file_info_treeview);
157 ctx->pseudonym_selection = gtk_tree_view_get_selection (ctx->pseudonym_treeview);
158 ctx->pseudonym_treemodel = gtk_tree_view_get_model (ctx->pseudonym_treeview);
159
160 g_signal_connect (G_OBJECT (ctx->file_info_selection), "changed",
161 G_CALLBACK (selection_changed_cb), ctx);
162 g_signal_connect (G_OBJECT (ctx->pseudonym_selection), "changed",
163 G_CALLBACK (selection_changed_cb), ctx);
164}
165
166/**
167 * Update selectivity in the master dialog.
168 */
169static void
170update_selectivity (struct MainPublishingDialogContext *ctx)
171{
172 GtkTreeIter iter;
173 GtkTreeIter parent;
174 GtkTreeIter pred;
175 int is_dir;
176 struct GNUNET_FS_FileInformation *fip;
177 int ns_ok;
178 gchar *namespace_id;
179
180 ns_ok = GNUNET_YES;
181 if (TRUE == gtk_tree_selection_get_selected (ctx->pseudonym_selection, NULL, &iter))
182 {
183 gtk_tree_model_get (ctx->pseudonym_treemodel, &iter, 2, &namespace_id, -1);
184 if (namespace_id == NULL)
185 ns_ok = GNUNET_NO;
186 else
187 g_free (namespace_id);
188 }
189 /* Don't let the user close the dialog until all scanners are finished and
190 * their windows are closed
191 */
192 if ((gtk_tree_model_get_iter_first (ctx->file_info_treemodel, &iter))
193 && (ns_ok == GNUNET_YES) && ctx->adddir_head == NULL)
194 gtk_widget_set_sensitive (ctx->execute_button, TRUE);
195 else
196 gtk_widget_set_sensitive (ctx->execute_button, FALSE);
197 if (ctx->adddir_head == NULL)
198 gtk_widget_set_sensitive (ctx->cancel_button, TRUE);
199 else
200 gtk_widget_set_sensitive (ctx->cancel_button, FALSE);
201 if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &iter))
202 {
203 gtk_widget_set_sensitive (ctx->up_button, FALSE);
204 gtk_widget_set_sensitive (ctx->down_button, FALSE);
205 gtk_widget_set_sensitive (ctx->left_button, FALSE);
206 gtk_widget_set_sensitive (ctx->right_button, FALSE);
207 gtk_widget_set_sensitive (ctx->delete_button, FALSE);
208 gtk_widget_set_sensitive (ctx->edit_button, FALSE);
209 return;
210 }
211 gtk_widget_set_sensitive (ctx->delete_button, TRUE);
212 gtk_widget_set_sensitive (ctx->edit_button, TRUE);
213
214 /* now figure out which move operations are currently legal */
215 GNUNET_assert (TRUE == gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &iter));
216 if (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, &iter))
217 {
218 gtk_widget_set_sensitive (ctx->down_button, TRUE);
219 }
220 else
221 {
222 gtk_widget_set_sensitive (ctx->down_button, FALSE);
223 }
224 GNUNET_assert (TRUE == gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &iter));
225 if (TRUE == gtk_tree_model_iter_parent (ctx->file_info_treemodel, &parent, &iter))
226 {
227 gtk_widget_set_sensitive (ctx->left_button, TRUE);
228 GNUNET_assert (TRUE == gtk_tree_model_iter_children (ctx->file_info_treemodel, &pred, &parent));
229 }
230 else
231 {
232 gtk_widget_set_sensitive (ctx->left_button, FALSE);
233 GNUNET_assert (TRUE == gtk_tree_model_get_iter_first (ctx->file_info_treemodel, &pred));
234 }
235 /* iterate over 'next' of pred to find out if our
236 * predecessor is a directory! */
237 is_dir = GNUNET_SYSERR;
238 while (GNUNET_YES != gtk_tree_iter_equals (ctx->file_info_treemodel, &pred, &iter))
239 {
240 gtk_tree_model_get (ctx->file_info_treemodel, &pred, 5, &fip, -1);
241 is_dir = GNUNET_FS_file_information_is_directory (fip);
242 GNUNET_assert (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, &pred));
243 }
244 if (GNUNET_YES == is_dir)
245 {
246 gtk_widget_set_sensitive (ctx->right_button, TRUE);
247 }
248 else
249 {
250 gtk_widget_set_sensitive (ctx->right_button, FALSE);
251 }
252 if (GNUNET_SYSERR != is_dir)
253 {
254 gtk_widget_set_sensitive (ctx->up_button, TRUE);
255 }
256 else
257 {
258 gtk_widget_set_sensitive (ctx->up_button, FALSE);
259 }
260}
261
262
263/**
264 * Add an empty directory to the tree model.
265 *
266 * @param name name for the directory
267 * @param bo block options
268 * @param iter parent entry, or NULL for top-level addition
269 * @param pos iterator to set to the location of the new element
270 */
271static void
272create_dir_at_iter (struct MainPublishingDialogContext *ctx, const char *name,
273 const struct GNUNET_FS_BlockOptions *bo, GtkTreeIter * iter,
274 GtkTreeIter * pos)
275{
276 struct GNUNET_FS_FileInformation *fi;
277 GtkTreeRowReference *row_reference;
278 GtkTreePath *path;
279 struct GNUNET_CONTAINER_MetaData *meta;
280
281 meta = GNUNET_CONTAINER_meta_data_create ();
282 GNUNET_FS_meta_data_make_directory (meta);
283 GNUNET_CONTAINER_meta_data_insert (meta, "<gnunet-gtk>",
284 EXTRACTOR_METATYPE_FILENAME,
285 EXTRACTOR_METAFORMAT_UTF8, "text/plain",
286 name, strlen (name) + 1);
287 gtk_tree_store_insert_before (GTK_TREE_STORE (ctx->file_info_treemodel), pos, iter, NULL);
288 path = gtk_tree_model_get_path (ctx->file_info_treemodel, pos);
289 row_reference = gtk_tree_row_reference_new (ctx->file_info_treemodel, path);
290 gtk_tree_path_free (path);
291 fi = GNUNET_FS_file_information_create_empty_directory
292 (GNUNET_FS_GTK_get_fs_handle (), row_reference, NULL, meta, bo, name);
293 GNUNET_CONTAINER_meta_data_destroy (meta);
294 gtk_tree_store_set (GTK_TREE_STORE (ctx->file_info_treemodel), pos, 0, MARKER_DIR_FILE_SIZE, 1, (gboolean) GNUNET_NO,
295 2, name, 3, (guint) bo->anonymity_level, 4,
296 (guint) bo->content_priority, 5, fi,
297 6, (guint64) bo->expiration_time.abs_value,
298 7, (guint) bo->replication_level,
299 -1);
300 update_selectivity (ctx);
301}
302
303static void
304selection_changed_cb (GtkTreeSelection * ts, struct MainPublishingDialogContext *ctx)
305{
306 update_selectivity (ctx);
307}
308
309static void
310remove_old_entry (GtkTreeStore * ts, GtkTreeIter * root)
311{
312 GtkTreeIter child;
313
314 while (TRUE ==
315 gtk_tree_model_iter_children (GTK_TREE_MODEL (ts), &child, root))
316 remove_old_entry (ts, &child);
317 gtk_tree_store_remove (ts, root);
318}
319
320
321/**
322 * Move an entry in the tree.
323 */
324static void
325move_entry (struct MainPublishingDialogContext *ctx, GtkTreeModel * tm, GtkTreeIter * old,
326 GtkTreeIter * newpos, int dsel)
327{
328 struct GNUNET_FS_FileInformation *fip;
329 gint do_index;
330 gchar *short_fn;
331 guint anonymity_level;
332 guint priority;
333 guint replication_level;
334 guint64 expiration_time_abs;
335 char *fsf;
336 GtkTreePath *path;
337 GtkTreeIter child;
338 GtkTreeIter cnewpos;
339 GtkTreeRowReference *rr;
340 GtkTreeRowReference *rr2;
341
342 gtk_tree_model_get (tm, old, 0, &fsf, 1, &do_index, 2, &short_fn, 3,
343 &anonymity_level, 4, &priority, 5, &fip,
344 6, &expiration_time_abs, 7, &replication_level, -1);
345 gtk_tree_store_set (GTK_TREE_STORE (tm), newpos, 0, fsf, 1, do_index, 2,
346 short_fn, 3, (guint) anonymity_level, 4, (guint) priority,
347 5, fip,
348 6, expiration_time_abs,
349 7, replication_level, -1);
350 if (dsel == GNUNET_YES)
351 {
352 path = gtk_tree_model_get_path (tm, newpos);
353 rr = gtk_tree_row_reference_new (tm, path);
354 gtk_tree_path_free (path);
355 }
356 else
357 {
358 rr = NULL;
359 }
360 if (TRUE == gtk_tree_model_iter_children (tm, &child, old))
361 {
362 do
363 {
364 path = gtk_tree_model_get_path (tm, &child);
365 rr2 = gtk_tree_row_reference_new (tm, path);
366 gtk_tree_path_free (path);
367 gtk_tree_store_insert_before (GTK_TREE_STORE (tm), &cnewpos, newpos,
368 NULL);
369 move_entry (ctx, tm, &child, &cnewpos, GNUNET_NO);
370 path = gtk_tree_row_reference_get_path (rr2);
371 gtk_tree_row_reference_free (rr2);
372 GNUNET_assert (TRUE == gtk_tree_model_get_iter (tm, &child, path));
373 gtk_tree_path_free (path);
374 }
375 while (TRUE == gtk_tree_model_iter_next (tm, &child));
376 }
377 g_free (short_fn);
378 g_free (fsf);
379 if (dsel == GNUNET_YES)
380 {
381 path = gtk_tree_row_reference_get_path (rr);
382 gtk_tree_row_reference_free (rr);
383 gtk_tree_view_expand_to_path (ctx->file_info_treeview, path);
384 GNUNET_assert (TRUE == gtk_tree_model_get_iter (tm, newpos, path));
385 gtk_tree_path_free (path);
386 gtk_tree_selection_select_iter (ctx->file_info_selection, newpos);
387 }
388 update_selectivity (ctx);
389}
390
391
392/**
393 * User has changed the "current" identifier for the content in
394 * the GtkTreeView. Update the model.
395 */
396void GNUNET_GTK_master_publish_dialog_pseudonym_updates_renderer_edited_cb
397 (GtkCellRendererText * renderer, gchar * cpath, gchar * new_text,
398 struct MainPublishingDialogContext *ctx)
399{
400 GtkTreeIter iter;
401
402 if (TRUE !=
403 gtk_tree_model_get_iter_from_string (ctx->pseudonym_treemodel, &iter, cpath))
404 {
405 GNUNET_break (0);
406 return;
407 }
408 gtk_tree_store_set (GTK_TREE_STORE (ctx->pseudonym_treemodel), &iter, 5, new_text, -1);
409 update_selectivity (ctx);
410}
411
412
413/**
414 * User has changed the "current" identifier for the content in
415 * the GtkTreeView. Update the model.
416 */
417void GNUNET_GTK_master_publish_dialog_pseudonym_identifier_renderer_edited_cb
418 (GtkCellRendererText * renderer, gchar * cpath, gchar * new_text,
419 struct MainPublishingDialogContext *ctx)
420{
421 GtkTreeIter iter;
422
423 if (TRUE !=
424 gtk_tree_model_get_iter_from_string (ctx->pseudonym_treemodel, &iter, cpath))
425 {
426 GNUNET_break (0);
427 return;
428 }
429 gtk_tree_store_set (GTK_TREE_STORE (ctx->pseudonym_treemodel), &iter, 2, new_text, -1);
430 update_selectivity (ctx);
431}
432
433
434void
435GNUNET_GTK_master_publish_dialog_right_button_clicked_cb (GtkWidget * dummy,
436 struct MainPublishingDialogContext *ctx)
437{
438 GtkTreeIter iter;
439 GtkTreeIter parent;
440 GtkTreeIter pred;
441 GtkTreeIter prev;
442 GtkTreeIter pos;
443
444 if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &iter))
445 {
446 GNUNET_break (0);
447 return;
448 }
449 if (TRUE == gtk_tree_model_iter_parent (ctx->file_info_treemodel, &parent, &iter))
450 {
451 GNUNET_assert (TRUE == gtk_tree_model_iter_children (ctx->file_info_treemodel, &pred, &parent));
452 }
453 else if (TRUE != gtk_tree_model_get_iter_first (ctx->file_info_treemodel, &pred))
454 {
455 GNUNET_break (0);
456 return;
457 }
458 /* iterate over 'next' of pred to find out who our predecessor is! */
459 memset (&prev, 0, sizeof (GtkTreeIter));
460 while (GNUNET_YES != gtk_tree_iter_equals (ctx->file_info_treemodel, &pred, &iter))
461 {
462 prev = pred;
463 GNUNET_assert (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, &pred));
464 }
465 gtk_tree_store_insert_before (GTK_TREE_STORE (ctx->file_info_treemodel), &pos, &prev, NULL);
466 if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &iter))
467 {
468 GNUNET_break (0);
469 return;
470 }
471 move_entry (ctx, ctx->file_info_treemodel, &iter, &pos, GNUNET_YES);
472 remove_old_entry (GTK_TREE_STORE (ctx->file_info_treemodel), &iter);
473}
474
475
476void
477GNUNET_GTK_master_publish_dialog_left_button_clicked_cb (GtkWidget * dummy,
478 struct MainPublishingDialogContext *ctx)
479{
480 GtkTreeIter iter;
481 GtkTreeIter parent;
482 GtkTreeIter pos;
483
484
485 if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &iter))
486 {
487 GNUNET_break (0);
488 return;
489 }
490 if (TRUE != gtk_tree_model_iter_parent (ctx->file_info_treemodel, &parent, &iter))
491 {
492 GNUNET_break (0);
493 return;
494 }
495 gtk_tree_store_insert_after (GTK_TREE_STORE (ctx->file_info_treemodel), &pos, NULL, &parent);
496 if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &iter))
497 {
498 GNUNET_break (0);
499 return;
500 }
501 move_entry (ctx, ctx->file_info_treemodel, &iter, &pos, GNUNET_YES);
502 remove_old_entry (GTK_TREE_STORE (ctx->file_info_treemodel), &iter);
503}
504
505
506void
507GNUNET_GTK_master_publish_dialog_up_button_clicked_cb (GtkWidget * dummy,
508 struct MainPublishingDialogContext *ctx)
509{
510 GtkTreeIter iter;
511 GtkTreeIter parent;
512 GtkTreeIter pred;
513 GtkTreeIter prev;
514 GtkTreeIter *pprev;
515 GtkTreeIter pos;
516
517 if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &iter))
518 {
519 GNUNET_break (0);
520 return;
521 }
522 if (TRUE == gtk_tree_model_iter_parent (ctx->file_info_treemodel, &parent, &iter))
523 {
524 GNUNET_assert (TRUE == gtk_tree_model_iter_children (ctx->file_info_treemodel, &pred, &parent));
525 pprev = &parent;
526 }
527 else if (TRUE == gtk_tree_model_get_iter_first (ctx->file_info_treemodel, &pred))
528 {
529 pprev = NULL;
530 }
531 else
532 {
533 GNUNET_break (0);
534 return;
535 }
536 /* iterate over 'next' of pred to find out who our predecessor is! */
537 while (GNUNET_YES != gtk_tree_iter_equals (ctx->file_info_treemodel, &pred, &iter))
538 {
539 prev = pred;
540 pprev = &prev;
541 GNUNET_assert (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, &pred));
542 }
543 gtk_tree_store_insert_before (GTK_TREE_STORE (ctx->file_info_treemodel), &pos, NULL, pprev);
544 if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &iter))
545 {
546 GNUNET_break (0);
547 return;
548 }
549 move_entry (ctx, ctx->file_info_treemodel, &iter, &pos, GNUNET_YES);
550 remove_old_entry (GTK_TREE_STORE (ctx->file_info_treemodel), &iter);
551}
552
553
554void
555GNUNET_GTK_master_publish_dialog_down_button_clicked_cb (GtkWidget * dummy,
556 struct MainPublishingDialogContext *ctx)
557{
558 GtkTreeIter iter;
559 GtkTreeIter next;
560 GtkTreeIter pos;
561
562 if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &iter))
563 {
564 GNUNET_break (0);
565 return;
566 }
567 if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &next))
568 {
569 GNUNET_break (0);
570 return;
571 }
572 GNUNET_assert (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, &next));
573 gtk_tree_store_insert_after (GTK_TREE_STORE (ctx->file_info_treemodel), &pos, NULL, &next);
574 if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &iter))
575 {
576 GNUNET_break (0);
577 return;
578 }
579 move_entry (ctx, ctx->file_info_treemodel, &iter, &pos, GNUNET_YES);
580 remove_old_entry (GTK_TREE_STORE (ctx->file_info_treemodel), &iter);
581}
582
583
584void
585GNUNET_GTK_master_publish_dialog_new_button_clicked_cb (GtkWidget * dummy,
586 struct MainPublishingDialogContext *ctx)
587{
588 GtkTreeIter iter;
589 GtkTreeIter pos;
590 struct GNUNET_FS_BlockOptions bo;
591
592 /* FIXME: consider opening a dialog to get
593 * anonymity, priority and expiration prior
594 * to calling this function (currently we
595 * use default values for those).
596 * Or getting these values from the configuration.
597 */
598 bo.anonymity_level = 1;
599 bo.content_priority = 1000;
600 bo.expiration_time =
601 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS);
602 bo.replication_level = 1;
603 if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &iter))
604 {
605 create_dir_at_iter (ctx, "unnamed/", &bo, NULL, &pos);
606 return;
607 }
608 create_dir_at_iter (ctx, "unnamed/", &bo, &iter, &pos);
609}
610
611
612static void
613insert_progress_dialog_text (struct AddDirClientContext *adcc,
614 const char *text)
615{
616 gtk_text_buffer_insert_at_cursor (adcc->progress_dialog_textbuffer,
617 text, -1);
618 gtk_text_view_place_cursor_onscreen (adcc->progress_dialog_textview);
619 gtk_adjustment_set_value (adcc->textview_vertial_adjustment,
620 gtk_adjustment_get_upper (adcc->textview_vertial_adjustment));
621}
622
623
624static void
625add_item (struct AddDirClientContext *adcc, GtkTreeStore *ts,
626 struct GNUNET_FS_ShareTreeItem *item,
627 GtkTreeIter *parent,
628 GtkTreeIter *sibling,
629 GtkTreeIter *item_iter)
630{
631 char *file_size_fancy;
632 struct GNUNET_FS_FileInformation *fi;
633 GtkTreeRowReference *row_reference;
634 GtkTreePath *path;
635 struct stat sbuf;
636
637 if (0 != stat (item->filename,
638 &sbuf))
639 {
640 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "stat", item->filename);
641 return;
642 }
643
644 gtk_tree_store_insert_after (ts, item_iter, parent, sibling);
645 path = gtk_tree_model_get_path (GTK_TREE_MODEL (ts), item_iter);
646 row_reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (ts), path);
647 gtk_tree_path_free (path);
648
649 if (item->is_directory)
650 {
651 if (NULL != item->meta)
652 GNUNET_CONTAINER_meta_data_delete (item->meta,
653 EXTRACTOR_METATYPE_MIMETYPE, NULL, 0);
654 else
655 item->meta = GNUNET_CONTAINER_meta_data_create ();
656 GNUNET_FS_meta_data_make_directory (item->meta);
657 if (NULL == item->ksk_uri)
658 item->ksk_uri = GNUNET_FS_uri_ksk_create (GNUNET_FS_DIRECTORY_MIME, NULL);
659 else
660 GNUNET_FS_uri_ksk_add_keyword (item->ksk_uri, GNUNET_FS_DIRECTORY_MIME,
661 GNUNET_NO);
662 fi = GNUNET_FS_file_information_create_empty_directory (
663 GNUNET_FS_GTK_get_fs_handle (), row_reference, item->ksk_uri,
664 item->meta, &adcc->directory_scan_bo, item->filename);
665 }
666 else
667 {
668 fi = GNUNET_FS_file_information_create_from_file (
669 GNUNET_FS_GTK_get_fs_handle (), row_reference, item->filename,
670 item->ksk_uri, item->meta, adcc->directory_scan_do_index,
671 &adcc->directory_scan_bo);
672 }
673 if (item->is_directory)
674 file_size_fancy = GNUNET_strdup (MARKER_DIR_FILE_SIZE);
675 else
676 file_size_fancy = GNUNET_STRINGS_byte_size_fancy (sbuf.st_size);
677
678 gtk_tree_store_set (ts, item_iter, 0, file_size_fancy,
679 1, (gboolean) adcc->directory_scan_do_index,
680 2, item->short_filename,
681 3, (guint) adcc->directory_scan_bo.anonymity_level,
682 4, (guint) adcc->directory_scan_bo.content_priority,
683 5, fi,
684 6, (guint64) adcc->directory_scan_bo.expiration_time.abs_value,
685 7, (guint) adcc->directory_scan_bo.replication_level, -1);
686 GNUNET_free (file_size_fancy);
687}
688
689
690/**
691 * Traverse the share tree and add it to the tree store
692 *
693 */
694static void
695add_share_items_to_treestore (struct AddDirClientContext *adcc,
696 struct GNUNET_FS_ShareTreeItem *toplevel,
697 GtkTreeIter *parent_iter)
698{
699 struct MainPublishingDialogContext *ctx = adcc->ctx;
700 GtkTreeStore *ts = GTK_TREE_STORE (ctx->file_info_treemodel);
701 GtkTreeIter *sibling_iter;
702 GtkTreeIter last_added;
703 struct GNUNET_FS_ShareTreeItem *item;
704
705 sibling_iter = NULL;
706 for (item = toplevel; item != NULL; item = item->next)
707 {
708 add_item (adcc, ts, item, parent_iter, sibling_iter, &last_added);
709 sibling_iter = &last_added;
710 if (item->is_directory)
711 add_share_items_to_treestore (adcc,
712 item->children_head,
713 sibling_iter);
714 }
715}
716
717
718static void
719close_scan (struct AddDirClientContext *adcc)
720{
721 gtk_widget_destroy (adcc->progress_dialog);
722 g_object_unref (G_OBJECT (adcc->progress_dialog_builder));
723 GNUNET_CONTAINER_DLL_remove (adcc->ctx->adddir_head,
724 adcc->ctx->adddir_tail,
725 adcc);
726 update_selectivity (adcc->ctx);
727 GNUNET_free (adcc);
728}
729
730
731static void
732directory_scan_cb (void *cls,
733 const char *filename, int is_directory,
734 enum GNUNET_FS_DirScannerProgressUpdateReason reason)
735{
736 static struct GNUNET_TIME_Absolute last_pulse;
737 struct AddDirClientContext *adcc = cls;
738 char *s;
739 gdouble fraction;
740
741 switch (reason)
742 {
743 case GNUNET_FS_DIRSCANNER_FILE_START:
744 GNUNET_assert (filename != NULL);
745 if (GNUNET_TIME_absolute_get_duration (last_pulse).rel_value > 100)
746 {
747 gtk_progress_bar_pulse (adcc->progress_dialog_bar);
748 last_pulse = GNUNET_TIME_absolute_get ();
749 }
750#if VERBOSE_PROGRESS
751 if (is_directory)
752 {
753 GNUNET_asprintf (&s, _("Scanning directory `%s'.\n"), filename);
754 insert_progress_dialog_text (adcc, s);
755 GNUNET_free (s);
756 }
757 else
758 adcc->total++;
759#else
760 if (! is_directory)
761 adcc->total++;
762#endif
763 break;
764 case GNUNET_FS_DIRSCANNER_FILE_IGNORED:
765 GNUNET_assert (filename != NULL);
766 GNUNET_asprintf (&s,
767 _("Failed to scan `%s' (access error). Skipping.\n"),
768 filename);
769#if ! VERBOSE_PROGRESS
770 gtk_widget_show (GTK_WIDGET (gtk_builder_get_object (adcc->progress_dialog_builder,
771 "GNUNET_FS_GTK_progress_dialog_scrolled_window")));
772#endif
773 insert_progress_dialog_text (adcc, s);
774 GNUNET_free (s);
775 break;
776 case GNUNET_FS_DIRSCANNER_ALL_COUNTED:
777 fraction = (adcc->total == 0) ? 1.0 : (1.0 * adcc->done) / adcc->total;
778 GNUNET_asprintf (&s, "%u/%u (%3f%%)",
779 adcc->done,
780 adcc->total,
781 100.0 * fraction);
782 gtk_progress_bar_set_text (adcc->progress_dialog_bar,
783 s);
784 GNUNET_free (s);
785 gtk_progress_bar_set_fraction (adcc->progress_dialog_bar,
786 fraction);
787 break;
788 case GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED:
789#if VERBOSE_PROGRESS
790 GNUNET_asprintf (&s, _("Processed file `%s'.\n"), filename);
791 insert_progress_dialog_text (adcc, s);
792 GNUNET_free (s);
793#endif
794 adcc->done++;
795 GNUNET_assert (adcc->done <= adcc->total);
796 fraction = (adcc->total == 0) ? 1.0 : (1.0 * adcc->done) / adcc->total;
797 GNUNET_asprintf (&s, "%u/%u (%3f%%)",
798 adcc->done,
799 adcc->total,
800 100.0 * fraction);
801 gtk_progress_bar_set_text (adcc->progress_dialog_bar,
802 s);
803 GNUNET_free (s);
804 gtk_progress_bar_set_fraction (adcc->progress_dialog_bar,
805 fraction);
806 break;
807 case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR:
808 insert_progress_dialog_text (adcc, _("Operation failed (press cancel)\n"));
809 GNUNET_FS_directory_scan_abort (adcc->ds);
810 adcc->ds = NULL;
811 break;
812 case GNUNET_FS_DIRSCANNER_FINISHED:
813 insert_progress_dialog_text (adcc, _("Scanner has finished.\n"));
814 adcc->directory_scan_result = GNUNET_FS_directory_scan_get_result (adcc->ds);
815 adcc->ds = NULL;
816 GNUNET_FS_share_tree_trim (adcc->directory_scan_result);
817 add_share_items_to_treestore (adcc,
818 adcc->directory_scan_result,
819 NULL);
820 GNUNET_FS_share_tree_free (adcc->directory_scan_result);
821 adcc->directory_scan_result = NULL;
822 update_selectivity (adcc->ctx);
823 close_scan (adcc);
824 break;
825 default:
826 GNUNET_break (0);
827 break;
828 }
829}
830
831
832static void
833scan_file_or_directory (struct MainPublishingDialogContext *ctx,
834 gchar *filename,
835 struct GNUNET_FS_BlockOptions *bo,
836 int do_index)
837{
838 struct AddDirClientContext *adcc;
839 GtkTextIter iter;
840
841 adcc = GNUNET_malloc (sizeof (struct AddDirClientContext));
842 adcc->ctx = ctx;
843 GNUNET_CONTAINER_DLL_insert_tail (ctx->adddir_head, ctx->adddir_tail, adcc);
844 adcc->ds = GNUNET_FS_directory_scan_start (filename,
845 GNUNET_NO, NULL, &directory_scan_cb, adcc);
846 adcc->directory_scan_bo = *bo;
847 adcc->directory_scan_do_index = do_index;
848
849 adcc->progress_dialog_builder = GNUNET_GTK_get_new_builder (
850 "gnunet_fs_gtk_progress_dialog.glade", adcc);
851 adcc->progress_dialog = GTK_WIDGET (gtk_builder_get_object (
852 adcc->progress_dialog_builder,
853 "GNUNET_FS_GTK_progress_dialog"));
854 adcc->progress_dialog_bar = GTK_PROGRESS_BAR (gtk_builder_get_object (
855 adcc->progress_dialog_builder,
856 "GNUNET_FS_GTK_progress_dialog_progressbar"));
857 adcc->progress_dialog_cancel = GTK_BUTTON (gtk_builder_get_object (
858 adcc->progress_dialog_builder,
859 "GNUNET_FS_GTK_progress_dialog_cancel_button"));
860 adcc->progress_dialog_textview = GTK_TEXT_VIEW (
861 gtk_builder_get_object (adcc->progress_dialog_builder,
862 "GNUNET_FS_GTK_progress_dialog_textview"));
863 adcc->textview_vertial_adjustment = GTK_ADJUSTMENT (
864 gtk_builder_get_object (adcc->progress_dialog_builder,
865 "GNUNET_FS_GTK_progress_dialog_textview_vertical_adjustment"));
866 adcc->progress_dialog_textbuffer = GTK_TEXT_BUFFER (
867 gtk_builder_get_object (adcc->progress_dialog_builder,
868 "GNUNET_FS_GTK_progress_dialog_textbuffer"));
869 gtk_text_buffer_get_end_iter (adcc->progress_dialog_textbuffer,
870 &iter);
871 adcc->progress_dialog_textmark = gtk_text_buffer_create_mark (
872 adcc->progress_dialog_textbuffer, "scroll",
873 &iter, FALSE);
874#if VERBOSE_PROGRESS
875 gtk_widget_show (GTK_WIDGET (gtk_builder_get_object (adcc->progress_dialog_builder,
876 "GNUNET_FS_GTK_progress_dialog_scrolled_window")));
877#endif
878
879 gtk_window_set_transient_for (GTK_WINDOW (adcc->progress_dialog), adcc->ctx->master_pubdialog);
880 gtk_window_set_title (GTK_WINDOW (adcc->progress_dialog), filename);
881 gtk_window_present (GTK_WINDOW (adcc->progress_dialog));
882
883 update_selectivity (ctx);
884}
885
886
887static void
888publish_directory_dialog_response_cb (GtkDialog * dialog,
889 gint response_id,
890 struct MainPublishingDialogContext *ctx)
891{
892 char *filename;
893 int do_index;
894 GtkSpinButton *sb;
895 struct GNUNET_FS_BlockOptions bo;
896 GtkWidget *ad;
897
898 if (g_signal_handler_is_connected (G_OBJECT (dialog), ctx->open_directory_handler_id))
899 g_signal_handler_disconnect (G_OBJECT (dialog), ctx->open_directory_handler_id);
900 ctx->open_directory_handler_id = 0;
901
902 ad = GTK_WIDGET (gtk_builder_get_object
903 (ctx->open_directory_builder, "GNUNET_GTK_publish_directory_dialog"));
904 if (response_id == -5)
905 {
906 filename = GNUNET_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER (ad));
907 sb = GTK_SPIN_BUTTON (gtk_builder_get_object
908 (ctx->open_directory_builder,
909 "GNUNET_GTK_publish_directory_dialog_expiration_year_spin_button"));
910 if (!GNUNET_GTK_get_selected_anonymity_level
911 (ctx->open_directory_builder, "GNUNET_GTK_publish_directory_dialog_anonymity_combobox",
912 &bo.anonymity_level))
913 bo.anonymity_level = 1;
914 bo.content_priority =
915 gtk_spin_button_get_value (GTK_SPIN_BUTTON
916 (gtk_builder_get_object
917 (ctx->open_directory_builder,
918 "GNUNET_GTK_publish_directory_dialog_priority_spin_button")));
919 bo.replication_level =
920 gtk_spin_button_get_value (GTK_SPIN_BUTTON
921 (gtk_builder_get_object
922 (ctx->open_directory_builder,
923 "GNUNET_GTK_publish_directory_dialog_replication_spin_button")));
924 bo.expiration_time = GNUNET_FS_GTK_get_expiration_time (sb);
925 do_index =
926 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
927 (gtk_builder_get_object
928 (ctx->open_directory_builder,
929 "GNUNET_GTK_publish_directory_dialog_do_index_checkbutton")));
930
931 scan_file_or_directory (ctx, filename, &bo, do_index);
932 g_free (filename);
933 }
934 gtk_widget_destroy (ad);
935 g_object_unref (G_OBJECT (ctx->open_directory_builder));
936}
937
938
939static void
940publish_file_dialog_response_cb (GtkDialog * dialog,
941 gint response_id,
942 struct MainPublishingDialogContext *ctx)
943{
944 char *filename;
945 struct GNUNET_FS_BlockOptions bo;
946 int do_index;
947 GtkSpinButton *sb;
948 GtkWidget *ad;
949
950 if (g_signal_handler_is_connected (G_OBJECT (dialog), ctx->open_file_handler_id))
951 g_signal_handler_disconnect (G_OBJECT (dialog), ctx->open_file_handler_id);
952 ctx->open_file_handler_id = 0;
953
954 ad = GTK_WIDGET (gtk_builder_get_object
955 (ctx->open_file_builder, "GNUNET_GTK_publish_file_dialog"));
956
957 if (response_id == -5)
958 {
959 /* OK */
960 sb = GTK_SPIN_BUTTON (gtk_builder_get_object
961 (ctx->open_file_builder,
962 "GNUNET_GTK_publish_file_dialog_expiration_year_spin_button"));
963
964 if (!GNUNET_GTK_get_selected_anonymity_level
965 (ctx->open_file_builder, "GNUNET_GTK_publish_file_dialog_anonymity_combobox",
966 &bo.anonymity_level))
967 bo.anonymity_level = 1;
968 bo.content_priority =
969 gtk_spin_button_get_value (GTK_SPIN_BUTTON
970 (gtk_builder_get_object
971 (ctx->open_file_builder,
972 "GNUNET_GTK_publish_file_dialog_priority_spin_button")));
973 bo.expiration_time = GNUNET_FS_GTK_get_expiration_time (sb);
974 bo.replication_level =
975 gtk_spin_button_get_value (GTK_SPIN_BUTTON
976 (gtk_builder_get_object
977 (ctx->open_file_builder,
978 "GNUNET_GTK_publish_file_dialog_replication_spin_button")));
979 do_index =
980 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
981 (gtk_builder_get_object
982 (ctx->open_file_builder,
983 "GNUNET_GTK_publish_file_dialog_do_index_checkbutton")));
984
985 filename = GNUNET_GTK_filechooser_get_filename_utf8 (GTK_FILE_CHOOSER (ad));
986
987 scan_file_or_directory (ctx, filename, &bo, do_index);
988
989 g_free (filename);
990 }
991 else
992 {
993 /* Cancel/Escape/close/etc */
994 }
995 gtk_widget_destroy (ad);
996}
997
998
999void
1000GNUNET_GTK_master_publish_dialog_add_button_clicked_cb (GtkWidget * dummy,
1001 struct MainPublishingDialogContext *ctx)
1002{
1003 GtkWidget *ad;
1004
1005 GtkComboBox *combo;
1006 GtkTreeModel *anon_treemodel;
1007
1008 ctx->open_file_builder = GNUNET_GTK_get_new_builder ("gnunet_fs_gtk_publish_file_dialog.glade", ctx);
1009 GNUNET_FS_GTK_setup_expiration_year_adjustment (ctx->open_file_builder);
1010 ad = GTK_WIDGET (gtk_builder_get_object
1011 (ctx->open_file_builder, "GNUNET_GTK_publish_file_dialog"));
1012
1013 /* FIXME: Use some kind of adjustable defaults instead of 1000, 0 and TRUE */
1014 gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (
1015 ctx->open_file_builder,
1016 "GNUNET_GTK_publish_file_dialog_priority_spin_button")), 1000);
1017 gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (
1018 ctx->open_file_builder,
1019 "GNUNET_GTK_publish_file_dialog_replication_spin_button")), 0);
1020 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object (
1021 ctx->open_file_builder,
1022 "GNUNET_GTK_publish_file_dialog_do_index_checkbutton")), TRUE);
1023
1024 ctx->open_file_handler_id = g_signal_connect (G_OBJECT (ad), "response", G_CALLBACK (publish_file_dialog_response_cb), ctx);
1025
1026 anon_treemodel = GTK_TREE_MODEL (gtk_builder_get_object (ctx->main_window_builder,
1027 "main_window_search_anonymity_liststore"));
1028 combo = GTK_COMBO_BOX (gtk_builder_get_object (ctx->open_file_builder,
1029 "GNUNET_GTK_publish_file_dialog_anonymity_combobox"));
1030 gtk_combo_box_set_model (combo, anon_treemodel);
1031
1032 gtk_window_set_transient_for (GTK_WINDOW (ad), ctx->master_pubdialog);
1033
1034 gtk_window_present (GTK_WINDOW (ad));
1035}
1036
1037
1038struct EditPublishContext
1039{
1040 struct GNUNET_FS_FileInformation *fip;
1041
1042 GtkTreeModel *tm;
1043
1044 GtkTreeIter iter;
1045};
1046
1047
1048/**
1049 * Update tree view based on the information from the
1050 * GNUNET_FS_FileInformation publish-structure.
1051 *
1052 * @param cls closure, a 'struct EditPublishContext *'
1053 * @param fi the entry in the publish-structure
1054 * @param length length of the file or directory
1055 * @param meta metadata for the file or directory (can be modified)
1056 * @param uri pointer to the keywords that will be used for this entry (can be modified)
1057 * @param bo block options (can be modified)
1058 * @param do_index should we index (can be modified)
1059 * @param client_info pointer to client context set upon creation (can be modified)
1060 * @return GNUNET_OK to continue, GNUNET_NO to remove
1061 * this entry from the directory, GNUNET_SYSERR
1062 * to abort the iteration
1063 */
1064static int
1065update_treeview_after_edit (void *cls, struct GNUNET_FS_FileInformation *fi,
1066 uint64_t length, struct GNUNET_CONTAINER_MetaData *meta,
1067 struct GNUNET_FS_Uri **uri,
1068 struct GNUNET_FS_BlockOptions *bo, int *do_index,
1069 void **client_info)
1070{
1071 struct EditPublishContext *epc = cls;
1072
1073 gtk_tree_store_set (GTK_TREE_STORE (epc->tm), &epc->iter,
1074 1, *do_index,
1075 3, (guint) bo->anonymity_level,
1076 4, (guint) bo->content_priority,
1077 6, (guint64) bo->expiration_time.abs_value,
1078 7, (guint) bo->replication_level,
1079 -1);
1080 return GNUNET_SYSERR;
1081}
1082
1083
1084/**
1085 * Function called when the edit publish dialog has been closed.
1086 *
1087 * @param cls closure
1088 * @param ret GTK_RESPONSE_OK if the dialog was closed with "OK"
1089 * @param root unused (namespace root name)
1090 */
1091static void
1092master_publish_edit_publish_dialog_cb (gpointer cls,
1093 gint ret,
1094 const char *root)
1095{
1096 struct EditPublishContext *cbargs = cls;
1097
1098 if (ret == GTK_RESPONSE_OK)
1099 GNUNET_FS_file_information_inspect (cbargs->fip, &update_treeview_after_edit, cbargs);
1100 GNUNET_free (cbargs);
1101}
1102
1103
1104void
1105GNUNET_GTK_master_publish_dialog_edit_button_clicked_cb (GtkWidget * dummy,
1106 struct MainPublishingDialogContext *ctx)
1107{
1108 struct EditPublishContext *cbargs;
1109 GtkListStore *anon_liststore;
1110
1111 anon_liststore = GTK_LIST_STORE (gtk_builder_get_object (ctx->main_window_builder,
1112 "main_window_search_anonymity_liststore"));
1113 cbargs = GNUNET_malloc (sizeof (struct EditPublishContext));
1114 cbargs->tm = ctx->file_info_treemodel;
1115 if (! gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &cbargs->iter))
1116 {
1117 GNUNET_break (0);
1118 GNUNET_free (cbargs);
1119 return;
1120 }
1121 gtk_tree_model_get (ctx->file_info_treemodel, &cbargs->iter,
1122 5, &cbargs->fip,
1123 -1);
1124 /* FIXME: can we just give our anon_liststore out like this? What about
1125 (unintended) sharing of state? */
1126 GNUNET_FS_GTK_edit_publish_dialog (ctx->master_pubdialog,
1127 cbargs->fip,
1128 GNUNET_YES,
1129 anon_liststore,
1130 &master_publish_edit_publish_dialog_cb,
1131 cbargs);
1132}
1133
1134
1135/**
1136 * Free row reference stored in the file information's
1137 * client-info pointer.
1138 */
1139static int
1140free_fi_row_reference (void *cls, struct GNUNET_FS_FileInformation *fi,
1141 uint64_t length, struct GNUNET_CONTAINER_MetaData *meta,
1142 struct GNUNET_FS_Uri **uri,
1143 struct GNUNET_FS_BlockOptions *bo, int *do_index,
1144 void **client_info)
1145{
1146 GtkTreeRowReference *row = *client_info;
1147
1148 if (row == NULL)
1149 {
1150 GNUNET_break (0);
1151 return GNUNET_OK;
1152 }
1153 gtk_tree_row_reference_free (row);
1154 return GNUNET_OK;
1155}
1156
1157
1158void
1159GNUNET_GTK_master_publish_dialog_delete_button_clicked_cb (GtkWidget * dummy,
1160 struct MainPublishingDialogContext *ctx)
1161{
1162 GtkTreeIter iter;
1163 struct GNUNET_FS_FileInformation *fip;
1164
1165 if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &iter))
1166 {
1167 GNUNET_break (0);
1168 return;
1169 }
1170 gtk_tree_model_get (ctx->file_info_treemodel, &iter, 5, &fip, -1);
1171 GNUNET_FS_file_information_destroy (fip, &free_fi_row_reference, NULL);
1172 gtk_tree_store_remove (GTK_TREE_STORE (ctx->file_info_treemodel), &iter);
1173 update_selectivity (ctx);
1174}
1175
1176
1177void
1178GNUNET_FS_GTK_progress_dialog_cancel_button_clicked_cb (GtkButton *button,
1179 void *cls)
1180{
1181 struct AddDirClientContext *adcc = cls;
1182
1183 if (adcc->ds != NULL)
1184 {
1185 /* Still scanning - signal the scanner to finish */
1186 GNUNET_FS_directory_scan_abort (adcc->ds);
1187 adcc->ds = NULL;
1188 }
1189 close_scan (adcc);
1190}
1191
1192
1193gboolean
1194GNUNET_FS_GTK_progress_dialog_delete_event_cb (GtkWidget *widget,
1195 GdkEvent * event,
1196 void *cls)
1197{
1198 /* Don't allow GTK to kill the window, until the scan is finished */
1199 return GNUNET_NO;
1200}
1201
1202
1203void
1204GNUNET_GTK_master_publish_dialog_open_button_clicked_cb (GtkWidget * dummy,
1205 struct MainPublishingDialogContext *ctx)
1206{
1207 GtkWidget *ad;
1208
1209 GtkComboBox *combo;
1210 GtkTreeModel *anon_treemodel;
1211
1212 ctx->open_directory_builder = GNUNET_GTK_get_new_builder ("gnunet_fs_gtk_publish_directory_dialog.glade", ctx);
1213 GNUNET_FS_GTK_setup_expiration_year_adjustment (ctx->open_directory_builder);
1214
1215 /* FIXME: Use some kind of adjustable defaults instead of 1000, 0 and TRUE */
1216 gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (
1217 ctx->open_directory_builder,
1218 "GNUNET_GTK_publish_directory_dialog_priority_spin_button")), 1000);
1219 gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (
1220 ctx->open_directory_builder,
1221 "GNUNET_GTK_publish_directory_dialog_replication_spin_button")), 0);
1222 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object (
1223 ctx->open_directory_builder,
1224 "GNUNET_GTK_publish_directory_dialog_do_index_checkbutton")), TRUE);
1225
1226 ad = GTK_WIDGET (gtk_builder_get_object
1227 (ctx->open_directory_builder, "GNUNET_GTK_publish_directory_dialog"));
1228
1229 ctx->open_directory_handler_id = g_signal_connect (G_OBJECT (ad), "response", G_CALLBACK (publish_directory_dialog_response_cb), ctx);
1230
1231 anon_treemodel = GTK_TREE_MODEL (gtk_builder_get_object (ctx->main_window_builder,
1232 "main_window_search_anonymity_liststore"));
1233 combo = GTK_COMBO_BOX (gtk_builder_get_object (ctx->open_directory_builder,
1234 "GNUNET_GTK_publish_directory_dialog_anonymity_combobox"));
1235 gtk_combo_box_set_model (combo, anon_treemodel);
1236
1237 gtk_window_set_transient_for (GTK_WINDOW (ad), ctx->master_pubdialog);
1238
1239 gtk_window_present (GTK_WINDOW (ad));
1240}
1241
1242
1243/**
1244 * Get the file information struct corresponding to the
1245 * given iter in the publish dialog tree model. Recursively
1246 * builds the file information struct from the subtree.
1247 *
1248 * @param tm model to grab fi from
1249 * @param iter position to grab fi from
1250 * @return file information from the given position (never NULL)
1251 */
1252static struct GNUNET_FS_FileInformation *
1253get_file_information (GtkTreeModel * tm, GtkTreeIter * iter)
1254{
1255 struct GNUNET_FS_FileInformation *fi;
1256 struct GNUNET_FS_FileInformation *fic;
1257 GtkTreeIter child;
1258
1259 gtk_tree_model_get (tm, iter, 5, &fi, -1);
1260 gtk_tree_store_set (GTK_TREE_STORE (tm), iter, 5, NULL, -1);
1261 GNUNET_assert (fi != NULL);
1262 if (gtk_tree_model_iter_children (tm, &child, iter))
1263 {
1264 GNUNET_break (GNUNET_YES == GNUNET_FS_file_information_is_directory (fi));
1265 do
1266 {
1267 fic = get_file_information (tm, &child);
1268 GNUNET_break (GNUNET_OK == GNUNET_FS_file_information_add (fi, fic));
1269 }
1270 while (gtk_tree_model_iter_next (tm, &child));
1271 }
1272 return fi;
1273}
1274
1275
1276/**
1277 * Closure for 'add_updateable_to_ts'.
1278 */
1279struct UpdateableContext
1280{
1281 /**
1282 * Parent of current insertion.
1283 */
1284 GtkTreeIter *parent;
1285
1286 /**
1287 * Tree store we are modifying.
1288 */
1289 GtkTreeStore *ts;
1290
1291 /**
1292 * Name of the namespace.
1293 */
1294 const char *namespace_name;
1295
1296 /**
1297 * Handle to the namespace.
1298 */
1299 struct GNUNET_FS_Namespace *ns;
1300
1301 /**
1302 * Hash codes of identifiers already added to tree store.
1303 */
1304 struct GNUNET_CONTAINER_MultiHashMap *seen;
1305
1306 /**
1307 * Did the iterator get called?
1308 */
1309 int update_called;
1310};
1311
1312
1313/**
1314 * Add updateable entries to the tree view.
1315 *
1316 * @param cls closure
1317 * @param last_id ID to add
1318 * @param last_uri associated URI
1319 * @param last_meta associate meta data
1320 * @param next_id ID for future updates
1321 */
1322static void
1323add_updateable_to_ts (void *cls, const char *last_id,
1324 const struct GNUNET_FS_Uri *last_uri,
1325 const struct GNUNET_CONTAINER_MetaData *last_meta,
1326 const char *next_id)
1327{
1328 struct UpdateableContext *uc = cls;
1329 struct UpdateableContext sc;
1330 GtkTreeIter iter;
1331 GtkTreeIter titer;
1332 char *desc;
1333 GNUNET_HashCode hc;
1334
1335 uc->update_called = GNUNET_YES;
1336 GNUNET_CRYPTO_hash (last_id, strlen (last_id), &hc);
1337 if (NULL != GNUNET_CONTAINER_multihashmap_get (uc->seen, &hc))
1338 return;
1339 GNUNET_CONTAINER_multihashmap_put (uc->seen, &hc, "dummy",
1340 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1341 /* FIXME: what if this put fails? Not convinced it cannot... */
1342 desc =
1343 GNUNET_CONTAINER_meta_data_get_first_by_types (last_meta,
1344 EXTRACTOR_METATYPE_DESCRIPTION,
1345 EXTRACTOR_METATYPE_TITLE,
1346 EXTRACTOR_METATYPE_BOOK_TITLE,
1347 EXTRACTOR_METATYPE_FILENAME,
1348 EXTRACTOR_METATYPE_SUMMARY,
1349 EXTRACTOR_METATYPE_ALBUM,
1350 EXTRACTOR_METATYPE_COMMENT,
1351 EXTRACTOR_METATYPE_SUBJECT,
1352 -1);
1353 if (desc == NULL)
1354 desc = GNUNET_strdup (_("no description supplied"));
1355 else
1356 {
1357 char *utf8_desc = NULL;
1358
1359 utf8_desc =
1360 GNUNET_FS_GTK_dubious_meta_to_utf8 (EXTRACTOR_METAFORMAT_UTF8, desc,
1361 strlen (desc) + 1);
1362 GNUNET_free (desc);
1363 if (utf8_desc != NULL)
1364 desc = utf8_desc;
1365 else
1366 desc = NULL;
1367 }
1368 gtk_tree_store_insert_with_values (uc->ts, &iter, uc->parent, G_MAXINT, 0,
1369 uc->namespace_name, 1, uc->ns, 2, last_id,
1370 3, GNUNET_FS_uri_dup (last_uri), 4,
1371 GNUNET_CONTAINER_meta_data_duplicate
1372 (last_meta), 5, "", 6, desc, 7,
1373 TRUE /* update editable (always) */ ,
1374 8, FALSE
1375 /* current not editable (only for top-level) */
1376 , -1);
1377 GNUNET_free_non_null (desc);
1378 sc.parent = &iter;
1379 sc.ts = uc->ts;
1380 sc.namespace_name = uc->namespace_name;
1381 sc.ns = uc->ns;
1382 sc.seen = uc->seen;
1383 sc.update_called = GNUNET_NO;
1384 GNUNET_FS_namespace_list_updateable (uc->ns, next_id, &add_updateable_to_ts,
1385 &sc);
1386 if ((sc.update_called == GNUNET_NO) && (next_id != NULL) &&
1387 (strlen (next_id) > 0))
1388 {
1389 /* add leaf */
1390 gtk_tree_store_insert_with_values (uc->ts, &titer, &iter, G_MAXINT, 0,
1391 uc->namespace_name, 1, uc->ns, 2,
1392 next_id, 3, NULL, 4, NULL, 5, "", 6, "",
1393 7, TRUE /* update editable (always) */ ,
1394 8, FALSE
1395 /* current not editable (only for top-level) */
1396 , -1);
1397 }
1398}
1399
1400
1401/**
1402 * Add all updateable entries of the current namespace to the
1403 * tree store.
1404 *
1405 * @param cls the 'GtkTreeStore' to update
1406 * @param name name of the namespace to add
1407 * @param id identity of the namespace to add
1408 */
1409static void
1410add_namespace_to_ts (void *cls, const char *name, const GNUNET_HashCode * id)
1411{
1412 GtkTreeStore *ts = cls;
1413 struct UpdateableContext uc;
1414 GtkTreeIter iter;
1415
1416 uc.parent = &iter;
1417 uc.namespace_name = name;
1418 uc.ts = ts;
1419 uc.ns = GNUNET_FS_namespace_create (GNUNET_FS_GTK_get_fs_handle (), name);
1420 uc.update_called = GNUNET_NO;
1421 gtk_tree_store_insert_with_values (ts, &iter, NULL, G_MAXINT, 0, name, 1,
1422 uc.ns, 2, NULL /* last-id */ ,
1423 3, NULL /* last-uri (as string!) */ ,
1424 4, NULL /* meta */ ,
1425 5, NULL /* next-ID */ ,
1426 6, NULL /* last-description */ ,
1427 7, TRUE /* update editable */ ,
1428 8, TRUE /* current editable */ ,
1429 -1);
1430 uc.seen = GNUNET_CONTAINER_multihashmap_create (128);
1431 GNUNET_FS_namespace_list_updateable (uc.ns, NULL, &add_updateable_to_ts, &uc);
1432 GNUNET_CONTAINER_multihashmap_destroy (uc.seen);
1433}
1434
1435
1436static void
1437free_pseudonym_tree_store (GtkTreeModel * tm, GtkTreeIter * iter)
1438{
1439 struct GNUNET_CONTAINER_MetaData *meta;
1440 struct GNUNET_FS_Namespace *ns;
1441 GtkTreeIter child;
1442
1443 gtk_tree_model_get (tm, iter, 1, &ns, 4, &meta, -1);
1444 if (meta != NULL)
1445 GNUNET_CONTAINER_meta_data_destroy (meta);
1446 if (ns != NULL)
1447 {
1448 // FIXME: delete ns?
1449 // GNUNET_FS_namespace_delete (nso, GNUNET_NO);
1450 }
1451 if (TRUE == gtk_tree_model_iter_children (tm, &child, iter))
1452 {
1453 do
1454 {
1455 free_pseudonym_tree_store (tm, &child);
1456 }
1457 while (TRUE == gtk_tree_model_iter_next (tm, &child));
1458 }
1459}
1460
1461
1462static void
1463free_file_information_tree_store (GtkTreeModel * tm, GtkTreeIter * iter)
1464{
1465 GtkTreeIter child;
1466 struct GNUNET_FS_FileInformation *fip;
1467
1468 gtk_tree_model_get (tm, iter, 5, &fip, -1);
1469 if (fip != NULL)
1470 GNUNET_FS_file_information_destroy (fip, NULL, NULL);
1471 if (TRUE == gtk_tree_model_iter_children (tm, &child, iter))
1472 {
1473 do
1474 {
1475 free_file_information_tree_store (tm, &child);
1476 }
1477 while (TRUE == gtk_tree_model_iter_next (tm, &child));
1478 }
1479}
1480
1481static int
1482hide_master_publish_dialog (struct MainPublishingDialogContext *ctx, gint ret)
1483{
1484 GtkTreeIter iter;
1485 gpointer namespace;
1486 gchar *namespace_id;
1487 gchar *namespace_uid;
1488 struct GNUNET_FS_FileInformation *fi;
1489
1490 /* Don't close until all scanners are finished */
1491 if (ctx->adddir_head != NULL)
1492 return GNUNET_NO;
1493
1494 if (ret == GTK_RESPONSE_OK)
1495 {
1496 if (TRUE == gtk_tree_selection_get_selected (ctx->pseudonym_selection, NULL, &iter))
1497 {
1498 gtk_tree_model_get (ctx->pseudonym_treemodel, &iter, 1, &namespace, 2, &namespace_id, 5,
1499 &namespace_uid, -1);
1500 }
1501 else
1502 {
1503 namespace = NULL;
1504 namespace_id = NULL;
1505 namespace_uid = NULL;
1506 }
1507 if (gtk_tree_model_get_iter_first (ctx->file_info_treemodel, &iter))
1508 do
1509 {
1510 fi = get_file_information (ctx->file_info_treemodel, &iter);
1511 /* FIXME: should we convert namespace id and uid from UTF8? */
1512 GNUNET_FS_publish_start (GNUNET_FS_GTK_get_fs_handle (), fi, namespace,
1513 namespace_id, namespace_uid,
1514 GNUNET_FS_PUBLISH_OPTION_NONE);
1515 }
1516 while (gtk_tree_model_iter_next (ctx->file_info_treemodel, &iter));
1517 g_free (namespace_id);
1518 g_free (namespace_uid);
1519 }
1520
1521 /* free state from 'ptm' */
1522 if (TRUE == gtk_tree_model_get_iter_first (ctx->pseudonym_treemodel, &iter))
1523 do
1524 {
1525 free_pseudonym_tree_store (ctx->pseudonym_treemodel, &iter);
1526 }
1527 while (TRUE == gtk_tree_model_iter_next (ctx->pseudonym_treemodel, &iter));
1528 gtk_tree_store_clear (GTK_TREE_STORE (ctx->pseudonym_treemodel));
1529
1530 /* free state from 'tm' */
1531 if (TRUE == gtk_tree_model_get_iter_first (ctx->file_info_treemodel, &iter))
1532 do
1533 {
1534 free_file_information_tree_store (ctx->file_info_treemodel, &iter);
1535 }
1536 while (TRUE == gtk_tree_model_iter_next (ctx->file_info_treemodel, &iter));
1537 gtk_tree_store_clear (GTK_TREE_STORE (ctx->file_info_treemodel));
1538 gtk_widget_destroy (GTK_WIDGET (ctx->master_pubdialog));
1539 g_object_unref (G_OBJECT (ctx->builder));
1540 GNUNET_free (ctx);
1541 return GNUNET_YES;
1542}
1543
1544
1545void
1546GNUNET_GTK_master_publish_dialog_execute_button_clicked_cb (GtkButton * button,
1547 struct MainPublishingDialogContext *ctx)
1548{
1549 hide_master_publish_dialog (ctx, GTK_RESPONSE_OK);
1550}
1551
1552
1553void
1554GNUNET_GTK_master_publish_dialog_cancel_button_clicked_cb (GtkButton * button,
1555 struct MainPublishingDialogContext *ctx)
1556{
1557 hide_master_publish_dialog (ctx, GTK_RESPONSE_CANCEL);
1558}
1559
1560
1561gboolean
1562GNUNET_GTK_master_publish_dialog_delete_event_cb (GtkWidget * widget,
1563 GdkEvent * event,
1564 struct MainPublishingDialogContext *ctx)
1565{
1566 if (GNUNET_NO == hide_master_publish_dialog (ctx, GTK_RESPONSE_CANCEL))
1567 return TRUE;
1568 return FALSE;
1569}
1570
1571
1572/**
1573 */
1574void
1575GNUNET_GTK_main_menu_file_publish_activate_cb (GtkWidget * dummy, gpointer user_data)
1576{
1577 struct MainPublishingDialogContext *ctx;
1578
1579 ctx = GNUNET_malloc (sizeof (struct MainPublishingDialogContext));
1580 ctx->builder = GNUNET_GTK_get_new_builder ("gnunet_fs_gtk_publish_dialog.glade", ctx);
1581
1582 if (ctx->builder == NULL)
1583 {
1584 GNUNET_free (ctx);
1585 return;
1586 }
1587
1588 init_ctx (ctx);
1589 ctx->main_window_builder = GTK_BUILDER (user_data);
1590 GNUNET_FS_namespace_list (GNUNET_FS_GTK_get_fs_handle (),
1591 &add_namespace_to_ts, GTK_TREE_STORE (ctx->pseudonym_treemodel));
1592 gtk_window_present (GTK_WINDOW (ctx->master_pubdialog));
1593}
1594
1595
1596/* end of gnunet-fs-gtk-main_window_file_publish.c */