diff options
Diffstat (limited to 'src/fs/gnunet-fs-gtk.c')
-rw-r--r-- | src/fs/gnunet-fs-gtk.c | 415 |
1 files changed, 381 insertions, 34 deletions
diff --git a/src/fs/gnunet-fs-gtk.c b/src/fs/gnunet-fs-gtk.c index 67a7059f..3223ec7b 100644 --- a/src/fs/gnunet-fs-gtk.c +++ b/src/fs/gnunet-fs-gtk.c | |||
@@ -46,6 +46,7 @@ static struct GNUNET_FS_Handle *fs; | |||
46 | */ | 46 | */ |
47 | static struct EXTRACTOR_PluginList *plugins; | 47 | static struct EXTRACTOR_PluginList *plugins; |
48 | 48 | ||
49 | guint namespace_selector_window_leave_timeout_source = 0; | ||
49 | 50 | ||
50 | /** | 51 | /** |
51 | * Return handle for file-sharing operations. | 52 | * Return handle for file-sharing operations. |
@@ -129,44 +130,389 @@ void | |||
129 | GNUNET_GTK_main_menu_file_search_activate_cb (GtkWidget * dummy, gpointer data); | 130 | GNUNET_GTK_main_menu_file_search_activate_cb (GtkWidget * dummy, gpointer data); |
130 | 131 | ||
131 | 132 | ||
133 | void | ||
134 | main_window_search_namespace_dropdown_button_toggled_cb (GtkToggleButton *togglebutton, | ||
135 | gpointer user_data) | ||
136 | { | ||
137 | gboolean active; | ||
138 | GtkBuilder *builder = GTK_BUILDER (user_data); | ||
139 | GtkWidget *namespace_selector_window; | ||
140 | namespace_selector_window = GTK_WIDGET (gtk_builder_get_object (builder, "namespace_selector_window")); | ||
141 | g_object_get (G_OBJECT (togglebutton), "active", &active, NULL); | ||
142 | if (active) | ||
143 | { | ||
144 | GtkAllocation togglebutton_allocation; | ||
145 | GdkWindow *main_window_gdk; | ||
146 | gint mwg_x, mwg_y, tgb_x, tgb_y, popup_x, popup_y; | ||
147 | |||
148 | gtk_widget_get_allocation (GTK_WIDGET (togglebutton), &togglebutton_allocation); | ||
149 | |||
150 | main_window_gdk = gtk_widget_get_window (GTK_WIDGET (togglebutton)); | ||
151 | |||
152 | gdk_window_get_origin (main_window_gdk, &mwg_x, &mwg_y); | ||
153 | |||
154 | /* FIXME: this might become a problem in other window managers, | ||
155 | * where reference point is not in the top-left corner. | ||
156 | * We want to show the window below the button. | ||
157 | */ | ||
158 | tgb_x = mwg_x + togglebutton_allocation.x; | ||
159 | tgb_y = mwg_y + togglebutton_allocation.y; | ||
160 | popup_x = tgb_x; | ||
161 | popup_y = tgb_y + togglebutton_allocation.height; | ||
162 | |||
163 | gtk_window_move (GTK_WINDOW (namespace_selector_window), popup_x, popup_y); | ||
164 | |||
165 | gtk_widget_show (namespace_selector_window); | ||
166 | } | ||
167 | else | ||
168 | gtk_widget_hide (namespace_selector_window); | ||
169 | } | ||
170 | |||
171 | gboolean | ||
172 | namespace_selector_window_leave_timeout_cb (gpointer user_data) | ||
173 | { | ||
174 | GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (user_data); | ||
175 | /* This will eventually hide the namespace selector */ | ||
176 | gtk_toggle_button_set_active (toggle_button, FALSE); | ||
177 | return FALSE; | ||
178 | } | ||
179 | |||
180 | gboolean | ||
181 | main_window_search_namespace_dropdown_button_enter_notify_event_cb ( | ||
182 | GtkWidget *widget, GdkEvent *event, gpointer user_data) | ||
183 | { | ||
184 | if (namespace_selector_window_leave_timeout_source > 0) | ||
185 | g_source_remove (namespace_selector_window_leave_timeout_source); | ||
186 | return FALSE; | ||
187 | } | ||
188 | |||
189 | |||
190 | gboolean | ||
191 | namespace_selector_window_leave_notify_event_cb (GtkWidget *widget, | ||
192 | GdkEvent *event, gpointer user_data) | ||
193 | { | ||
194 | GtkBuilder *builder; | ||
195 | GtkToggleButton *toggle_button; | ||
196 | guint timeout_id; | ||
197 | |||
198 | builder = GTK_BUILDER (user_data); | ||
199 | |||
200 | toggle_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "main_window_search_namespace_dropdown_button")); | ||
201 | |||
202 | /* Place a timeout to hide the window. It will be cancelled if the cursor | ||
203 | * enters the namespace selector window or the toggle button within 100ms. | ||
204 | */ | ||
205 | timeout_id = g_timeout_add (100, &namespace_selector_window_leave_timeout_cb, toggle_button); | ||
206 | if (namespace_selector_window_leave_timeout_source > 0) | ||
207 | g_source_remove (namespace_selector_window_leave_timeout_source); | ||
208 | namespace_selector_window_leave_timeout_source = timeout_id; | ||
209 | |||
210 | return FALSE; | ||
211 | } | ||
212 | |||
213 | gboolean | ||
214 | GNUNET_GTK_get_tree_string (GtkTreeView *treeview, GtkTreePath *treepath, | ||
215 | guint column, gchar **value) | ||
216 | { | ||
217 | gboolean ok; | ||
218 | GtkTreeModel *model; | ||
219 | |||
220 | model = gtk_tree_view_get_model (treeview); | ||
221 | if (!model) | ||
222 | return FALSE; | ||
223 | |||
224 | GtkTreeIter iter; | ||
225 | ok = gtk_tree_model_get_iter (model, &iter, treepath); | ||
226 | if (!ok) | ||
227 | return FALSE; | ||
228 | |||
229 | *value = NULL; | ||
230 | gtk_tree_model_get (model, &iter, column, value, -1); | ||
231 | if (*value == NULL) | ||
232 | return FALSE; | ||
233 | return TRUE; | ||
234 | } | ||
235 | |||
236 | gboolean | ||
237 | get_selected_anonymity_level (GtkBuilder *builder, guint *p_level) | ||
238 | { | ||
239 | GtkComboBox *combo; | ||
240 | GtkTreeIter iter; | ||
241 | GtkTreeModel *model; | ||
242 | guint level; | ||
243 | |||
244 | combo = GTK_COMBO_BOX(gtk_builder_get_object (builder, | ||
245 | "main_window_search_anonymity_combobox")); | ||
246 | if (!combo) | ||
247 | return FALSE; | ||
248 | |||
249 | if (!gtk_combo_box_get_active_iter (combo, &iter)) | ||
250 | return FALSE; | ||
251 | |||
252 | model = gtk_combo_box_get_model (combo); | ||
253 | if (!model) | ||
254 | return FALSE; | ||
255 | |||
256 | gtk_tree_model_get (model, &iter, 1, &level, -1); | ||
257 | if (p_level) | ||
258 | *p_level = level; | ||
259 | return TRUE; | ||
260 | } | ||
261 | |||
262 | gboolean | ||
263 | get_selected_namespace_treepath_iter_model_widget (GtkBuilder *builder, | ||
264 | GtkTreePath **p_treepath, GtkTreeIter *p_iter, GtkTreeModel **p_model, | ||
265 | GtkWidget **p_widget) | ||
266 | { | ||
267 | GtkTreeSelection *selection; | ||
268 | GtkTreeModel *model; | ||
269 | GList *selected; | ||
270 | GtkTreePath *treepath; | ||
271 | GtkWidget *widget; | ||
272 | |||
273 | widget = GTK_WIDGET (gtk_builder_get_object (builder, "namespace_selector_treeview")); | ||
274 | if (!widget) | ||
275 | return FALSE; | ||
276 | |||
277 | selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); | ||
278 | model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); | ||
279 | if (!selection || !model) | ||
280 | return FALSE; | ||
281 | |||
282 | selected = gtk_tree_selection_get_selected_rows (selection, NULL); | ||
283 | if (!selected) | ||
284 | return FALSE; | ||
285 | if (selected->data == NULL) | ||
286 | { | ||
287 | g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL); | ||
288 | g_list_free (selected); | ||
289 | return FALSE; | ||
290 | } | ||
291 | /* Free everything except the first path, keep it */ | ||
292 | treepath = (GtkTreePath *) selected->data; | ||
293 | selected = g_list_remove (selected, selected->data); | ||
294 | g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL); | ||
295 | g_list_free (selected); | ||
296 | |||
297 | if (p_iter && !gtk_tree_model_get_iter (model, p_iter, treepath)) | ||
298 | { | ||
299 | gtk_tree_path_free (treepath); | ||
300 | return FALSE; | ||
301 | } | ||
302 | *p_treepath = treepath; | ||
303 | if (p_model) | ||
304 | *p_model = model; | ||
305 | if (p_widget) | ||
306 | *p_widget = widget; | ||
307 | return TRUE; | ||
308 | } | ||
309 | |||
310 | void | ||
311 | namespace_selector_treeview_cursor_changed_cb (GtkWidget *widget, | ||
312 | gpointer user_data) | ||
313 | { | ||
314 | GtkBuilder *builder; | ||
315 | GtkToggleButton *toggle_button; | ||
316 | GtkLabel *sel_namespace_label; | ||
317 | gchar *value; | ||
318 | GtkTreePath *treepath; | ||
319 | |||
320 | builder = GTK_BUILDER (user_data); | ||
321 | |||
322 | if (!get_selected_namespace_treepath_iter_model_widget (builder, &treepath, NULL, NULL, NULL)) | ||
323 | return; | ||
324 | |||
325 | toggle_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "main_window_search_namespace_dropdown_button")); | ||
326 | if (!toggle_button) | ||
327 | return; | ||
328 | |||
329 | sel_namespace_label = GTK_LABEL (gtk_builder_get_object (builder, "main_window_search_selected_namespace_label")); | ||
330 | if (!sel_namespace_label) | ||
331 | return; | ||
332 | |||
333 | if (GNUNET_GTK_get_tree_string (GTK_TREE_VIEW (widget), treepath, 0, | ||
334 | &value)) | ||
335 | gtk_label_set_text (sel_namespace_label, value); | ||
336 | |||
337 | gtk_tree_path_free (treepath); | ||
338 | |||
339 | /* This will eventually hide the namespace selector */ | ||
340 | gtk_toggle_button_set_active (toggle_button, FALSE); | ||
341 | } | ||
342 | |||
343 | void | ||
344 | main_window_search_button_clicked_cb (GtkButton *button, gpointer user_data) | ||
345 | { | ||
346 | GtkBuilder *builder; | ||
347 | GtkTreePath *namespace_treepath = NULL; | ||
348 | GtkTreeModel *namespace_model = NULL; | ||
349 | GtkComboBox *mime_combo; | ||
350 | GtkTreeModel *mime_model; | ||
351 | GtkEntry *query_entry; | ||
352 | guint anonymity_level; | ||
353 | GtkTreeIter iter; | ||
354 | const char *entry_keywords; | ||
355 | gchar *keywords; | ||
356 | gchar *mime_keyword; | ||
357 | |||
358 | GNUNET_HashCode *nsid = NULL; | ||
359 | struct GNUNET_FS_Uri *uri; | ||
360 | char *emsg; | ||
361 | |||
362 | builder = GTK_BUILDER (user_data); | ||
363 | |||
364 | if (!get_selected_anonymity_level (builder, &anonymity_level)) | ||
365 | return; | ||
366 | |||
367 | mime_combo = GTK_COMBO_BOX (GNUNET_FS_GTK_get_main_window_object | ||
368 | ("main_window_search_mime_combobox")); | ||
369 | mime_model = gtk_combo_box_get_model (mime_combo); | ||
370 | if (mime_model && gtk_combo_box_get_active_iter (mime_combo, &iter)) | ||
371 | { | ||
372 | mime_keyword = NULL; | ||
373 | gtk_tree_model_get (mime_model, &iter, 0, &mime_keyword, -1); | ||
374 | } | ||
375 | |||
376 | get_selected_namespace_treepath_iter_model_widget (builder, | ||
377 | &namespace_treepath, &iter, &namespace_model, NULL); | ||
378 | |||
379 | query_entry = GTK_ENTRY (gtk_builder_get_object (builder, | ||
380 | "main_window_search_entry")); | ||
381 | |||
382 | entry_keywords = gtk_entry_get_text (query_entry); | ||
383 | if (mime_keyword != NULL) | ||
384 | { | ||
385 | keywords = g_strdup_printf ("%s %s", entry_keywords, mime_keyword); | ||
386 | g_free (mime_keyword); | ||
387 | } | ||
388 | else | ||
389 | keywords = g_strdup (entry_keywords); | ||
390 | if (namespace_treepath != NULL) | ||
391 | gtk_tree_model_get (namespace_model, &iter, 1, &nsid, -1); | ||
392 | if (nsid != NULL) | ||
393 | { | ||
394 | uri = GNUNET_FS_uri_sks_create_from_nsid (nsid, keywords); | ||
395 | GNUNET_assert (uri != NULL); | ||
396 | } | ||
397 | else | ||
398 | { | ||
399 | emsg = NULL; | ||
400 | uri = GNUNET_FS_uri_ksk_create (keywords, &emsg); | ||
401 | if (uri == NULL) | ||
402 | { | ||
403 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
404 | _("Invalid keyword string `%s': %s"), keywords, emsg); | ||
405 | GNUNET_free_non_null (emsg); | ||
406 | return; | ||
407 | } | ||
408 | } | ||
409 | GNUNET_FS_search_start (GNUNET_FS_GTK_get_fs_handle (), uri, | ||
410 | anonymity_level, GNUNET_FS_SEARCH_OPTION_NONE, NULL); | ||
411 | |||
412 | g_free (keywords); | ||
413 | GNUNET_FS_uri_destroy (uri); | ||
414 | } | ||
415 | |||
132 | /** | 416 | /** |
133 | * Add the tab with the 'new' icon for starting a search. | 417 | * Add pseudonym data to tree store |
418 | * | ||
419 | * @param cls closure (the 'GtkListStore') | ||
420 | * @param pseudonym hash code of public key of pseudonym | ||
421 | * @param md meta data known about the pseudonym | ||
422 | * @param rating the local rating of the pseudonym | ||
423 | * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort | ||
134 | */ | 424 | */ |
135 | static void | 425 | static int |
136 | add_new_tab () | 426 | add_namespace_to_ts (void *cls, const GNUNET_HashCode * pseudonym, |
427 | const struct GNUNET_CONTAINER_MetaData *md, int rating) | ||
137 | { | 428 | { |
138 | GtkNotebook *notebook; | 429 | GtkTreeStore *ts = cls; |
139 | GtkWindow *sf; | 430 | char *root; |
140 | gint pages; | 431 | char *ns_name; |
141 | GtkBuilder *builder; | 432 | GNUNET_HashCode *nsid; |
142 | GtkWidget *label; | 433 | char *description; |
143 | GtkWidget *frame; | 434 | char *uris; |
144 | 435 | char *emsg; | |
145 | builder = | 436 | struct GNUNET_FS_Uri *uri; |
146 | GNUNET_GTK_get_new_builder ("gnunet_fs_gtk_main_tab_new_frame.glade"); | 437 | GtkTreeIter iter; |
147 | 438 | ||
148 | /* load frame */ | 439 | ns_name = |
149 | sf = GTK_WINDOW (gtk_builder_get_object (builder, "_main_tab_new_frame")); | 440 | GNUNET_PSEUDONYM_id_to_name (GNUNET_FS_GTK_get_configuration (), |
150 | label = gtk_bin_get_child (GTK_BIN (sf)); | 441 | pseudonym); |
151 | g_object_ref (G_OBJECT (label)); | 442 | nsid = GNUNET_malloc (sizeof (GNUNET_HashCode)); |
152 | gtk_container_remove (GTK_CONTAINER (sf), label); | 443 | *nsid = *pseudonym; |
153 | gtk_widget_destroy (GTK_WIDGET (sf)); | 444 | root = NULL; |
154 | g_object_unref (builder); | 445 | uris = GNUNET_CONTAINER_meta_data_get_by_type (md, EXTRACTOR_METATYPE_URI); |
155 | g_signal_connect (G_OBJECT (label), "clicked", | 446 | if (uris != NULL) |
156 | G_CALLBACK (&GNUNET_GTK_main_menu_file_search_activate_cb), | 447 | { |
157 | NULL); | 448 | emsg = NULL; |
158 | 449 | uri = GNUNET_FS_uri_parse (uris, &emsg); | |
159 | notebook = | 450 | if (uri == NULL) |
160 | GTK_NOTEBOOK (GNUNET_FS_GTK_get_main_window_object | 451 | GNUNET_free (emsg); |
161 | ("GNUNET_GTK_main_window_notebook")); | 452 | root = GNUNET_FS_uri_sks_get_content_id (uri); |
162 | pages = gtk_notebook_get_n_pages (notebook); | 453 | GNUNET_FS_uri_destroy (uri); |
163 | frame = gtk_label_new (""); | 454 | } |
164 | gtk_widget_show (frame); | 455 | description = |
165 | gtk_notebook_append_page (notebook, frame, label); | 456 | GNUNET_CONTAINER_meta_data_get_first_by_types (md, |
166 | gtk_notebook_set_current_page (notebook, pages); | 457 | EXTRACTOR_METATYPE_TITLE, |
167 | gtk_widget_show (GTK_WIDGET (notebook)); | 458 | EXTRACTOR_METATYPE_BOOK_TITLE, |
459 | EXTRACTOR_METATYPE_DESCRIPTION, | ||
460 | EXTRACTOR_METATYPE_SUMMARY, | ||
461 | EXTRACTOR_METATYPE_ALBUM, | ||
462 | EXTRACTOR_METATYPE_COMMENT, | ||
463 | EXTRACTOR_METATYPE_SUBJECT, | ||
464 | EXTRACTOR_METATYPE_KEYWORDS, | ||
465 | -1); | ||
466 | gtk_tree_store_insert_with_values (ts, &iter, NULL, G_MAXINT, 0, ns_name, 1, | ||
467 | nsid, 2, root, 3, description, -1); | ||
468 | GNUNET_free (ns_name); | ||
469 | GNUNET_free_non_null (root); | ||
470 | GNUNET_free_non_null (description); | ||
471 | return GNUNET_OK; | ||
168 | } | 472 | } |
169 | 473 | ||
474 | void | ||
475 | GNUNET_GTK_main_window_realize_cb (GtkWidget *widget, gpointer user_data) | ||
476 | { | ||
477 | GtkTreeIter iter; | ||
478 | GtkTreeView *namespace_tree; | ||
479 | GtkTreeStore *namespace_treestore; | ||
480 | GtkBuilder *builder; | ||
481 | GtkWidget *namespace_selector_window; | ||
482 | |||
483 | builder = GTK_BUILDER (user_data); | ||
484 | |||
485 | namespace_treestore = GTK_TREE_STORE (GNUNET_FS_GTK_get_main_window_object | ||
486 | ("main_window_search_namespace_treestore")); | ||
487 | namespace_tree = GTK_TREE_VIEW (GNUNET_FS_GTK_get_main_window_object | ||
488 | ("namespace_selector_treeview")); | ||
489 | |||
490 | gtk_tree_store_insert_with_values (namespace_treestore, &iter, NULL, | ||
491 | G_MAXINT, 0, "Any", 1, NULL, 2, "", 3, | ||
492 | "Do not search in any particular namespace", -1); | ||
493 | GNUNET_PSEUDONYM_list_all (GNUNET_FS_GTK_get_configuration (), | ||
494 | &add_namespace_to_ts, namespace_treestore); | ||
495 | |||
496 | /* FIXME: read currently selected namespace from somewhere instead of selecting 0th item */ | ||
497 | if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (namespace_treestore), &iter)) | ||
498 | { | ||
499 | gchar *value; | ||
500 | GtkLabel *sel_namespace_label; | ||
501 | GtkTreePath *treepath = gtk_tree_path_new_first (); | ||
502 | gtk_tree_selection_select_iter (gtk_tree_view_get_selection ( | ||
503 | namespace_tree), &iter); | ||
504 | sel_namespace_label = GTK_LABEL (gtk_builder_get_object (builder, "main_window_search_selected_namespace_label")); | ||
505 | if (GNUNET_GTK_get_tree_string (namespace_tree, treepath, 0, &value)) | ||
506 | gtk_label_set_text (sel_namespace_label, value); | ||
507 | gtk_tree_path_free (treepath); | ||
508 | } | ||
509 | |||
510 | /* How the window (to trigger certain events) and immediately hide it */ | ||
511 | namespace_selector_window = GTK_WIDGET (gtk_builder_get_object (builder, "namespace_selector_window")); | ||
512 | gtk_widget_show (namespace_selector_window); | ||
513 | gtk_widget_hide (namespace_selector_window); | ||
514 | |||
515 | } | ||
170 | 516 | ||
171 | /** | 517 | /** |
172 | * Actual main function run right after GNUnet's scheduler | 518 | * Actual main function run right after GNUnet's scheduler |
@@ -201,7 +547,8 @@ run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
201 | GNUNET_FS_OPTIONS_END); | 547 | GNUNET_FS_OPTIONS_END); |
202 | if (fs != NULL) | 548 | if (fs != NULL) |
203 | { | 549 | { |
204 | add_new_tab (); | 550 | /* Searches are now started from the search bar */ |
551 | /* add_new_tab (); */ | ||
205 | } | 552 | } |
206 | else | 553 | else |
207 | { | 554 | { |