Merge lp:~aauzi/midori/fix-1006629 into lp:midori

Proposed by André Auzi
Status: Work in progress
Proposed branch: lp:~aauzi/midori/fix-1006629
Merge into: lp:midori
Diff against target: 4720 lines (+3164/-334)
13 files modified
katze/katze-array.c (+53/-2)
katze/katze-arrayaction.c (+270/-2)
katze/katze-utils.c (+156/-3)
katze/katze-utils.h (+11/-0)
midori/midori-array.c (+7/-0)
midori/midori-bookmarks-db.c (+106/-15)
midori/midori-bookmarks-db.h (+11/-9)
midori/midori-browser.c (+390/-31)
midori/midori-locationaction.c (+78/-10)
midori/midori-locationaction.h (+8/-0)
midori/midori-view.c (+110/-1)
panels/midori-bookmarks.c (+1963/-260)
tests/bookmarks.c (+1/-1)
To merge this branch: bzr merge lp:~aauzi/midori/fix-1006629
Reviewer Review Type Date Requested Status
Midori Devs Pending
Review via email: mp+203255@code.launchpad.net

Description of the change

Coming after lp:~aauzi/midori/fix-894143, this proposes bookmark creation by Dnd from Location bar into the bookmarkbar and ordering of the bookmarkbar with Dnd.

Preliminary code for Dnd creation from tabs is deactivated. It needs rework to adapt to recent tabby evolutions.

To post a comment you must log in.
lp:~aauzi/midori/fix-1006629 updated
6212. By André Auzi

merge lp:midori

Unmerged revisions

6212. By André Auzi

merge lp:midori

6211. By André Auzi

Merge lp:~aauzi/midori/fix-894143 with pos_bar order

6210. By André Auzi

Fix bookmarkbar item position updates

6209. By André Auzi

Put traces in midori_debug ("bookmarks")

6208. By André Auzi

merge lp:midori, remove tab drag-n-drop due to tabby evolutions

6207. By André Auzi

merge lp:midori

6206. By André Auzi

connect menu button press event

6205. By André Auzi

merge lp:midori

6204. By André Auzi

fix hilight item width

6203. By André Auzi

merge lp:midori

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'katze/katze-array.c'
--- katze/katze-array.c 2013-11-04 20:57:37 +0000
+++ katze/katze-array.c 2014-01-26 19:44:25 +0000
@@ -33,6 +33,15 @@
33 GList* items;33 GList* items;
34};34};
3535
36enum
37{
38 PROP_0,
39
40 PROP_TYPE,
41
42 N_PROPERTIES
43};
44
36enum {45enum {
37 ADD_ITEM,46 ADD_ITEM,
38 REMOVE_ITEM,47 REMOVE_ITEM,
@@ -55,6 +64,17 @@
55{64{
56 g_object_set_data (G_OBJECT (array), "last-update",65 g_object_set_data (G_OBJECT (array), "last-update",
57 GINT_TO_POINTER (time (NULL)));66 GINT_TO_POINTER (time (NULL)));
67/* #define DEBUG_UPDATE */
68#ifdef DEBUG_UPDATE
69 if (KATZE_IS_ITEM (array))
70 {
71 const gchar *name = katze_item_get_name (KATZE_ITEM (array));
72 if (name && *name)
73 {
74 g_print ("_katze_array_update: %s\n", name);
75 }
76 }
77#endif
58}78}
5979
60static void80static void
@@ -105,6 +125,27 @@
105}125}
106126
107static void127static void
128_katze_array_set_property (GObject *object,
129 guint property_id,
130 const GValue *value,
131 GParamSpec *pspec)
132{
133 KatzeArray *array = KATZE_ARRAY (object);
134
135 switch (property_id)
136 {
137 case PROP_TYPE:
138 array->priv->type = g_value_get_gtype (value);
139 break;
140
141 default:
142 /* We don't have any other property... */
143 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
144 break;
145 }
146}
147
148static void
108katze_array_class_init (KatzeArrayClass* class)149katze_array_class_init (KatzeArrayClass* class)
109{150{
110 GObjectClass* gobject_class;151 GObjectClass* gobject_class;
@@ -187,6 +228,7 @@
187228
188 gobject_class = G_OBJECT_CLASS (class);229 gobject_class = G_OBJECT_CLASS (class);
189 gobject_class->finalize = katze_array_finalize;230 gobject_class->finalize = katze_array_finalize;
231 gobject_class->set_property = _katze_array_set_property;
190232
191 class->add_item = _katze_array_add_item;233 class->add_item = _katze_array_add_item;
192 class->remove_item = _katze_array_remove_item;234 class->remove_item = _katze_array_remove_item;
@@ -194,6 +236,16 @@
194 class->clear = _katze_array_clear;236 class->clear = _katze_array_clear;
195 class->update = _katze_array_update;237 class->update = _katze_array_update;
196238
239
240 g_object_class_install_property (gobject_class,
241 PROP_TYPE,
242 g_param_spec_gtype (
243 "type",
244 "Type",
245 "The array item type",
246 G_TYPE_NONE,
247 G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
248
197 g_type_class_add_private (class, sizeof (KatzeArrayPrivate));249 g_type_class_add_private (class, sizeof (KatzeArrayPrivate));
198}250}
199251
@@ -238,8 +290,7 @@
238290
239 g_return_val_if_fail (g_type_is_a (type, G_TYPE_OBJECT), NULL);291 g_return_val_if_fail (g_type_is_a (type, G_TYPE_OBJECT), NULL);
240292
241 array = g_object_new (KATZE_TYPE_ARRAY, NULL);293 array = g_object_new (KATZE_TYPE_ARRAY, "type", type, NULL);
242 array->priv->type = type;
243294
244 return array;295 return array;
245}296}
246297
=== modified file 'katze/katze-arrayaction.c'
--- katze/katze-arrayaction.c 2012-12-16 18:40:00 +0000
+++ katze/katze-arrayaction.c 2014-01-26 19:44:25 +0000
@@ -29,6 +29,10 @@
2929
30 KatzeArray* array;30 KatzeArray* array;
31 gboolean reversed;31 gboolean reversed;
32
33 GtkTargetList* dnd_targets;
34 GdkEventButton *press_event;
35 GdkEventButton stock_press_event;
32};36};
3337
34struct _KatzeArrayActionClass38struct _KatzeArrayActionClass
@@ -43,7 +47,8 @@
43 PROP_0,47 PROP_0,
4448
45 PROP_ARRAY,49 PROP_ARRAY,
46 PROP_REVERSED50 PROP_REVERSED,
51 PROP_DND_TARGETS
47};52};
4853
49enum54enum
@@ -215,6 +220,20 @@
215 "Whether the array should be walked backwards when building menus",220 "Whether the array should be walked backwards when building menus",
216 FALSE,221 FALSE,
217 G_PARAM_READWRITE));222 G_PARAM_READWRITE));
223 /**
224 * KatzeArrayAction:dnd-targets:
225 *
226 * GtkTargetList* the array supports.
227 *
228 * Since: 0.5.2
229 **/
230 g_object_class_install_property (gobject_class,
231 PROP_DND_TARGETS,
232 g_param_spec_pointer (
233 "dnd-targets",
234 "DNDTargets",
235 "GtkTargetList* the array supports",
236 G_PARAM_READABLE|G_PARAM_WRITABLE));
218}237}
219238
220static void239static void
@@ -222,6 +241,8 @@
222{241{
223 array_action->array = NULL;242 array_action->array = NULL;
224 array_action->reversed = FALSE;243 array_action->reversed = FALSE;
244 array_action->dnd_targets = NULL;
245 array_action->press_event = NULL;
225}246}
226247
227static void248static void
@@ -229,6 +250,9 @@
229{250{
230 KatzeArrayAction* array_action = KATZE_ARRAY_ACTION (object);251 KatzeArrayAction* array_action = KATZE_ARRAY_ACTION (object);
231252
253 if (array_action->dnd_targets)
254 gtk_target_list_unref (array_action->dnd_targets);
255
232 katze_object_assign (array_action->array, NULL);256 katze_object_assign (array_action->array, NULL);
233257
234 G_OBJECT_CLASS (katze_array_action_parent_class)->finalize (object);258 G_OBJECT_CLASS (katze_array_action_parent_class)->finalize (object);
@@ -250,6 +274,9 @@
250 case PROP_REVERSED:274 case PROP_REVERSED:
251 array_action->reversed = g_value_get_boolean (value);275 array_action->reversed = g_value_get_boolean (value);
252 break;276 break;
277 case PROP_DND_TARGETS:
278 array_action->dnd_targets = (GtkTargetList*)g_value_get_pointer (value);
279 break;
253 default:280 default:
254 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);281 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
255 break;282 break;
@@ -272,6 +299,9 @@
272 case PROP_REVERSED:299 case PROP_REVERSED:
273 g_value_set_boolean (value, array_action->reversed);300 g_value_set_boolean (value, array_action->reversed);
274 break;301 break;
302 case PROP_DND_TARGETS:
303 g_value_set_pointer (value, array_action->dnd_targets);
304 break;
275 default:305 default:
276 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);306 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
277 break;307 break;
@@ -310,8 +340,29 @@
310 GdkEventButton* event,340 GdkEventButton* event,
311 KatzeArrayAction* array_action)341 KatzeArrayAction* array_action)
312{342{
343 array_action->stock_press_event = *event;
344 array_action->press_event = &array_action->stock_press_event;
345
346 return FALSE;
347}
348
349static gboolean
350katze_array_action_menu_button_release_cb (GtkWidget* proxy,
351 GdkEventButton* event,
352 KatzeArrayAction* array_action)
353{
313 KatzeItem* item = g_object_get_data (G_OBJECT (proxy), "KatzeItem");354 KatzeItem* item = g_object_get_data (G_OBJECT (proxy), "KatzeItem");
314355
356 if (array_action->press_event)
357 {
358 gint x = array_action->press_event->x;
359 gint y = array_action->press_event->y;
360 array_action->press_event = NULL;
361
362 if (x != event->x || y != event->y)
363 return TRUE;
364 }
365
315 katze_array_action_activate_item (array_action, item, event->button);366 katze_array_action_activate_item (array_action, item, event->button);
316367
317 /* we need to block the 'activate' handler which would be called368 /* we need to block the 'activate' handler which would be called
@@ -323,6 +374,120 @@
323}374}
324375
325static void376static void
377katze_array_action_item_drag_source_drag_data_get (
378 KatzeItem *item,
379 GdkDragContext *drag_context,
380 GtkSelectionData *data,
381 guint info,
382 guint time,
383 KatzeArrayAction* action)
384{
385 g_return_if_fail (KATZE_IS_ITEM (item));
386
387 switch (gdk_drag_context_get_selected_action (drag_context))
388 {
389 default:
390 break;
391 case GDK_ACTION_MOVE:
392 case GDK_ACTION_COPY:
393 if (selection_data_from_katze_item (data, item))
394 break;
395 case GDK_ACTION_LINK:
396 if (KATZE_ITEM_IS_BOOKMARK (item))
397 {
398 const gchar* uri = katze_item_get_uri (item);
399 if (uri && *uri)
400 {
401 gchar* src_uris[2];
402 gchar** uris;
403
404 src_uris[0] = (gchar*)uri;
405 src_uris[1] = NULL;
406
407 uris = g_strdupv (src_uris);
408
409 gtk_selection_data_set_uris (data, uris);
410 gtk_selection_data_set_text (data, uri, -1);
411
412 g_strfreev (uris);
413 }
414 }
415 break;
416 }
417}
418
419static void
420katze_array_action_menu_item_drag_source_drag_data_get_cb (
421 GtkWidget *widget,
422 GdkDragContext *drag_context,
423 GtkSelectionData *data,
424 guint info,
425 guint time,
426 KatzeArrayAction* action)
427{
428 KatzeItem* item = (KatzeItem*)g_object_get_data (G_OBJECT (widget), "KatzeItem");
429
430 katze_array_action_item_drag_source_drag_data_get (item, drag_context, data, info, time, action);
431}
432
433static void
434katze_array_action_tool_item_child_drag_source_drag_data_get_cb (
435 GtkWidget *widget,
436 GdkDragContext *drag_context,
437 GtkSelectionData *data,
438 guint info,
439 guint time,
440 KatzeArrayAction *action)
441{
442 GtkWidget* proxy = gtk_widget_get_parent (widget);
443 KatzeItem* item = (KatzeItem*)g_object_get_data (G_OBJECT (proxy), "KatzeItem");
444 GtkToolbar* toolbar = GTK_TOOLBAR (gtk_widget_get_parent (proxy));
445 gint pos;
446
447 g_return_if_fail (KATZE_IS_ITEM (item));
448
449 pos = gtk_toolbar_get_item_index (toolbar, GTK_TOOL_ITEM (proxy));
450 if (pos != katze_item_get_meta_integer (item, "pos_bar"))
451 katze_item_set_meta_integer (item, "pos_bar", pos);
452
453 katze_array_action_item_drag_source_drag_data_get (item, drag_context, data, info, time, action);
454}
455
456extern void midori_bookmarkbar_position_items (GtkWidget *widget);
457
458
459static void
460katze_array_action_tool_item_child_drag_source_drag_data_delete_cb (
461 GtkWidget *widget,
462 GdkDragContext *drag_context,
463 KatzeArrayAction* action)
464{
465 GtkWidget* proxy = gtk_widget_get_parent (widget);
466 KatzeItem* item = (KatzeItem*)g_object_get_data (G_OBJECT (proxy), "KatzeItem");
467 GtkToolbar* toolbar = GTK_TOOLBAR (gtk_widget_get_parent (proxy));
468
469 g_return_if_fail (KATZE_IS_ITEM (item));
470
471 gtk_container_remove (GTK_CONTAINER (toolbar), proxy);
472
473 midori_bookmarkbar_position_items (GTK_WIDGET (toolbar));
474}
475
476static void
477katze_array_action_menu_item_drag_source_drag_data_delete_cb (
478 GtkWidget *proxy,
479 GdkDragContext *drag_context,
480 KatzeArrayAction* action)
481{
482 KatzeItem* item = (KatzeItem*)g_object_get_data (G_OBJECT (proxy), "KatzeItem");
483 GtkMenuShell* menu = GTK_MENU_SHELL (gtk_widget_get_parent (proxy));
484
485 g_return_if_fail (KATZE_IS_ITEM (item));
486
487 gtk_container_remove (GTK_CONTAINER (menu), proxy);
488}
489
490static void
326katze_array_action_menu_item_select_cb (GtkWidget* proxy,491katze_array_action_menu_item_select_cb (GtkWidget* proxy,
327 KatzeArrayAction* array_action);492 KatzeArrayAction* array_action);
328493
@@ -407,6 +572,24 @@
407 G_CALLBACK (katze_array_action_menu_item_select_cb), array_action);572 G_CALLBACK (katze_array_action_menu_item_select_cb), array_action);
408 g_signal_connect (menuitem, "activate",573 g_signal_connect (menuitem, "activate",
409 G_CALLBACK (katze_array_action_menu_item_select_cb), array_action);574 G_CALLBACK (katze_array_action_menu_item_select_cb), array_action);
575#if 0
576 /* TODO: insert menu DND dest code here */
577 if (array_action->dnd_targets)
578 {
579 gtk_drag_dest_set (submenu, GTK_DEST_DEFAULT_ALL, NULL, 0,
580 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_LINK);
581 gtk_drag_dest_set_target_list (submenu, array_action->dnd_targets);
582 g_signal_connect (submenu, "drag-motion",
583 G_CALLBACK (katze_array_action_menu_drag_dest_drag_motion_cb),
584 array_action);
585 g_signal_connect (submenu, "drag-leave",
586 G_CALLBACK (katze_array_action_menu_drag_dest_drag_leave_cb),
587 array_action);
588 g_signal_connect (submenu, "drag-data-received",
589 G_CALLBACK (katze_array_action_menu_drag_dest_drag_data_received_cb),
590 array_action);
591 }
592#endif
410 }593 }
411 else594 else
412 {595 {
@@ -416,6 +599,23 @@
416 }599 }
417 g_signal_connect (menuitem, "button-press-event",600 g_signal_connect (menuitem, "button-press-event",
418 G_CALLBACK (katze_array_action_menu_button_press_cb), array_action);601 G_CALLBACK (katze_array_action_menu_button_press_cb), array_action);
602 g_signal_connect (menuitem, "button-release-event",
603 G_CALLBACK (katze_array_action_menu_button_release_cb), array_action);
604
605
606 if (array_action->dnd_targets)
607 {
608 gtk_drag_source_set (menuitem, GDK_BUTTON1_MASK, NULL, 0,
609 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_LINK);
610 gtk_drag_source_set_target_list (menuitem, array_action->dnd_targets);
611 g_signal_connect (menuitem, "drag-data-get",
612 G_CALLBACK (katze_array_action_menu_item_drag_source_drag_data_get_cb),
613 array_action);
614 g_signal_connect (menuitem, "drag-data-delete",
615 G_CALLBACK (katze_array_action_menu_item_drag_source_drag_data_delete_cb),
616 array_action);
617 }
618
419 gtk_widget_show (menuitem);619 gtk_widget_show (menuitem);
420 }620 }
421}621}
@@ -622,15 +822,49 @@
622 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);822 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
623 g_signal_connect (menuitem, "select",823 g_signal_connect (menuitem, "select",
624 G_CALLBACK (katze_array_action_menu_item_select_cb), array_action);824 G_CALLBACK (katze_array_action_menu_item_select_cb), array_action);
825#if 0
826 /* TODO: insert menu DND menu code here */
827 if (array_action->dnd_targets)
828 {
829 gtk_drag_dest_set (submenu, GTK_DEST_DEFAULT_ALL, NULL, 0,
830 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_LINK);
831 gtk_drag_dest_set_target_list (submenu, array_action->dnd_targets);
832 g_signal_connect (submenu, "drag-motion",
833 G_CALLBACK (katze_array_action_menu_drag_dest_drag_motion_cb),
834 array_action);
835 g_signal_connect (submenu, "drag-leave",
836 G_CALLBACK (katze_array_action_menu_drag_dest_drag_leave_cb),
837 array_action);
838 g_signal_connect (submenu, "drag-data-received",
839 G_CALLBACK (katze_array_action_menu_drag_dest_drag_data_received_cb),
840 array_action);
841 }
842#endif
625 }843 }
626 else844 else
627 {845 {
628 g_signal_connect (menuitem, "button-press-event",846 g_signal_connect (menuitem, "button-press-event",
629 G_CALLBACK (katze_array_action_menu_button_press_cb), array_action);847 G_CALLBACK (katze_array_action_menu_button_press_cb), array_action);
848 g_signal_connect (menuitem, "button-release-event",
849 G_CALLBACK (katze_array_action_menu_button_release_cb), array_action);
630 /* we need the 'activate' signal as well for keyboard events */850 /* we need the 'activate' signal as well for keyboard events */
631 g_signal_connect (menuitem, "activate",851 g_signal_connect (menuitem, "activate",
632 G_CALLBACK (katze_array_action_menu_activate_cb), array_action);852 G_CALLBACK (katze_array_action_menu_activate_cb), array_action);
633 }853 }
854
855 if (array_action->dnd_targets)
856 {
857 gtk_drag_source_set (menuitem, GDK_BUTTON1_MASK, NULL, 0,
858 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_LINK);
859 gtk_drag_source_set_target_list (menuitem, array_action->dnd_targets);
860 g_signal_connect (menuitem, "drag-data-get",
861 G_CALLBACK (katze_array_action_menu_item_drag_source_drag_data_get_cb),
862 array_action);
863 g_signal_connect (menuitem, "drag-data-delete",
864 G_CALLBACK (katze_array_action_menu_item_drag_source_drag_data_delete_cb),
865 array_action);
866 }
867
634 gtk_tool_item_set_proxy_menu_item (GTK_TOOL_ITEM (proxy),868 gtk_tool_item_set_proxy_menu_item (GTK_TOOL_ITEM (proxy),
635 "katze-tool-item-menu", menuitem);869 "katze-tool-item-menu", menuitem);
636 return TRUE;870 return TRUE;
@@ -706,9 +940,33 @@
706 else940 else
707 gtk_tool_item_set_tooltip_text (toolitem, uri);941 gtk_tool_item_set_tooltip_text (toolitem, uri);
708942
709 g_object_set_data (G_OBJECT (toolitem), "KatzeArray", item);943 g_object_set_data (G_OBJECT (toolitem), "KatzeItem", item);
710 g_signal_connect (toolitem, "clicked",944 g_signal_connect (toolitem, "clicked",
711 G_CALLBACK (katze_array_action_proxy_clicked_cb), array_action);945 G_CALLBACK (katze_array_action_proxy_clicked_cb), array_action);
946 if (KATZE_IS_ITEM (item))
947 {
948 GtkWidget* child = gtk_bin_get_child (GTK_BIN (toolitem));
949
950 if (KATZE_ITEM_IS_FOLDER (item) && array_action->dnd_targets)
951 {
952#if 0
953 /* TODO: add toggle button DND dest code here */
954#endif
955 }
956
957 if (array_action->dnd_targets)
958 {
959 gtk_drag_source_set (child, GDK_BUTTON1_MASK, NULL, 0,
960 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_LINK);
961 gtk_drag_source_set_target_list (child, array_action->dnd_targets);
962 g_signal_connect (child, "drag-data-get",
963 G_CALLBACK (katze_array_action_tool_item_child_drag_source_drag_data_get_cb),
964 array_action);
965 g_signal_connect (child, "drag-data-delete",
966 G_CALLBACK (katze_array_action_tool_item_child_drag_source_drag_data_delete_cb),
967 array_action);
968 }
969 }
712970
713 g_object_set_data (G_OBJECT (toolitem), "KatzeArrayAction", array_action);971 g_object_set_data (G_OBJECT (toolitem), "KatzeArrayAction", array_action);
714 g_signal_connect (item, "notify",972 g_signal_connect (item, "notify",
@@ -767,12 +1025,14 @@
767 KatzeArray* array)1025 KatzeArray* array)
768{1026{
769 GSList* proxies;1027 GSList* proxies;
1028 KatzeArray *old_array = NULL;
7701029
771 g_return_if_fail (KATZE_IS_ARRAY_ACTION (array_action));1030 g_return_if_fail (KATZE_IS_ARRAY_ACTION (array_action));
772 g_return_if_fail (!array || katze_array_is_a (array, KATZE_TYPE_ITEM));1031 g_return_if_fail (!array || katze_array_is_a (array, KATZE_TYPE_ITEM));
7731032
774 /* FIXME: Disconnect old array */1033 /* FIXME: Disconnect old array */
7751034
1035 old_array = array_action->array;
776 if (array)1036 if (array)
777 g_object_ref (array);1037 g_object_ref (array);
778 katze_object_assign (array_action->array, array);1038 katze_object_assign (array_action->array, array);
@@ -793,7 +1053,15 @@
7931053
794 do1054 do
795 {1055 {
1056 KatzeArray* item = g_object_get_data (G_OBJECT (proxies->data), "KatzeItem");
1057
1058 if (item && (item == old_array))
1059 g_object_set_data (G_OBJECT (proxies->data), "KatzeItem", array);
1060
796 gtk_widget_set_sensitive (proxies->data, array != NULL);1061 gtk_widget_set_sensitive (proxies->data, array != NULL);
797 }1062 }
798 while ((proxies = g_slist_next (proxies)));1063 while ((proxies = g_slist_next (proxies)));
1064
1065 if (array)
1066 katze_array_update (KATZE_ARRAY (array));
799}1067}
8001068
=== modified file 'katze/katze-utils.c'
--- katze/katze-utils.c 2013-11-05 21:51:18 +0000
+++ katze/katze-utils.c 2014-01-26 19:44:25 +0000
@@ -29,6 +29,13 @@
29 #include <unistd.h>29 #include <unistd.h>
30#endif30#endif
3131
32typedef struct _KatzeArrayData KatzeArrayData;
33
34struct _KatzeArrayData
35{
36 KatzeItem* items[1];
37};
38
32#define I_ g_intern_static_string39#define I_ g_intern_static_string
3340
34static void41static void
@@ -1002,12 +1009,99 @@
10021009
1003 g_return_val_if_fail (GTK_IS_TREE_VIEW (treeview), FALSE);1010 g_return_val_if_fail (GTK_IS_TREE_VIEW (treeview), FALSE);
10041011
1005 if ((selection = gtk_tree_view_get_selection (treeview)))1012 selection = gtk_tree_view_get_selection(treeview);
1006 if (gtk_tree_selection_get_selected (selection, model, iter))1013
1007 return TRUE;1014 switch (gtk_tree_selection_get_mode (selection))
1015 {
1016 default:
1017 break;
1018
1019 case GTK_SELECTION_SINGLE:
1020 case GTK_SELECTION_BROWSE:
1021 if (gtk_tree_selection_get_selected (selection, model, iter))
1022 return TRUE;
1023 break;
1024
1025 case GTK_SELECTION_MULTIPLE:
1026 if (gtk_tree_selection_count_selected_rows (selection) == 1)
1027 {
1028 GtkTreeModel *stock_model;
1029 GList *list = gtk_tree_selection_get_selected_rows (selection, &stock_model);
1030
1031 if (model)
1032 *model = stock_model;
1033
1034 if (list)
1035 {
1036 GtkTreePath *path = (GtkTreePath *)g_list_nth_data (list, 0);
1037
1038 if (path && (!iter || gtk_tree_model_get_iter (stock_model, iter, path)))
1039 {
1040 g_list_free_full(list, (GDestroyNotify) gtk_tree_path_free);
1041 return TRUE;
1042 }
1043
1044 g_list_free_full(list, (GDestroyNotify) gtk_tree_path_free);
1045 }
1046 }
1047 }
1048
1008 return FALSE;1049 return FALSE;
1009}1050}
10101051
1052/**
1053 * katze_tree_view_get_selected_rows:
1054 * @treeview: a #GtkTreeView
1055 * @model: a pointer to store the #GtkTreeModel, or %NULL
1056 * @rows: a pointer to store the #GList of #GtkTreePath, or %NULL
1057 *
1058 * Determines whether there is a selection in @treeview
1059 * and sets the @rows to the current selection.
1060 *
1061 * If there is a selection and @model is not %NULL, it is
1062 * set to the model. If @model is %NULL, the @rows will be
1063 * set to %NULL.
1064 *
1065 * Either @model or @rows or both can be %NULL in which case
1066 * no value will be assigned in any case.
1067 *
1068 * When @rows is not %NULL it must be freed using:
1069 * g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free);
1070 *
1071 * Return value: the count of selected rows
1072 *
1073 * Since: 0.4.7.aau.1
1074 **/
1075
1076gint
1077katze_tree_view_get_selected_rows (GtkTreeView* treeview,
1078 GtkTreeModel** model,
1079 GList** rows)
1080{
1081 gint count;
1082 GtkTreeSelection* selection;
1083
1084 if (model)
1085 *model = NULL;
1086 if (rows)
1087 *rows = NULL;
1088
1089 g_return_val_if_fail (GTK_IS_TREE_VIEW (treeview), 0);
1090
1091 selection = gtk_tree_view_get_selection(treeview);
1092
1093 count = gtk_tree_selection_count_selected_rows (selection);
1094 if (count > 0)
1095 {
1096 if (model && rows)
1097 {
1098 *rows = gtk_tree_selection_get_selected_rows (selection, model);
1099 }
1100 }
1101
1102 return count;
1103}
1104
1011void1105void
1012katze_bookmark_populate_tree_view (KatzeArray* array,1106katze_bookmark_populate_tree_view (KatzeArray* array,
1013 GtkTreeStore* model,1107 GtkTreeStore* model,
@@ -1377,3 +1471,62 @@
1377 gtk_widget_set_size_request (GTK_WIDGET (window), 700, 100);1471 gtk_widget_set_size_request (GTK_WIDGET (window), 700, 100);
1378}1472}
13791473
1474gboolean
1475selection_data_from_katze_item (GtkSelectionData* selection_data, KatzeItem* item)
1476{
1477 GdkAtom katze_array_atom = gdk_atom_intern_static_string ("KATZE_ARRAY");
1478 KatzeArrayData *kad;
1479
1480 g_return_val_if_fail (selection_data != NULL, FALSE);
1481 g_return_val_if_fail (KATZE_IS_ITEM (item), FALSE);
1482
1483 if (gtk_selection_data_get_target (selection_data) != katze_array_atom)
1484 return FALSE;
1485
1486 kad = g_malloc (sizeof (KatzeArrayData));
1487
1488 kad->items[0] = item;
1489
1490 gtk_selection_data_set (selection_data,
1491 katze_array_atom,
1492 8, /* bytes */
1493 (void*)kad,
1494 sizeof (KatzeArrayData));
1495
1496 g_free (kad);
1497 return TRUE;
1498}
1499
1500KatzeArray*
1501katze_array_from_selection_data (GtkSelectionData* selection_data)
1502{
1503 GdkAtom katze_array_atom = gdk_atom_intern_static_string ("KATZE_ARRAY");
1504 KatzeArrayData *kad;
1505 KatzeArray *array;
1506 gint size;
1507 gint count;
1508 gint i;
1509
1510 g_return_val_if_fail (selection_data != NULL, FALSE);
1511
1512 if (gtk_selection_data_get_target (selection_data) != katze_array_atom)
1513 return NULL;
1514
1515 if (gtk_selection_data_get_format (selection_data) != 8)
1516 return NULL;
1517
1518 size = gtk_selection_data_get_length (selection_data);
1519 if (size <= 0)
1520 return NULL;
1521
1522 kad = (void*) gtk_selection_data_get_data (selection_data);
1523
1524 count = (size - G_STRUCT_OFFSET (KatzeArrayData, items))/sizeof(KatzeItem*);
1525
1526 array = katze_array_new (KATZE_TYPE_ARRAY);
1527
1528 for ( i = 0; i < count; i++ )
1529 katze_array_add_item (array, kad->items[i]);
1530
1531 return array;
1532}
13801533
=== modified file 'katze/katze-utils.h'
--- katze/katze-utils.h 2013-04-16 22:10:56 +0000
+++ katze/katze-utils.h 2014-01-26 19:44:25 +0000
@@ -88,6 +88,11 @@
88 GtkTreeModel** model,88 GtkTreeModel** model,
89 GtkTreeIter* iter);89 GtkTreeIter* iter);
9090
91gint
92katze_tree_view_get_selected_rows (GtkTreeView* treeview,
93 GtkTreeModel** model,
94 GList** rows);
95
91void96void
92katze_bookmark_populate_tree_view (KatzeArray* array,97katze_bookmark_populate_tree_view (KatzeArray* array,
93 GtkTreeStore* model,98 GtkTreeStore* model,
@@ -138,6 +143,12 @@
138void143void
139katze_window_set_sensible_default_size (GtkWindow* window);144katze_window_set_sensible_default_size (GtkWindow* window);
140145
146gboolean
147selection_data_from_katze_item (GtkSelectionData* selection_data, KatzeItem* item);
148
149KatzeArray*
150katze_array_from_selection_data (GtkSelectionData* selection_data);
151
141G_END_DECLS152G_END_DECLS
142153
143#endif /* __KATZE_UTILS_H__ */154#endif /* __KATZE_UTILS_H__ */
144155
=== modified file 'midori/midori-array.c'
--- midori/midori-array.c 2013-08-05 19:52:52 +0000
+++ midori/midori-array.c 2014-01-26 19:44:25 +0000
@@ -1031,9 +1031,16 @@
1031 || g_str_equal (name, "last_visit") || g_str_equal (name, "visit_count")1031 || g_str_equal (name, "last_visit") || g_str_equal (name, "visit_count")
1032 || g_str_equal (name, "pos_panel") || g_str_equal (name, "pos_bar"))1032 || g_str_equal (name, "pos_panel") || g_str_equal (name, "pos_bar"))
1033 {1033 {
1034#if 0
1034 gint value;1035 gint value;
1035 value = sqlite3_column_int64 (stmt, column);1036 value = sqlite3_column_int64 (stmt, column);
1036 katze_item_set_meta_integer (item, name, value);1037 katze_item_set_meta_integer (item, name, value);
1038#else
1039 /* use text to properly handle NULL values */
1040 const unsigned char* text;
1041 text = sqlite3_column_text (stmt, column);
1042 katze_item_set_meta_string (item, name, (gchar*)text);
1043#endif
1037 }1044 }
1038 else if (g_str_equal (name, "desc"))1045 else if (g_str_equal (name, "desc"))
1039 {1046 {
10401047
=== modified file 'midori/midori-bookmarks-db.c'
--- midori/midori-bookmarks-db.c 2014-01-24 23:04:05 +0000
+++ midori/midori-bookmarks-db.c 2014-01-26 19:44:25 +0000
@@ -181,14 +181,29 @@
181midori_bookmarks_db_get_item_parent (MidoriBookmarksDb* bookmarks,181midori_bookmarks_db_get_item_parent (MidoriBookmarksDb* bookmarks,
182 gpointer item)182 gpointer item)
183{183{
184 gint64 parentid = katze_item_get_meta_integer (KATZE_ITEM (item), "parentid");
185 KatzeItem *search = katze_item_new ();
184 KatzeArray* parent;186 KatzeArray* parent;
185 gint64 parentid;187
186188 if (!parentid)
187 parentid = katze_item_get_meta_integer (KATZE_ITEM (item), "parentid");189 {
188190 parentid = katze_item_get_meta_integer (KATZE_ITEM (bookmarks), "id");
189 if (parentid == 0)191 katze_item_set_meta_integer (KATZE_ITEM (item), "parentid", parentid);
190 {192 }
193
194 katze_item_set_meta_integer(search, "id", parentid);
195
196 parent = KATZE_ARRAY (g_hash_table_lookup (bookmarks->all_items, search));
197
198 g_object_unref (search);
199
200 if (!parent)
201 {
202 g_warning ("item parent not found\n");
203
191 parent = KATZE_ARRAY (bookmarks);204 parent = KATZE_ARRAY (bookmarks);
205 katze_item_set_meta_integer (KATZE_ITEM (item), "parentid",
206 katze_item_get_meta_integer (KATZE_ITEM (bookmarks), "id"));
192 }207 }
193 else208 else
194 {209 {
@@ -267,7 +282,10 @@
267282
268 g_return_if_fail (parent);283 g_return_if_fail (parent);
269284
270 katze_array_update (parent);285 if (IS_MIDORI_BOOKMARKS_DB (parent))
286 KATZE_ARRAY_CLASS (midori_bookmarks_db_parent_class)->update (parent);
287 else
288 katze_array_update (parent);
271}289}
272290
273/**291/**
@@ -479,7 +497,7 @@
479 else if (old_parent && katze_item_get_meta_integer (old_parent, "id") > 0)497 else if (old_parent && katze_item_get_meta_integer (old_parent, "id") > 0)
480 new_parentid = g_strdup_printf ("%" G_GINT64_FORMAT, katze_item_get_meta_integer (old_parent, "id"));498 new_parentid = g_strdup_printf ("%" G_GINT64_FORMAT, katze_item_get_meta_integer (old_parent, "id"));
481 else499 else
482 new_parentid = g_strdup_printf ("NULL");500 new_parentid = g_strdup ("NULL");
483501
484 sqlcmd = sqlite3_mprintf (502 sqlcmd = sqlite3_mprintf (
485 "INSERT INTO bookmarks (id, parentid, title, uri, desc, toolbar, app) "503 "INSERT INTO bookmarks (id, parentid, title, uri, desc, toolbar, app) "
@@ -557,7 +575,8 @@
557575
558 sqlcmd = sqlite3_mprintf (576 sqlcmd = sqlite3_mprintf (
559 "UPDATE bookmarks SET "577 "UPDATE bookmarks SET "
560 "parentid=%q, title='%q', uri='%q', desc='%q', toolbar=%d, app=%d "578 "parentid=%q, title='%q', uri='%q', desc='%q', toolbar=%d, app=%d, "
579 "pos_bar=%d, pos_panel=%d "
561 "WHERE id = %q ;",580 "WHERE id = %q ;",
562 parentid,581 parentid,
563 katze_item_get_name (item),582 katze_item_get_name (item),
@@ -565,6 +584,8 @@
565 katze_str_non_null (katze_item_get_meta_string (item, "desc")),584 katze_str_non_null (katze_item_get_meta_string (item, "desc")),
566 katze_item_get_meta_boolean (item, "toolbar"),585 katze_item_get_meta_boolean (item, "toolbar"),
567 katze_item_get_meta_boolean (item, "app"),586 katze_item_get_meta_boolean (item, "app"),
587 (gint)katze_item_get_meta_integer (item, "pos_bar"),
588 (gint)katze_item_get_meta_integer (item, "pos_panel"),
568 id);589 id);
569590
570 updated = TRUE;591 updated = TRUE;
@@ -579,6 +600,14 @@
579 g_free (parentid);600 g_free (parentid);
580 g_free (id);601 g_free (id);
581602
603#ifdef DEBUG_DB_UPDATE
604 g_print ("update:%s - parentid: %s, pos_bar:%d, pos_panel:%d\n",
605 katze_item_get_name (item),
606 parentid,
607 (gint)katze_item_get_meta_integer (item, "pos_bar"),
608 (gint)katze_item_get_meta_integer (item, "pos_panel"));
609#endif
610
582 return updated;611 return updated;
583}612}
584613
@@ -710,10 +739,10 @@
710 g_return_val_if_fail (errmsg != NULL, NULL);739 g_return_val_if_fail (errmsg != NULL, NULL);
711740
712 database = midori_bookmarks_database_new (&error);741 database = midori_bookmarks_database_new (&error);
713 742
714 if (error != NULL)743 if (error != NULL)
715 {744 {
716 *errmsg = g_strdup (error->message);745 *errmsg = g_strdup (error->message);
717 g_error_free (error);746 g_error_free (error);
718 return NULL;747 return NULL;
719 }748 }
@@ -724,7 +753,10 @@
724 if (midori_debug ("bookmarks"))753 if (midori_debug ("bookmarks"))
725 sqlite3_trace (db, midori_bookmarks_db_dbtracer, NULL);754 sqlite3_trace (db, midori_bookmarks_db_dbtracer, NULL);
726755
727 bookmarks = MIDORI_BOOKMARKS_DB (g_object_new (TYPE_MIDORI_BOOKMARKS_DB, NULL));756 bookmarks = MIDORI_BOOKMARKS_DB (g_object_new (TYPE_MIDORI_BOOKMARKS_DB,
757 "type", KATZE_TYPE_ITEM,
758 NULL));
759
728 bookmarks->db = db;760 bookmarks->db = db;
729761
730 g_object_set_data (G_OBJECT (bookmarks), "db", db);762 g_object_set_data (G_OBJECT (bookmarks), "db", db);
@@ -776,6 +808,7 @@
776 katze_item_set_meta_integer (item, "parentid", parentid);808 katze_item_set_meta_integer (item, "parentid", parentid);
777 midori_bookmarks_db_add_item (bookmarks, item);809 midori_bookmarks_db_add_item (bookmarks, item);
778 }810 }
811
779 g_list_free (list);812 g_list_free (list);
780}813}
781814
@@ -859,7 +892,7 @@
859 * @array: the main bookmark array892 * @array: the main bookmark array
860 * @sqlcmd: the sqlcmd to execute893 * @sqlcmd: the sqlcmd to execute
861 *894 *
862 * Internal function that process the requested @sqlcmd.895 * Internal function that processes the requested @sqlcmd.
863 *896 *
864 * Return value: a #KatzeArray on success, %NULL otherwise897 * Return value: a #KatzeArray on success, %NULL otherwise
865 **/898 **/
@@ -885,6 +918,10 @@
885 * @fields: comma separated list of fields918 * @fields: comma separated list of fields
886 * @condition: condition, like "folder = '%q'"919 * @condition: condition, like "folder = '%q'"
887 * @value: a value to be inserted if @condition contains %q920 * @value: a value to be inserted if @condition contains %q
921 * @order: a value to be inserted in "ORDER BY"
922 * default order is :
923 * (uri='') ASC, title DESC
924 * given @order, when not %NULL, replaces the term: (uri='') ASC
888 * @recursive: if %TRUE include children925 * @recursive: if %TRUE include children
889 *926 *
890 * Stores the result in a #KatzeArray.927 * Stores the result in a #KatzeArray.
@@ -898,6 +935,7 @@
898 const gchar* fields,935 const gchar* fields,
899 const gchar* condition,936 const gchar* condition,
900 const gchar* value,937 const gchar* value,
938 const gchar* order,
901 gboolean recursive)939 gboolean recursive)
902{940{
903 gchar* sqlcmd;941 gchar* sqlcmd;
@@ -911,7 +949,8 @@
911 g_return_val_if_fail (condition, NULL);949 g_return_val_if_fail (condition, NULL);
912950
913 sqlcmd = g_strdup_printf ("SELECT %s FROM bookmarks WHERE %s "951 sqlcmd = g_strdup_printf ("SELECT %s FROM bookmarks WHERE %s "
914 "ORDER BY (uri='') ASC, title DESC", fields, condition);952 "ORDER BY %s, title DESC", fields, condition, order ? order : "(uri='') ASC");
953
915 if (strstr (condition, "%q"))954 if (strstr (condition, "%q"))
916 {955 {
917 sqlcmd_value = sqlite3_mprintf (sqlcmd, value ? value : "");956 sqlcmd_value = sqlite3_mprintf (sqlcmd, value ? value : "");
@@ -932,7 +971,7 @@
932 gchar* parentid = g_strdup_printf ("%" G_GINT64_FORMAT,971 gchar* parentid = g_strdup_printf ("%" G_GINT64_FORMAT,
933 katze_item_get_meta_integer (item, "id"));972 katze_item_get_meta_integer (item, "id"));
934 KatzeArray* subarray = midori_bookmarks_db_query_recursive (bookmarks,973 KatzeArray* subarray = midori_bookmarks_db_query_recursive (bookmarks,
935 fields, "parentid=%q", parentid, TRUE);974 fields, "parentid=%q", parentid, order, TRUE);
936 KatzeItem* subitem;975 KatzeItem* subitem;
937 GList* sublist;976 GList* sublist;
938977
@@ -1097,3 +1136,55 @@
1097 value, id,1136 value, id,
1098 recursive);1137 recursive);
1099}1138}
1139
1140/**
1141 * midori_bookmarks_db_populate_folder:
1142 **/
1143
1144void
1145midori_bookmarks_db_populate_folder (MidoriBookmarksDb* bookmarks,
1146 KatzeArray *folder)
1147{
1148 const gchar* id = katze_item_get_meta_string (KATZE_ITEM (folder), "id");
1149 const gchar *condition;
1150 KatzeArray* array;
1151 KatzeItem* item;
1152 GList* list;
1153
1154 if (id == NULL)
1155 {
1156 condition = "parentid is NULL";
1157 }
1158 else
1159 {
1160 condition = "parentid = %q";
1161 }
1162
1163 array = midori_bookmarks_db_query_recursive (bookmarks,
1164 "id, title, parentid, uri, app, pos_panel, pos_bar", condition, id, "(uri='') ASC, pos_panel ASC", FALSE);
1165
1166 if (IS_MIDORI_BOOKMARKS_DB (folder))
1167 {
1168 KATZE_ARRAY_FOREACH_ITEM_L (item, folder, list)
1169 {
1170 KATZE_ARRAY_CLASS (midori_bookmarks_db_parent_class)->remove_item (folder, item);
1171 }
1172
1173 KATZE_ARRAY_FOREACH_ITEM_L (item, array, list)
1174 {
1175 KATZE_ARRAY_CLASS (midori_bookmarks_db_parent_class)->add_item (folder, item);
1176 }
1177 }
1178 else
1179 {
1180 katze_array_clear(folder);
1181
1182 KATZE_ARRAY_FOREACH_ITEM_L (item, array, list)
1183 {
1184 katze_array_add_item (folder, item);
1185 }
1186 }
1187
1188 g_object_unref (array);
1189}
1190
11001191
=== modified file 'midori/midori-bookmarks-db.h'
--- midori/midori-bookmarks-db.h 2013-09-17 19:34:23 +0000
+++ midori/midori-bookmarks-db.h 2014-01-26 19:44:25 +0000
@@ -62,19 +62,21 @@
62 const gchar* fields,62 const gchar* fields,
63 const gchar* condition,63 const gchar* condition,
64 const gchar* value,64 const gchar* value,
65 const gchar* order,
65 gboolean recursive);66 gboolean recursive);
6667
67gint6468gint64
68midori_bookmarks_db_count_recursive (MidoriBookmarksDb* bookmarks,69midori_bookmarks_db_count_recursive (MidoriBookmarksDb* bookmarks,
69 const gchar* condition,70 const gchar* condition,
70 const gchar* value,71 const gchar* value,
71 KatzeItem* folder,72 KatzeItem* folder,
72 gboolean recursive);73 gboolean recursive);
7374
74gint6475void
75midori_bookmarks_insert_item_db (sqlite3* db,76midori_bookmarks_db_on_quit (MidoriBookmarksDb* array);
76 KatzeItem* item,77
77 gint64 parentid);78void
79midori_bookmarks_db_populate_folder (MidoriBookmarksDb* bookmarks,
80 KatzeArray *folder);
7881
79#endif /* !__MIDORI_BOOKMARKS_DB_H__ */82#endif /* !__MIDORI_BOOKMARKS_DB_H__ */
80
8183
=== modified file 'midori/midori-browser.c'
--- midori/midori-browser.c 2014-01-06 23:05:10 +0000
+++ midori/midori-browser.c 2014-01-26 19:44:25 +0000
@@ -99,9 +99,24 @@
99 guint maximum_history_age;99 guint maximum_history_age;
100 guint last_web_search;100 guint last_web_search;
101101
102 struct _BookmarkbarDNDControl
103 {
104 GtkTargetList* source_targets;
105 GtkTargetList* dest_targets;
106
107 struct _BookmarkbarDragDestControl
108 {
109 GtkToolItem* highligth_item;
110 gboolean hovering;
111 int n;
112 } drag_dest_control;
113 } bookmarkbar_dnd_control;
102 gboolean bookmarkbar_populate;114 gboolean bookmarkbar_populate;
103};115};
104116
117typedef struct _BookmarkbarDNDControl BookmarkbarDNDControl;
118typedef struct _BookmarkbarDragDestControl BookmarkbarDragDestControl;
119
105G_DEFINE_TYPE (MidoriBrowser, midori_browser, GTK_TYPE_WINDOW)120G_DEFINE_TYPE (MidoriBrowser, midori_browser, GTK_TYPE_WINDOW)
106121
107enum122enum
@@ -173,11 +188,22 @@
173midori_bookmarkbar_populate (MidoriBrowser* browser);188midori_bookmarkbar_populate (MidoriBrowser* browser);
174static void189static void
175midori_bookmarkbar_populate_idle (MidoriBrowser* browser);190midori_bookmarkbar_populate_idle (MidoriBrowser* browser);
191void
192midori_bookmarkbar_position_items (GtkWidget* widget);
176193
177static void194static void
178midori_bookmarkbar_clear (GtkWidget* toolbar);195midori_bookmarkbar_clear (GtkWidget* toolbar);
179196
180static void197static void
198bookmarkbar_dnd_control_init (BookmarkbarDNDControl* control, MidoriBrowser* browser);
199
200static void
201bookmarkbar_dnd_control_finalize (BookmarkbarDNDControl* control);
202
203static void
204bookmarkbar_dnd_control_install (BookmarkbarDNDControl* control, GtkToolbar* bookmarkbar);
205
206static void
181_midori_browser_set_toolbar_style (MidoriBrowser* browser,207_midori_browser_set_toolbar_style (MidoriBrowser* browser,
182 MidoriToolbarStyle toolbar_style);208 MidoriToolbarStyle toolbar_style);
183209
@@ -716,6 +742,8 @@
716 const gchar* title)742 const gchar* title)
717{743{
718 const gchar* custom_title = midori_settings_get_custom_title (MIDORI_SETTINGS (browser->settings));744 const gchar* custom_title = midori_settings_get_custom_title (MIDORI_SETTINGS (browser->settings));
745 GtkAction* action = _action_by_name (browser, "Location");
746 midori_location_action_set_title (MIDORI_LOCATION_ACTION (action), title);
719 if (custom_title && *custom_title)747 if (custom_title && *custom_title)
720 gtk_window_set_title (GTK_WINDOW (browser), custom_title);748 gtk_window_set_title (GTK_WINDOW (browser), custom_title);
721 else if (katze_object_get_boolean (browser->settings, "enable-private-browsing"))749 else if (katze_object_get_boolean (browser->settings, "enable-private-browsing"))
@@ -885,14 +913,14 @@
885 gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo));913 gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo));
886914
887 renderer = gtk_cell_renderer_pixbuf_new ();915 renderer = gtk_cell_renderer_pixbuf_new ();
888 g_object_set (G_OBJECT (renderer), 916 g_object_set (G_OBJECT (renderer),
889 "stock-id", GTK_STOCK_DIRECTORY,917 "stock-id", GTK_STOCK_DIRECTORY,
890 "stock-size", GTK_ICON_SIZE_MENU,918 "stock-size", GTK_ICON_SIZE_MENU,
891 NULL);919 NULL);
892 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, FALSE);920 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, FALSE);
893921
894 renderer = katze_cell_renderer_combobox_text_new ();922 renderer = katze_cell_renderer_combobox_text_new ();
895 g_object_set (G_OBJECT (renderer), 923 g_object_set (G_OBJECT (renderer),
896 "width-chars", 40, /* FIXME: figure out a way to define an acceptable string length */924 "width-chars", 40, /* FIXME: figure out a way to define an acceptable string length */
897 "ellipsize", PANGO_ELLIPSIZE_END,925 "ellipsize", PANGO_ELLIPSIZE_END,
898 "unfolded-text", _("Select [text]"),926 "unfolded-text", _("Select [text]"),
@@ -916,7 +944,7 @@
916 folders = g_list_append (folders, folder);944 folders = g_list_append (folders, folder);
917 }945 }
918946
919 sqlite3_clear_bindings (statement);947 sqlite3_clear_bindings (statement);
920 sqlite3_reset (statement);948 sqlite3_reset (statement);
921 }949 }
922950
@@ -1025,7 +1053,7 @@
1025static gint641053static gint64
1026midori_bookmark_folder_button_get_active (GtkWidget* combo)1054midori_bookmark_folder_button_get_active (GtkWidget* combo)
1027{1055{
1028 gint64 id = 0;1056 gint64 id = -1;
1029 GtkTreeIter iter;1057 GtkTreeIter iter;
10301058
1031 g_return_val_if_fail (GTK_IS_COMBO_BOX (combo), 0);1059 g_return_val_if_fail (GTK_IS_COMBO_BOX (combo), 0);
@@ -1902,6 +1930,8 @@
1902 KatzeItem* item = midori_view_get_proxy_item (MIDORI_VIEW (view));1930 KatzeItem* item = midori_view_get_proxy_item (MIDORI_VIEW (view));
1903 guint n;1931 guint n;
19041932
1933 g_object_set (view, "dnd-targets", browser->bookmarkbar_dnd_control.source_targets, NULL);
1934
1905 midori_browser_connect_tab (browser, view);1935 midori_browser_connect_tab (browser, view);
19061936
1907 if (!katze_item_get_meta_boolean (item, "append") &&1937 if (!katze_item_get_meta_boolean (item, "append") &&
@@ -3107,29 +3137,17 @@
3107 KatzeArray* folder,3137 KatzeArray* folder,
3108 MidoriBrowser* browser)3138 MidoriBrowser* browser)
3109{3139{
3110 KatzeArray* bookmarks;
3111 const gchar* id = katze_item_get_meta_string (KATZE_ITEM (folder), "id");
3112 gchar* condition;
3113
3114 if (browser->bookmarks == NULL)3140 if (browser->bookmarks == NULL)
3115 return FALSE;3141 return FALSE;
31163142
3117 if (id == NULL)3143 midori_bookmarks_db_populate_folder (browser->bookmarks, folder);
3118 condition = "parentid is NULL";
3119 else
3120 condition = "parentid = %q";
3121
3122 bookmarks = midori_bookmarks_db_query_recursive (browser->bookmarks,
3123 "id, title, parentid, uri, app, pos_panel, pos_bar", condition, id, FALSE);
3124 if (!bookmarks)
3125 return FALSE;
31263144
3127 /* Clear items from dummy array here */3145 /* Clear items from dummy array here */
3128 gtk_container_foreach (GTK_CONTAINER (menu),3146 gtk_container_foreach (GTK_CONTAINER (menu),
3129 (GtkCallback)(gtk_widget_destroy), NULL);3147 (GtkCallback)(gtk_widget_destroy), NULL);
31303148
3131 /* "Import Bookmarks" and "Export Bookmarks" at the top */3149 /* "Import Bookmarks" and "Export Bookmarks" at the top */
3132 if (id == NULL)3150 if (folder == KATZE_ARRAY (browser->bookmarks))
3133 {3151 {
3134 GtkWidget* menuitem;3152 GtkWidget* menuitem;
3135 menuitem = gtk_action_create_menu_item (_action_by_name (browser, "BookmarksImport"));3153 menuitem = gtk_action_create_menu_item (_action_by_name (browser, "BookmarksImport"));
@@ -3143,7 +3161,7 @@
3143 gtk_widget_show (menuitem);3161 gtk_widget_show (menuitem);
3144 }3162 }
31453163
3146 if (katze_array_is_empty (bookmarks))3164 if (katze_array_is_empty (folder))
3147 {3165 {
3148 GtkWidget* menuitem = gtk_image_menu_item_new_with_label (_("Empty"));3166 GtkWidget* menuitem = gtk_image_menu_item_new_with_label (_("Empty"));
3149 gtk_widget_set_sensitive (menuitem, FALSE);3167 gtk_widget_set_sensitive (menuitem, FALSE);
@@ -3152,7 +3170,7 @@
3152 return TRUE;3170 return TRUE;
3153 }3171 }
31543172
3155 katze_array_action_generate_menu (KATZE_ARRAY_ACTION (action), bookmarks,3173 katze_array_action_generate_menu (KATZE_ARRAY_ACTION (action), folder,
3156 menu, GTK_WIDGET (browser));3174 menu, GTK_WIDGET (browser));
3157 return TRUE;3175 return TRUE;
3158}3176}
@@ -4502,7 +4520,7 @@
45024520
4503 error = NULL;4521 error = NULL;
4504 bookmarks = midori_bookmarks_db_query_recursive (browser->bookmarks,4522 bookmarks = midori_bookmarks_db_query_recursive (browser->bookmarks,
4505 "*", "parentid IS NULL", NULL, TRUE);4523 "*", "parentid IS NULL", NULL, NULL, TRUE);
4506 if (!midori_array_to_file (bookmarks, path, format, &error))4524 if (!midori_array_to_file (bookmarks, path, format, &error))
4507 {4525 {
4508 sokoke_message_dialog (GTK_MESSAGE_ERROR,4526 sokoke_message_dialog (GTK_MESSAGE_ERROR,
@@ -4903,6 +4921,8 @@
4903 uri = midori_view_get_display_uri (new_view);4921 uri = midori_view_get_display_uri (new_view);
4904 midori_browser_set_title (browser, midori_view_get_display_title (new_view));4922 midori_browser_set_title (browser, midori_view_get_display_title (new_view));
4905 action = _action_by_name (browser, "Location");4923 action = _action_by_name (browser, "Location");
4924 midori_location_action_set_icon (MIDORI_LOCATION_ACTION (action), midori_view_get_icon_uri (new_view));
4925 midori_location_action_set_title (MIDORI_LOCATION_ACTION (action), midori_view_get_display_title (new_view));
4906 midori_location_action_set_text (MIDORI_LOCATION_ACTION (action), uri);4926 midori_location_action_set_text (MIDORI_LOCATION_ACTION (action), uri);
4907 if (midori_paths_get_runtime_mode () == MIDORI_RUNTIME_MODE_APP)4927 if (midori_paths_get_runtime_mode () == MIDORI_RUNTIME_MODE_APP)
4908 gtk_window_set_icon (GTK_WINDOW (browser), midori_view_get_icon (new_view));4928 gtk_window_set_icon (GTK_WINDOW (browser), midori_view_get_icon (new_view));
@@ -5876,8 +5896,6 @@
5876 g_object_connect (action,5896 g_object_connect (action,
5877 "signal::populate-popup",5897 "signal::populate-popup",
5878 _action_tools_populate_popup, browser,5898 _action_tools_populate_popup, browser,
5879 "signal::activate-item-alt",
5880 midori_bookmarkbar_activate_item_alt, browser,
5881 NULL);5899 NULL);
5882 gtk_action_group_add_action (browser->action_group, action);5900 gtk_action_group_add_action (browser->action_group, action);
5883 g_object_unref (action);5901 g_object_unref (action);
@@ -6003,7 +6021,11 @@
6003 g_signal_connect (browser->bookmarkbar, "popup-context-menu",6021 g_signal_connect (browser->bookmarkbar, "popup-context-menu",
6004 G_CALLBACK (midori_browser_toolbar_popup_context_menu_cb), browser);6022 G_CALLBACK (midori_browser_toolbar_popup_context_menu_cb), browser);
60056023
6006 /* Create the panel */6024 bookmarkbar_dnd_control_init (&browser->bookmarkbar_dnd_control, browser);
6025 bookmarkbar_dnd_control_install (&browser->bookmarkbar_dnd_control,
6026 GTK_TOOLBAR (browser->bookmarkbar));
6027
6028 /* Create the panel */
6007 hpaned = gtk_hpaned_new ();6029 hpaned = gtk_hpaned_new ();
6008 g_signal_connect (hpaned, "notify::position",6030 g_signal_connect (hpaned, "notify::position",
6009 G_CALLBACK (midori_panel_notify_position_cb),6031 G_CALLBACK (midori_panel_notify_position_cb),
@@ -6101,6 +6123,8 @@
6101{6123{
6102 MidoriBrowser* browser = MIDORI_BROWSER (object);6124 MidoriBrowser* browser = MIDORI_BROWSER (object);
61036125
6126 bookmarkbar_dnd_control_finalize (&browser->bookmarkbar_dnd_control);
6127
6104 katze_assign (browser->statusbar_text, NULL);6128 katze_assign (browser->statusbar_text, NULL);
61056129
6106 katze_object_assign (browser->settings, NULL);6130 katze_object_assign (browser->settings, NULL);
@@ -6624,7 +6648,8 @@
66246648
6625static void6649static void
6626midori_bookmarkbar_insert_item (GtkWidget* toolbar,6650midori_bookmarkbar_insert_item (GtkWidget* toolbar,
6627 KatzeItem* item)6651 KatzeItem* item,
6652 gint pos)
6628{6653{
6629 MidoriBrowser* browser = midori_browser_get_for_widget (toolbar);6654 MidoriBrowser* browser = midori_browser_get_for_widget (toolbar);
6630 GtkAction* action = _action_by_name (browser, "Bookmarks");6655 GtkAction* action = _action_by_name (browser, "Bookmarks");
@@ -6643,19 +6668,19 @@
6643 else /* Separator */6668 else /* Separator */
6644 gtk_tool_item_set_use_drag_window (toolitem, TRUE);6669 gtk_tool_item_set_use_drag_window (toolitem, TRUE);
66456670
6671 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, pos);
6646 gtk_widget_show (GTK_WIDGET (toolitem));6672 gtk_widget_show (GTK_WIDGET (toolitem));
6647 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
6648}6673}
66496674
6650static void6675static void
6651midori_bookmarkbar_add_item_cb (KatzeArray* bookmarks,6676midori_bookmarkbar_add_item_cb (KatzeArray* bookmarks,
6652 KatzeItem* item,6677 KatzeItem* item,
6653 MidoriBrowser* browser)6678 MidoriBrowser* browser)
6654{6679{
6655 if (gtk_widget_get_visible (browser->bookmarkbar))6680 if (gtk_widget_get_visible (browser->bookmarkbar))
6656 midori_bookmarkbar_populate (browser);6681 midori_bookmarkbar_populate (browser);
6657 else if (katze_item_get_meta_boolean (item, "toolbar"))6682 else if (katze_item_get_meta_boolean (item, "toolbar"))
6658 _action_set_active (browser, "Bookmarkbar", TRUE);6683 _action_set_active (browser, "Bookmarkbar", TRUE);
6659 midori_browser_update_history (item, "bookmark", "created");6684 midori_browser_update_history (item, "bookmark", "created");
6660}6685}
66616686
@@ -6702,7 +6727,7 @@
6702 gtk_separator_tool_item_new (), -1);6727 gtk_separator_tool_item_new (), -1);
67036728
6704 array = midori_bookmarks_db_query_recursive (browser->bookmarks,6729 array = midori_bookmarks_db_query_recursive (browser->bookmarks,
6705 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "toolbar = 1", NULL, FALSE);6730 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "toolbar = 1", NULL, "pos_bar ASC", FALSE);
6706 if (!array)6731 if (!array)
6707 {6732 {
6708 _action_set_sensitive (browser, "BookmarkAdd", FALSE);6733 _action_set_sensitive (browser, "BookmarkAdd", FALSE);
@@ -6712,10 +6737,12 @@
67126737
6713 KATZE_ARRAY_FOREACH_ITEM (item, array)6738 KATZE_ARRAY_FOREACH_ITEM (item, array)
6714 {6739 {
6715 midori_bookmarkbar_insert_item (browser->bookmarkbar, item);6740 midori_bookmarkbar_insert_item (browser->bookmarkbar, item, -1);
6716 }6741 }
6717 _action_set_sensitive (browser, "BookmarkAdd", TRUE);6742 _action_set_sensitive (browser, "BookmarkAdd", TRUE);
6718 _action_set_sensitive (browser, "BookmarkFolderAdd", TRUE);6743 _action_set_sensitive (browser, "BookmarkFolderAdd", TRUE);
6744
6745 midori_bookmarkbar_position_items (browser->bookmarkbar);
6719}6746}
67206747
6721static void6748static void
@@ -6756,6 +6783,10 @@
6756 midori_bookmarkbar_remove_item_cb, browser);6783 midori_bookmarkbar_remove_item_cb, browser);
6757 }6784 }
67586785
6786 g_object_set (G_OBJECT (_action_by_name (browser, "Bookmarks")),
6787 "array", KATZE_ARRAY (bookmarks),
6788 NULL);
6789
6759 settings = midori_browser_get_settings (browser);6790 settings = midori_browser_get_settings (browser);
6760 g_signal_handlers_disconnect_by_func (settings,6791 g_signal_handlers_disconnect_by_func (settings,
6761 midori_browser_show_bookmarkbar_notify_value_cb, browser);6792 midori_browser_show_bookmarkbar_notify_value_cb, browser);
@@ -7481,3 +7512,331 @@
74817512
7482 g_signal_emit (browser, signals[QUIT], 0);7513 g_signal_emit (browser, signals[QUIT], 0);
7483}7514}
7515
7516static void
7517bookmarkbar_drag_dest_control_init (BookmarkbarDragDestControl* control)
7518{
7519 control->highligth_item = NULL;
7520 control->hovering = FALSE;
7521}
7522
7523static GtkTargetEntry bookmarkbar_dnd_target_entries[]=
7524{
7525 {"KATZE_ARRAY", GTK_TARGET_SAME_APP, 0},
7526};
7527
7528#define BOOKMARKBAR_DND_NB_TARGET_ENTRIES \
7529 G_N_ELEMENTS (bookmarkbar_dnd_target_entries)
7530
7531static void
7532bookmarkbar_dnd_control_init (BookmarkbarDNDControl* control, MidoriBrowser* browser)
7533{
7534 bookmarkbar_drag_dest_control_init (&control->drag_dest_control);
7535
7536 control->source_targets = gtk_target_list_new (
7537 bookmarkbar_dnd_target_entries, BOOKMARKBAR_DND_NB_TARGET_ENTRIES);
7538 gtk_target_list_add_uri_targets (control->source_targets, 0);
7539 gtk_target_list_add_text_targets (control->source_targets, 0);
7540
7541 control->dest_targets = gtk_target_list_new (
7542 bookmarkbar_dnd_target_entries, BOOKMARKBAR_DND_NB_TARGET_ENTRIES);
7543
7544 g_object_set (_action_by_name (browser, "Bookmarks"), "dnd-targets", control->source_targets, NULL);
7545 g_object_set (_action_by_name (browser, "Location"), "dnd-targets", control->source_targets, NULL);
7546}
7547
7548static void
7549bookmarkbar_dnd_control_finalize (BookmarkbarDNDControl* control)
7550{
7551 gtk_target_list_unref (control->source_targets);
7552 gtk_target_list_unref (control->dest_targets);
7553 control->source_targets = NULL;
7554 control->dest_targets = NULL;
7555}
7556
7557
7558static GtkToolItem*
7559bookmarkbar_drag_highlight_item (GdkDragContext *context)
7560{
7561
7562 GtkToolItem* highlight_item = NULL;
7563 GtkWidget* source = gtk_drag_get_source_widget (context);
7564
7565 if (source)
7566 {
7567 KatzeItem* item = (KatzeItem*)g_object_get_data (G_OBJECT (source), "KatzeItem");
7568
7569 if (!item && GTK_IS_TOOL_ITEM (gtk_widget_get_parent (source)))
7570 item = (KatzeItem*)g_object_get_data (G_OBJECT (gtk_widget_get_parent (source)), "KatzeItem");
7571
7572 if (KATZE_ITEM_IS_BOOKMARK (item))
7573 highlight_item = gtk_tool_button_new (NULL, "");
7574 else if (KATZE_ITEM_IS_FOLDER (item))
7575 highlight_item = gtk_toggle_tool_button_new ();
7576
7577 if (highlight_item)
7578 {
7579 GtkToolButton* toolbutton = GTK_TOOL_BUTTON (highlight_item);
7580 GtkWidget* image = katze_item_get_image (item, GTK_WIDGET (highlight_item));
7581 const gchar* title = katze_item_get_name (item);
7582 GtkWidget* label = gtk_label_new (NULL);
7583
7584 gtk_widget_show (image);
7585
7586 if (!title || !*title)
7587 title = katze_item_get_uri (item);
7588
7589 /* FIXME: Should text direction be respected here? */
7590 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
7591 gtk_label_set_max_width_chars (GTK_LABEL (label), 25);
7592 gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_MIDDLE);
7593 gtk_label_set_text (GTK_LABEL (label), title);
7594 gtk_widget_show (label);
7595
7596 gtk_tool_button_set_icon_widget (toolbutton, image);
7597 gtk_tool_button_set_label_widget (toolbutton, label);
7598
7599 gtk_tool_item_set_visible_horizontal (highlight_item, TRUE);
7600 gtk_tool_item_set_visible_vertical (highlight_item, TRUE);
7601 gtk_tool_item_set_is_important (highlight_item, TRUE);
7602 }
7603 }
7604
7605 if (!highlight_item)
7606 highlight_item = gtk_separator_tool_item_new ();
7607
7608 gtk_widget_show (GTK_WIDGET (highlight_item));
7609 return highlight_item;
7610}
7611
7612static gboolean
7613bookmarkbar_drag_dest_drag_motion_cb (GtkWidget *widget,
7614 GdkDragContext *context,
7615 gint x, gint y, guint t,
7616 BookmarkbarDragDestControl* control)
7617{
7618 GtkToolbar* toolbar = GTK_TOOLBAR (widget);
7619 gint n = gtk_toolbar_get_drop_index (toolbar, x, y);
7620
7621 if (!control->highligth_item)
7622 {
7623 GtkToolItem* highlight_item = bookmarkbar_drag_highlight_item (context);
7624 g_object_ref (highlight_item);
7625
7626 gtk_toolbar_set_drop_highlight_item (toolbar,
7627 highlight_item,
7628 n);
7629 control->highligth_item = highlight_item;
7630 control->n = n;
7631 }
7632 else if (n != control->n)
7633 {
7634 gtk_toolbar_set_drop_highlight_item (toolbar,
7635 control->highligth_item,
7636 n);
7637 control->n = n;
7638 }
7639 return FALSE;
7640}
7641
7642static void
7643bookmarkbar_drag_dest_drag_leave_cb (GtkWidget *widget,
7644 GdkDragContext *context,
7645 guint time,
7646 BookmarkbarDragDestControl* control)
7647{
7648 GtkToolbar* toolbar = GTK_TOOLBAR (widget);
7649
7650 if (control->highligth_item)
7651 {
7652 gtk_toolbar_set_drop_highlight_item (toolbar, NULL, -1);
7653 g_object_unref (control->highligth_item);
7654 control->highligth_item = NULL;
7655 }
7656}
7657
7658void
7659midori_bookmarkbar_position_items (GtkWidget *widget)
7660{
7661 GtkToolbar* toolbar = GTK_TOOLBAR (widget);
7662 MidoriBrowser* browser = midori_browser_get_for_widget (widget);
7663 gint n = gtk_toolbar_get_n_items (toolbar);
7664 gint i;
7665 gint pos;
7666
7667 pos = 0;
7668 for (i = 0; i < n ; i++ )
7669 {
7670 GtkWidget* toolitem = GTK_WIDGET (gtk_toolbar_get_nth_item (toolbar, i));
7671 KatzeItem* local_item = (KatzeItem*)g_object_get_data (G_OBJECT (toolitem), "KatzeItem");
7672
7673 if (!KATZE_IS_ITEM (local_item))
7674 continue;
7675
7676 if (pos != katze_item_get_meta_integer (local_item, "pos_bar"))
7677 katze_item_set_meta_integer (local_item, "pos_bar", pos);
7678
7679 midori_bookmarks_db_update_item (browser->bookmarks, local_item);
7680
7681 pos++;
7682 }
7683}
7684
7685static void
7686bookmarkbar_drag_dest_drag_data_received_cb (GtkWidget *widget,
7687 GdkDragContext *drag_context,
7688 gint x,
7689 gint y,
7690 GtkSelectionData *data,
7691 guint info,
7692 guint time,
7693 BookmarkbarDragDestControl* control)
7694{
7695 GtkToolbar* toolbar = GTK_TOOLBAR (widget);
7696 MidoriBrowser* browser = midori_browser_get_for_widget (widget);
7697 gboolean success = FALSE;
7698 gboolean delete = FALSE;
7699
7700 g_assert (browser);
7701
7702 g_signal_handlers_block_by_func (browser->bookmarks,
7703 midori_bookmarkbar_add_item_cb, browser);
7704 g_signal_handlers_block_by_func (browser->bookmarks,
7705 midori_bookmarkbar_update_item_cb, browser);
7706 g_signal_handlers_block_by_func (browser->bookmarks,
7707 midori_bookmarkbar_remove_item_cb, browser);
7708
7709 if (gtk_selection_data_get_length (data) >= 0)
7710 {
7711 switch (gdk_drag_context_get_selected_action (drag_context))
7712 {
7713 case GDK_ACTION_MOVE:
7714 delete = TRUE;
7715 case GDK_ACTION_COPY:
7716 if (gtk_selection_data_get_format (data) == 8)
7717 {
7718 KatzeArray *array = katze_array_from_selection_data (data);
7719
7720 if (array)
7721 {
7722 KatzeItem *item;
7723 KATZE_ARRAY_FOREACH_ITEM (item, array)
7724 {
7725 gint old_pos = gtk_toolbar_get_n_items(toolbar);
7726 gint dest_pos = gtk_toolbar_get_drop_index (toolbar, x, y);
7727 gboolean is_bookmark = katze_item_get_meta_string (item, "id") ? TRUE : FALSE ;
7728 gboolean from_toolbar = is_bookmark && katze_item_get_meta_boolean (item, "toolbar");
7729
7730 if (midori_debug("bookmarks"))
7731 {
7732 g_print ("bookmarkbar received KATZE_ITEM(bookmark:%d, toolbar:%d, title:%s) \n",
7733 is_bookmark, from_toolbar, katze_item_get_name (item));
7734 }
7735
7736 if (from_toolbar)
7737 {
7738 GtkToolItem* toolitem = NULL;
7739 KatzeItem* local_item = NULL;
7740
7741 old_pos = katze_item_get_meta_integer (item, "pos_bar");
7742
7743 if ((dest_pos != old_pos)
7744 && (toolitem = gtk_toolbar_get_nth_item (toolbar,
7745 old_pos))
7746 && (local_item = (KatzeItem*)g_object_get_data (
7747 G_OBJECT (toolitem), "KatzeItem")))
7748 {
7749 midori_bookmarkbar_insert_item (widget,
7750 local_item, dest_pos);
7751
7752 if (old_pos < dest_pos)
7753 old_pos++;
7754
7755 /* FIXME: force a move */
7756 delete = TRUE;
7757 }
7758 else
7759 delete = FALSE;
7760 }
7761 else if (!is_bookmark)
7762 {
7763 item = katze_item_copy (item);
7764
7765 katze_item_set_meta_integer (item, "toolbar", TRUE);
7766
7767 midori_bookmarkbar_insert_item (widget,
7768 item, dest_pos);
7769
7770 midori_bookmarks_db_add_item (browser->bookmarks, item);
7771
7772 if (old_pos > dest_pos)
7773 old_pos++;
7774
7775 delete = FALSE;
7776 }
7777 else
7778 {
7779 katze_item_set_meta_integer (item, "toolbar", TRUE);
7780
7781 midori_bookmarkbar_insert_item (widget,
7782 item, dest_pos);
7783
7784 if (old_pos > dest_pos)
7785 old_pos++;
7786
7787 delete = FALSE;
7788 }
7789 }
7790
7791 g_object_unref (array);
7792 success = TRUE;
7793 break;
7794 }
7795 }
7796 default:
7797 break;
7798 }
7799 }
7800
7801 if (!success)
7802 delete = FALSE;
7803
7804 gtk_drag_finish (drag_context, success, delete, time);
7805
7806 if (success && !delete)
7807 {
7808 midori_bookmarkbar_position_items (GTK_WIDGET (toolbar));
7809 }
7810
7811 g_signal_handlers_unblock_by_func (browser->bookmarks,
7812 midori_bookmarkbar_add_item_cb, browser);
7813 g_signal_handlers_unblock_by_func (browser->bookmarks,
7814 midori_bookmarkbar_update_item_cb, browser);
7815 g_signal_handlers_unblock_by_func (browser->bookmarks,
7816 midori_bookmarkbar_remove_item_cb, browser);
7817}
7818
7819static void
7820bookmarkbar_drag_dest_control_install (BookmarkbarDNDControl* control,
7821 GtkToolbar* bookmarkbar)
7822{
7823 GtkWidget* widget = GTK_WIDGET (bookmarkbar);
7824 gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_ALL, NULL, 0,
7825 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_LINK);
7826 gtk_drag_dest_set_target_list (widget, control->dest_targets);
7827 g_signal_connect (bookmarkbar, "drag-motion",
7828 G_CALLBACK (bookmarkbar_drag_dest_drag_motion_cb),
7829 &control->drag_dest_control);
7830 g_signal_connect (bookmarkbar, "drag-leave",
7831 G_CALLBACK (bookmarkbar_drag_dest_drag_leave_cb),
7832 &control->drag_dest_control);
7833 g_signal_connect (bookmarkbar, "drag-data-received",
7834 G_CALLBACK (bookmarkbar_drag_dest_drag_data_received_cb),
7835 &control->drag_dest_control);
7836}
7837
7838static void
7839bookmarkbar_dnd_control_install (BookmarkbarDNDControl* control, GtkToolbar* bookmarkbar)
7840{
7841 bookmarkbar_drag_dest_control_install (control, bookmarkbar);
7842}
74847843
=== modified file 'midori/midori-locationaction.c'
--- midori/midori-locationaction.c 2013-11-05 14:51:49 +0000
+++ midori/midori-locationaction.c 2014-01-26 19:44:25 +0000
@@ -43,6 +43,8 @@
43 gint completion_index;43 gint completion_index;
44 GtkWidget* entry;44 GtkWidget* entry;
45 KatzeArray* history;45 KatzeArray* history;
46 KatzeItem* item;
47 GtkTargetList* dnd_targets;
46};48};
4749
48struct _MidoriLocationActionClass50struct _MidoriLocationActionClass
@@ -58,7 +60,8 @@
5860
59 PROP_PROGRESS,61 PROP_PROGRESS,
60 PROP_SECONDARY_ICON,62 PROP_SECONDARY_ICON,
61 PROP_HISTORY63 PROP_HISTORY,
64 PROP_DND_TARGETS
62};65};
6366
64enum67enum
@@ -222,6 +225,22 @@
222 "The list of history items",225 "The list of history items",
223 KATZE_TYPE_ARRAY,226 KATZE_TYPE_ARRAY,
224 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));227 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
228
229 /**
230 * MidoriLocationAction:dnd-targets:
231 *
232 * GtkTargetList* the location action supports.
233 *
234 * Since: 0.5.2
235 **/
236 g_object_class_install_property (gobject_class,
237 PROP_DND_TARGETS,
238 g_param_spec_pointer (
239 "dnd-targets",
240 "DNDTargets",
241 "GtkTargetList* the location action supports",
242 G_PARAM_READABLE|G_PARAM_WRITABLE));
243
225}244}
226245
227gchar*246gchar*
@@ -813,6 +832,8 @@
813{832{
814 location_action->progress = 0.0;833 location_action->progress = 0.0;
815 location_action->completion_index = -1;834 location_action->completion_index = -1;
835 location_action->item = katze_item_new ();
836 location_action->dnd_targets = NULL;
816}837}
817838
818static void839static void
@@ -832,6 +853,8 @@
832 }853 }
833 katze_object_assign (location_action->history, NULL);854 katze_object_assign (location_action->history, NULL);
834855
856 g_object_unref (location_action->item);
857
835 G_OBJECT_CLASS (midori_location_action_parent_class)->finalize (object);858 G_OBJECT_CLASS (midori_location_action_parent_class)->finalize (object);
836}859}
837860
@@ -858,6 +881,9 @@
858 katze_assign (location_action->history, g_value_dup_object (value));881 katze_assign (location_action->history, g_value_dup_object (value));
859 break;882 break;
860 }883 }
884 case PROP_DND_TARGETS:
885 location_action->dnd_targets = (GtkTargetList*)g_value_get_pointer (value);
886 break;
861 default:887 default:
862 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);888 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
863 break;889 break;
@@ -883,6 +909,9 @@
883 case PROP_HISTORY:909 case PROP_HISTORY:
884 g_value_set_object (value, location_action->history);910 g_value_set_object (value, location_action->history);
885 break;911 break;
912 case PROP_DND_TARGETS:
913 g_value_set_pointer (value, location_action->dnd_targets);
914 break;
886 default:915 default:
887 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);916 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
888 break;917 break;
@@ -917,20 +946,19 @@
917 GtkSelectionData* data,946 GtkSelectionData* data,
918 guint info,947 guint info,
919 guint32 time,948 guint32 time,
920 GtkAction* action)949 MidoriLocationAction* action)
921{950{
922 if (gtk_entry_get_current_icon_drag_source (GTK_ENTRY (entry)) == GTK_ENTRY_ICON_PRIMARY)951 if (gtk_entry_get_current_icon_drag_source (GTK_ENTRY (entry)) == GTK_ENTRY_ICON_PRIMARY)
923 {952 {
924 const gchar* uri = gtk_entry_get_text (GTK_ENTRY (entry));953 katze_item_set_uri (action->item, gtk_entry_get_text (GTK_ENTRY (entry)));
925 gchar** uris = g_strsplit (uri, uri, 1);954 selection_data_from_katze_item (data, action->item);
926 gtk_selection_data_set_uris (data, uris);
927 g_strfreev (uris);
928 }955 }
929}956}
930957
931static GtkWidget*958static GtkWidget*
932midori_location_action_create_tool_item (GtkAction* action)959midori_location_action_create_tool_item (GtkAction* action)
933{960{
961 MidoriLocationAction* location_action = MIDORI_LOCATION_ACTION (action);
934 GtkWidget* toolitem;962 GtkWidget* toolitem;
935 GtkWidget* alignment;963 GtkWidget* alignment;
936 GtkWidget* entry;964 GtkWidget* entry;
@@ -953,10 +981,18 @@
953 gtk_entry_set_icon_activatable (GTK_ENTRY (entry),981 gtk_entry_set_icon_activatable (GTK_ENTRY (entry),
954 GTK_ENTRY_ICON_SECONDARY, TRUE);982 GTK_ENTRY_ICON_SECONDARY, TRUE);
955983
956 targetlist = gtk_target_list_new (NULL, 0);984 g_object_set_data (G_OBJECT (entry), "KatzeItem", MIDORI_LOCATION_ACTION (action)->item);
957 gtk_target_list_add_uri_targets (targetlist, 0);985
958 gtk_entry_set_icon_drag_source (GTK_ENTRY (entry), GTK_ENTRY_ICON_PRIMARY, targetlist, GDK_ACTION_ASK | GDK_ACTION_COPY | GDK_ACTION_LINK);986 if (location_action->dnd_targets)
959 gtk_target_list_unref (targetlist);987 gtk_entry_set_icon_drag_source (GTK_ENTRY (entry), GTK_ENTRY_ICON_PRIMARY,
988 location_action->dnd_targets, GDK_ACTION_ASK | GDK_ACTION_COPY | GDK_ACTION_LINK);
989 else
990 {
991 targetlist = gtk_target_list_new (NULL, 0);
992 gtk_target_list_add_uri_targets (targetlist, 0);
993 gtk_entry_set_icon_drag_source (GTK_ENTRY (entry), GTK_ENTRY_ICON_PRIMARY, targetlist, GDK_ACTION_ASK | GDK_ACTION_COPY | GDK_ACTION_LINK);
994 gtk_target_list_unref (targetlist);
995 }
960 g_signal_connect (entry, "drag-data-get",996 g_signal_connect (entry, "drag-data-get",
961 G_CALLBACK (midori_location_action_entry_drag_data_get_cb), action);997 G_CALLBACK (midori_location_action_entry_drag_data_get_cb), action);
962 gtk_widget_show (entry);998 gtk_widget_show (entry);
@@ -1630,6 +1666,38 @@
1630}1666}
16311667
1632/**1668/**
1669 * midori_location_action_set_icon:
1670 * @location_action: a #MidoriLocationAction
1671 * @icon: an icon
1672 *
1673 * Sets the entry icon to @icon.
1674 *
1675 * Since: 0.5.2
1676 **/
1677void
1678midori_location_action_set_icon (MidoriLocationAction* location_action,
1679 const gchar* icon)
1680{
1681 katze_item_set_icon (location_action->item, icon);
1682}
1683
1684/**
1685 * midori_location_action_set_title:
1686 * @location_action: a #MidoriLocationAction
1687 * @text: a string
1688 *
1689 * Sets the entry name to @text.
1690 *
1691 * Since: 0.5.2
1692 **/
1693void
1694midori_location_action_set_title (MidoriLocationAction* location_action,
1695 const gchar* title)
1696{
1697 katze_item_set_name (location_action->item, title);
1698}
1699
1700/**
1633 * midori_location_action_set_text:1701 * midori_location_action_set_text:
1634 * @location_action: a #MidoriLocationAction1702 * @location_action: a #MidoriLocationAction
1635 * @text: a string1703 * @text: a string
16361704
=== modified file 'midori/midori-locationaction.h'
--- midori/midori-locationaction.h 2013-04-16 23:10:10 +0000
+++ midori/midori-locationaction.h 2014-01-26 19:44:25 +0000
@@ -40,6 +40,14 @@
40midori_location_action_get_text (MidoriLocationAction* location_action);40midori_location_action_get_text (MidoriLocationAction* location_action);
4141
42void42void
43midori_location_action_set_icon (MidoriLocationAction* location_action,
44 const gchar* icon);
45
46void
47midori_location_action_set_title (MidoriLocationAction* location_action,
48 const gchar* title);
49
50void
43midori_location_action_set_text (MidoriLocationAction* location_action,51midori_location_action_set_text (MidoriLocationAction* location_action,
44 const gchar* text);52 const gchar* text);
4553
4654
=== modified file 'midori/midori-view.c'
--- midori/midori-view.c 2013-12-09 20:23:03 +0000
+++ midori/midori-view.c 2014-01-26 19:44:25 +0000
@@ -121,6 +121,8 @@
121 GtkWidget* overlay_label;121 GtkWidget* overlay_label;
122 GtkWidget* overlay_find;122 GtkWidget* overlay_find;
123 #endif123 #endif
124
125 GtkTargetList* dnd_targets;
124};126};
125127
126struct _MidoriViewClass128struct _MidoriViewClass
@@ -139,7 +141,8 @@
139 PROP_MINIMIZED,141 PROP_MINIMIZED,
140 PROP_ZOOM_LEVEL,142 PROP_ZOOM_LEVEL,
141 PROP_NEWS_FEEDS,143 PROP_NEWS_FEEDS,
142 PROP_SETTINGS144 PROP_SETTINGS,
145 PROP_DND_TARGETS
143};146};
144147
145enum {148enum {
@@ -379,6 +382,21 @@
379 MIDORI_TYPE_WEB_SETTINGS,382 MIDORI_TYPE_WEB_SETTINGS,
380 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));383 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
381384
385 /**
386 * MidoriView:dnd-targets:
387 *
388 * GtkTargetList* the view supports.
389 *
390 * Since: 0.5.2
391 **/
392 g_object_class_install_property (gobject_class,
393 PROP_DND_TARGETS,
394 g_param_spec_pointer (
395 "dnd-targets",
396 "DNDTargets",
397 "GtkTargetList* the view supports",
398 G_PARAM_READABLE|G_PARAM_WRITABLE));
399
382 #ifdef HAVE_WEBKIT2400 #ifdef HAVE_WEBKIT2
383 WebKitWebContext* context = webkit_web_context_get_default ();401 WebKitWebContext* context = webkit_web_context_get_default ();
384 webkit_web_context_register_uri_scheme (context,402 webkit_web_context_register_uri_scheme (context,
@@ -2983,6 +3001,8 @@
2983 view->news_feeds = NULL;3001 view->news_feeds = NULL;
2984 view->find_links = -1;3002 view->find_links = -1;
2985 view->alerts = 0;3003 view->alerts = 0;
3004 view->dnd_targets = NULL;
3005
29863006
2987 view->item = katze_item_new ();3007 view->item = katze_item_new ();
29883008
@@ -3056,6 +3076,9 @@
3056 case PROP_SETTINGS:3076 case PROP_SETTINGS:
3057 _midori_view_set_settings (view, g_value_get_object (value));3077 _midori_view_set_settings (view, g_value_get_object (value));
3058 break;3078 break;
3079 case PROP_DND_TARGETS:
3080 view->dnd_targets = (GtkTargetList*)g_value_get_pointer (value);
3081 break;
3059 default:3082 default:
3060 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);3083 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3061 break;3084 break;
@@ -3087,6 +3110,9 @@
3087 case PROP_SETTINGS:3110 case PROP_SETTINGS:
3088 g_value_set_object (value, view->settings);3111 g_value_set_object (value, view->settings);
3089 break;3112 break;
3113 case PROP_DND_TARGETS:
3114 g_value_set_pointer (value, view->dnd_targets);
3115 break;
3090 default:3116 default:
3091 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);3117 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3092 break;3118 break;
@@ -4296,6 +4322,89 @@
4296 return new_view;4322 return new_view;
4297}4323}
42984324
4325#if 0
4326static void
4327midori_view_tab_label_data_received (GtkWidget* widget,
4328 GdkDragContext* context,
4329 gint x,
4330 gint y,
4331 GtkSelectionData* data,
4332 guint ttype,
4333 guint timestamp,
4334 MidoriView* view)
4335{
4336 KatzeArray *array;
4337 gchar** uri;
4338
4339 array = katze_array_from_selection_data (data);
4340 if (array)
4341 {
4342 if (katze_array_get_length (array))
4343 {
4344 KatzeItem* item = katze_array_get_nth_item (array, 0);
4345 if (KATZE_ITEM_IS_BOOKMARK (item))
4346 {
4347 midori_view_set_title (view, katze_item_get_name (item));
4348 midori_view_set_uri (view, katze_item_get_uri (item));
4349 }
4350 }
4351
4352 g_object_unref (array);
4353 return;
4354 }
4355
4356 uri = gtk_selection_data_get_uris (data);
4357 if (uri != NULL)
4358 {
4359 midori_view_set_uri (view, uri[0]);
4360 g_strfreev (uri);
4361 }
4362 else
4363 {
4364 gchar* text = (gchar*) gtk_selection_data_get_text (data);
4365 midori_view_set_uri (view, text);
4366 g_free (text);
4367 }
4368}
4369
4370static void
4371midori_view_tab_label_data_get (GtkWidget *widget,
4372 GdkDragContext *drag_context,
4373 GtkSelectionData *data,
4374 guint info,
4375 guint time,
4376 MidoriView* view)
4377{
4378 selection_data_from_katze_item (data, view->item);
4379}
4380
4381static void
4382midori_view_install_tab_dnd (MidoriView* view, GtkWidget* widget)
4383{
4384 g_object_set_data (G_OBJECT (widget), "KatzeItem", view->item)
4385;
4386 gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_ALL, NULL,
4387 0, GDK_ACTION_COPY);
4388 if (view->dnd_targets)
4389 gtk_drag_dest_set_target_list (widget, view->dnd_targets);
4390 gtk_drag_dest_add_text_targets (widget);
4391 gtk_drag_dest_add_uri_targets (widget);
4392 g_signal_connect (widget, "drag-data-received",
4393 G_CALLBACK (midori_view_tab_label_data_received),
4394 view);
4395 if (view->dnd_targets)
4396 {
4397 g_print ("midori_view_get_tab: install source widget\n");
4398 gtk_drag_source_set (widget, GDK_BUTTON1_MASK, NULL, 0,
4399 GDK_ACTION_COPY|GDK_ACTION_LINK);
4400 gtk_drag_source_set_target_list (widget, view->dnd_targets);
4401 g_signal_connect (widget, "drag-data-get",
4402 G_CALLBACK (midori_view_tab_label_data_get),
4403 view);
4404 }
4405}
4406#endif
4407
4299/**4408/**
4300 * midori_view_get_tab_menu:4409 * midori_view_get_tab_menu:
4301 * @view: a #MidoriView4410 * @view: a #MidoriView
43024411
=== modified file 'panels/midori-bookmarks.c'
--- panels/midori-bookmarks.c 2014-01-24 23:04:05 +0000
+++ panels/midori-bookmarks.c 2014-01-26 19:44:25 +0000
@@ -26,6 +26,151 @@
2626
27#define COMPLETION_DELAY 20027#define COMPLETION_DELAY 200
2828
29#define MIDORI_BOOKMARKS_TREE_MODEL_TARGET "GTK_TREE_MODEL_ROW"
30
31G_BEGIN_DECLS
32
33#define MIDORI_BOOKMARKS_TREE_STORE_TYPE \
34 (midori_bookmarks_tree_store_get_type ())
35#define MIDORI_BOOKMARKS_TREE_STORE(obj) \
36 (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_BOOKMARKS_TREE_STORE_TYPE, MidoriBookmarksTreeStore))
37#define MIDORI_BOOKMARKS_TREE_STORE_CLASS(klass) \
38 (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_BOOKMARKS_TREE_STORE_TYPE, MidoriBookmarksTreeStoreClass))
39
40static gboolean
41midori_bookmarks_tree_store_drag_data_get (GtkTreeDragSource* drag_source,
42 GtkTreePath* source_path,
43 GtkSelectionData* selection_data);
44static gboolean
45midori_bookmarks_tree_store_drag_data_delete (GtkTreeDragSource* drag_source,
46 GtkTreePath* source_path);
47static gboolean
48midori_bookmarks_tree_store_row_drop_possible (GtkTreeDragDest *drag_dest,
49 GtkTreePath *dest_path,
50 GtkSelectionData *selection_data);
51static gboolean
52midori_bookmarks_tree_store_drag_data_received (GtkTreeDragDest *drag_dest,
53 GtkTreePath *dest_path,
54 GtkSelectionData *selection_data);
55
56typedef struct _MidoriBookmarksTreeStore MidoriBookmarksTreeStore;
57typedef struct _MidoriBookmarksTreeStoreClass MidoriBookmarksTreeStoreClass;
58typedef struct _TreeRowData TreeRowData;
59
60struct _MidoriBookmarksTreeStore
61{
62 GtkTreeStore parent_instance;
63
64 GList* stock_got_rows;
65 GtkTreeView *_view;
66};
67
68struct _MidoriBookmarksTreeStoreClass
69{
70 GtkTreeStoreClass parent_class;
71};
72
73struct _TreeRowData
74{
75 GtkTreeModel *model;
76 gchar path[4];
77};
78
79static GtkTreeDragSourceIface *
80gtk_tree_store_gtk_tree_drag_source_iface = NULL;
81static GtkTreeDragDestIface *
82gtk_tree_store_gtk_tree_drag_dest_iface = NULL;
83
84static void
85midori_bookmarks_tree_store_drag_source_init (GtkTreeDragSourceIface *iface)
86{
87 gtk_tree_store_gtk_tree_drag_source_iface = g_type_interface_peek_parent (iface);
88
89 iface->drag_data_get = midori_bookmarks_tree_store_drag_data_get;
90 iface->drag_data_delete = midori_bookmarks_tree_store_drag_data_delete;
91}
92
93static void
94midori_bookmarks_tree_store_drag_dest_init (GtkTreeDragDestIface *iface)
95{
96 gtk_tree_store_gtk_tree_drag_dest_iface = g_type_interface_peek_parent (iface);
97
98 iface->row_drop_possible = midori_bookmarks_tree_store_row_drop_possible;
99 iface->drag_data_received = midori_bookmarks_tree_store_drag_data_received;
100}
101
102static void
103midori_bookmarks_tree_store_init (MidoriBookmarksTreeStore* item)
104{
105 item->stock_got_rows = NULL;
106 item->_view = NULL;
107}
108
109static void
110midori_bookmarks_tree_store_class_init (MidoriBookmarksTreeStoreClass *class)
111{
112}
113
114G_DEFINE_TYPE_WITH_CODE (MidoriBookmarksTreeStore,
115 midori_bookmarks_tree_store,
116 GTK_TYPE_TREE_STORE,
117 G_IMPLEMENT_INTERFACE (
118 GTK_TYPE_TREE_DRAG_SOURCE,
119 midori_bookmarks_tree_store_drag_source_init)
120 G_IMPLEMENT_INTERFACE (
121 GTK_TYPE_TREE_DRAG_DEST,
122 midori_bookmarks_tree_store_drag_dest_init));
123
124
125GtkTreeStore*
126midori_bookmarks_tree_store_new (gint n_columns, ...)
127{
128 GtkTreeStore* tree_store = GTK_TREE_STORE (g_object_new (MIDORI_BOOKMARKS_TREE_STORE_TYPE, NULL));
129 va_list ap;
130 GType* types;
131 gint n;
132
133 if (!tree_store)
134 return NULL;
135
136 types = g_new (GType, n_columns);
137
138 if (!types)
139 {
140 g_object_unref(tree_store);
141 return NULL;
142 }
143
144 va_start(ap, n_columns);
145 for (n = 0; n < n_columns; n++)
146 {
147 types[n] = va_arg(ap, GType);
148 }
149 va_end(ap);
150
151 gtk_tree_store_set_column_types (tree_store,
152 n_columns,
153 types);
154
155 g_free (types);
156 return tree_store;
157}
158
159GtkTreeStore*
160midori_bookmarks_tree_store_newv (gint n_columns, GType *types)
161{
162 GtkTreeStore* tree_store = GTK_TREE_STORE (g_object_new (MIDORI_BOOKMARKS_TREE_STORE_TYPE, NULL));
163
164 if (!tree_store)
165 return NULL;
166
167 gtk_tree_store_set_column_types (tree_store,
168 n_columns,
169 types);
170
171 return tree_store;
172}
173
29gboolean174gboolean
30midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser,175midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser,
31 KatzeItem* bookmark_or_parent,176 KatzeItem* bookmark_or_parent,
@@ -37,6 +182,12 @@
37midori_browser_open_bookmark (MidoriBrowser* browser,182midori_browser_open_bookmark (MidoriBrowser* browser,
38 KatzeItem* item);183 KatzeItem* item);
39184
185static void
186midori_bookmarks_row_changed_cb (GtkTreeModel* model,
187 GtkTreePath* path,
188 GtkTreeIter* iter,
189 MidoriBookmarks* bookmarks);
190
40struct _MidoriBookmarks191struct _MidoriBookmarks
41{192{
42 GtkVBox parent_instance;193 GtkVBox parent_instance;
@@ -50,7 +201,19 @@
50 gint filter_timeout;201 gint filter_timeout;
51 gchar* filter;202 gchar* filter;
52203
204 GList* pending_inserts;
53 KatzeItem* hovering_item;205 KatzeItem* hovering_item;
206
207 struct _stock_pending_event
208 {
209 gint x;
210 gint y;
211 } *pending_event,
212 stock_pending_event;
213
214 GHashTable* updated_items;
215 GList* added_paths;
216 GList* reordered_paths;
54};217};
55218
56struct _MidoriBookmarksClass219struct _MidoriBookmarksClass
@@ -88,36 +251,47 @@
88 GParamSpec* pspec);251 GParamSpec* pspec);
89252
90static void253static void
91midori_bookmarks_row_changed_cb (GtkTreeModel* model,254midori_bookmarks_update_cb (KatzeArray* array,
92 GtkTreePath* path,255 MidoriBookmarks* bookmarks);
93 GtkTreeIter* iter,
94 MidoriBookmarks* bookmarks);
95
96static void256static void
97midori_bookmarks_add_item_cb (KatzeArray* array,257midori_bookmarks_add_item_cb (KatzeArray* array,
98 KatzeItem* item,258 KatzeItem* item,
99 MidoriBookmarks* bookmarks);259 MidoriBookmarks* bookmarks);
100
101static void260static void
102midori_bookmarks_update_item_cb (KatzeArray* array,261midori_bookmarks_update_item_cb (KatzeArray* array,
103 KatzeItem* item,262 KatzeItem* item,
104 MidoriBookmarks* bookmarks);263 MidoriBookmarks* bookmarks);
105
106static void264static void
107midori_bookmarks_remove_item_cb (KatzeArray* array,265midori_bookmarks_remove_item_cb (KatzeArray* array,
108 KatzeItem* item,266 KatzeItem* item,
109 MidoriBookmarks* bookmarks);267 MidoriBookmarks* bookmarks);
110268
111static void269static void
112midori_bookmarks_update_cb (KatzeArray* array,270midori_bookmarks_row_inserted_cb (GtkTreeModel* model,
113 MidoriBookmarks* bookmarks);271 GtkTreePath* path,
272 GtkTreeIter* iter,
273 MidoriBookmarks* bookmarks);
274static void
275midori_bookmarks_row_changed_cb (GtkTreeModel* model,
276 GtkTreePath* path,
277 GtkTreeIter* iter,
278 MidoriBookmarks* bookmarks);
279static void
280midori_bookmarks_row_deleted_cb (GtkTreeModel* model,
281 GtkTreePath* path,
282 MidoriBookmarks* bookmarks);
283
284static void
285midori_bookmarks_update_item (MidoriBookmarks* bookmarks, KatzeItem *item);
114286
115static void287static void
116midori_bookmarks_statusbar_update (MidoriBookmarks *bookmarks);288midori_bookmarks_statusbar_update (MidoriBookmarks *bookmarks);
117289
118static void290static void
119midori_bookmarks_add_item (KatzeItem* item,291midori_bookmarks_idle_remove_item (MidoriBookmarks* bookmarks, KatzeItem *item);
120 MidoriBookmarks* bookmarks);292
293static gboolean
294midori_bookmarks_idle_func (gpointer data);
121295
122static void296static void
123midori_bookmarks_class_init (MidoriBookmarksClass* class)297midori_bookmarks_class_init (MidoriBookmarksClass* class)
@@ -133,13 +307,13 @@
133 flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;307 flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
134308
135 g_object_class_install_property (gobject_class,309 g_object_class_install_property (gobject_class,
136 PROP_APP,310 PROP_APP,
137 g_param_spec_object (311 g_param_spec_object (
138 "app",312 "app",
139 "App",313 "App",
140 "The app",314 "The app",
141 MIDORI_TYPE_APP,315 MIDORI_TYPE_APP,
142 flags));316 flags));
143}317}
144318
145static const gchar*319static const gchar*
@@ -168,7 +342,7 @@
168 gchar* parent_id;342 gchar* parent_id;
169343
170 parent_id = g_strdup_printf ("%" G_GINT64_FORMAT, parentid);344 parent_id = g_strdup_printf ("%" G_GINT64_FORMAT, parentid);
171 if (!(root_array = midori_bookmarks_db_query_recursive (array, "*", "parentid = %q", parent_id, FALSE)))345 if (!(root_array = midori_bookmarks_db_query_recursive (array, "*", "parentid = %q", parent_id, "(uri='') ASC, pos_panel DESC", FALSE)))
172 {346 {
173 g_free (parent_id);347 g_free (parent_id);
174 return;348 return;
@@ -180,7 +354,7 @@
180 subarray = katze_array_new (KATZE_TYPE_ARRAY);354 subarray = katze_array_new (KATZE_TYPE_ARRAY);
181 katze_item_set_name (KATZE_ITEM (subarray), katze_item_get_name (item));355 katze_item_set_name (KATZE_ITEM (subarray), katze_item_get_name (item));
182 midori_bookmarks_export_array_db (db, subarray,356 midori_bookmarks_export_array_db (db, subarray,
183 katze_item_get_meta_integer (item, "parentid"));357 katze_item_get_meta_integer (item, "parentid"));
184 katze_array_add_item (array, subarray);358 katze_array_add_item (array, subarray);
185 }359 }
186 else360 else
@@ -201,20 +375,20 @@
201375
202 if (keyword && *keyword)376 if (keyword && *keyword)
203 array = midori_bookmarks_db_query_recursive (bookmarks->bookmarks_db,377 array = midori_bookmarks_db_query_recursive (bookmarks->bookmarks_db,
204 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "title LIKE '%%%q%%'", keyword, FALSE);378 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "title LIKE '%%%q%%'", keyword, NULL, FALSE);
205 else379 else
206 {380 {
207 if (parentid > 0)381 if (parentid > 0)
208 {382 {
209 gchar* parent_id = g_strdup_printf ("%" G_GINT64_FORMAT, parentid);383 gchar* parent_id = g_strdup_printf ("%" G_GINT64_FORMAT, parentid);
210 array = midori_bookmarks_db_query_recursive (bookmarks->bookmarks_db,384 array = midori_bookmarks_db_query_recursive (bookmarks->bookmarks_db,
211 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "parentid = %q", parent_id, FALSE);385 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "parentid = %q", parent_id, "(uri='') ASC, pos_panel DESC", FALSE);
212386
213 g_free (parent_id);387 g_free (parent_id);
214 }388 }
215 else389 else
216 array = midori_bookmarks_db_query_recursive (bookmarks->bookmarks_db,390 array = midori_bookmarks_db_query_recursive (bookmarks->bookmarks_db,
217 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "parentid IS NULL", NULL, FALSE);391 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "parentid IS NULL", NULL, "(uri='') ASC, pos_panel DESC", FALSE);
218 }392 }
219 return array ? array : katze_array_new (KATZE_TYPE_ITEM);393 return array ? array : katze_array_new (KATZE_TYPE_ITEM);
220}394}
@@ -231,24 +405,52 @@
231 KatzeItem* item;405 KatzeItem* item;
232 GtkTreeIter child;406 GtkTreeIter child;
233407
408 g_signal_handlers_block_by_func (model,
409 midori_bookmarks_row_changed_cb,
410 bookmarks);
411
234 array = midori_bookmarks_read_from_db (bookmarks, parentid, keyword);412 array = midori_bookmarks_read_from_db (bookmarks, parentid, keyword);
235 katze_bookmark_populate_tree_view (array, model, parent);413 katze_bookmark_populate_tree_view (array, model, parent);
414
415 g_signal_handlers_unblock_by_func (model,
416 midori_bookmarks_row_changed_cb,
417 bookmarks);
418
236 /* Remove invisible dummy row */419 /* Remove invisible dummy row */
237 last = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), parent);420 last = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), parent);
238 if (!last)421 if (!last)
239 return;422 return;
423
424 g_signal_handlers_block_by_func (model,
425 midori_bookmarks_row_deleted_cb,
426 bookmarks);
427
240 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (model), &child, parent, last - 1);428 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (model), &child, parent, last - 1);
241 gtk_tree_model_get (GTK_TREE_MODEL (model), &child, 0, &item, -1);429 gtk_tree_model_get (GTK_TREE_MODEL (model), &child, 0, &item, -1);
242 if (KATZE_ITEM_IS_SEPARATOR (item))430 if (KATZE_ITEM_IS_SEPARATOR (item))
243 gtk_tree_store_remove (model, &child);431 gtk_tree_store_remove (model, &child);
244 else432 else
245 g_object_unref (item);433 g_object_unref (item);
434
435 g_signal_handlers_unblock_by_func (model,
436 midori_bookmarks_row_deleted_cb,
437 bookmarks);
438
246}439}
247440
441static void
442midori_bookmarks_add_item (KatzeItem* item,
443 MidoriBookmarks* bookmarks);
444
445static void
446add_parent_to_reorder (GtkTreeModel* model,
447 GtkTreePath* path,
448 MidoriBookmarks* bookmarks);
449
248static gboolean450static gboolean
249midori_bookmarks_reach_item_recurse (GtkTreeModel* model,451midori_bookmarks_reach_item_recurse (GtkTreeModel* model,
250 GtkTreeIter* iter,452 GtkTreeIter* iter,
251 gint64 id)453 gint64 id)
252{454{
253 do455 do
254 {456 {
@@ -258,7 +460,7 @@
258460
259 gtk_tree_model_get (model, iter, 0, &item, -1);461 gtk_tree_model_get (model, iter, 0, &item, -1);
260462
261 if (!KATZE_ITEM_IS_SEPARATOR(item))463 if (item)
262 {464 {
263 itemid = katze_item_get_meta_integer (item, "id");465 itemid = katze_item_get_meta_integer (item, "id");
264 g_object_unref (item);466 g_object_unref (item);
@@ -267,13 +469,11 @@
267 if (id == itemid)469 if (id == itemid)
268 return TRUE;470 return TRUE;
269471
270 if (gtk_tree_model_iter_children (model, &child, iter))472 if (gtk_tree_model_iter_children (model, &child, iter)
473 && midori_bookmarks_reach_item_recurse (model, &child, id))
271 {474 {
272 if (midori_bookmarks_reach_item_recurse (model, &child, id))475 *iter = child;
273 {476 return TRUE;
274 *iter = child;
275 return TRUE;
276 }
277 }477 }
278 }478 }
279 while (gtk_tree_model_iter_next(model, iter));479 while (gtk_tree_model_iter_next(model, iter));
@@ -283,8 +483,8 @@
283483
284static gboolean484static gboolean
285midori_bookmarks_reach_item (GtkTreeModel* model,485midori_bookmarks_reach_item (GtkTreeModel* model,
286 GtkTreeIter* iter,486 GtkTreeIter* iter,
287 gint64 id)487 gint64 id)
288{488{
289 if (!gtk_tree_model_get_iter_first(model, iter))489 if (!gtk_tree_model_get_iter_first(model, iter))
290 return FALSE;490 return FALSE;
@@ -293,38 +493,73 @@
293}493}
294494
295static void495static void
296midori_bookmarks_add_item_to_model(GtkTreeStore* model,496midori_bookmarks_add_item_to_model(MidoriBookmarks* bookmarks,
297 GtkTreeIter* parent,497 GtkTreeModel* model,
298 KatzeItem* item)498 GtkTreeIter* parent,
499 KatzeItem* item)
299{500{
501 GtkTreeStore* tree_store = GTK_TREE_STORE (model);
502 gint last;
503 GtkTreeIter child;
504
300 if (KATZE_ITEM_IS_BOOKMARK (item))505 if (KATZE_ITEM_IS_BOOKMARK (item))
301 {506 {
507 gint position = 0;
508
509 /* skip the folders to be consistent with the db query order */
510 if (gtk_tree_model_iter_children (model, &child, parent))
511 while (gtk_tree_model_iter_has_child (model, &child))
512 {
513 position++;
514 if (!gtk_tree_model_iter_next (model, &child))
515 break;
516 }
517
302 gchar* tooltip = g_markup_escape_text (katze_item_get_uri (item), -1);518 gchar* tooltip = g_markup_escape_text (katze_item_get_uri (item), -1);
303519
304 gtk_tree_store_insert_with_values (model, NULL, parent,520 gtk_tree_store_insert_with_values (tree_store, NULL, parent,
305 0,521 position,
306 0, item, 1, tooltip, -1);522 0, item, 1, tooltip, -1);
307 g_free (tooltip);523 g_free (tooltip);
308 }524 }
309 else525 else if (KATZE_ITEM_IS_FOLDER (item))
310 {526 {
311 GtkTreeIter root_iter;527 GtkTreeIter root_iter;
312528
313 gtk_tree_store_insert_with_values (model, &root_iter, parent,529 gtk_tree_store_insert_with_values (tree_store, &root_iter, parent,
314 0, 0, item, -1);530 0, 0, item, -1);
315531
316 /* That's an invisible dummy, so we always have an expander */532 /* That's an invisible dummy, so we always have an expander */
317 gtk_tree_store_insert_with_values (model, NULL, &root_iter,533 gtk_tree_store_insert_with_values (tree_store, NULL, &root_iter,
318 0,534 0, 0, NULL, -1);
319 0, NULL, -1);
320 }535 }
536
537 /* Remove invisible dummy row */
538 last = gtk_tree_model_iter_n_children (model, parent);
539 if (!last)
540 return;
541
542 g_signal_handlers_block_by_func (model,
543 midori_bookmarks_row_deleted_cb,
544 bookmarks);
545
546 gtk_tree_model_iter_nth_child (model, &child, parent, last - 1);
547 gtk_tree_model_get (model, &child, 0, &item, -1);
548 if (KATZE_ITEM_IS_SEPARATOR (item))
549 gtk_tree_store_remove (tree_store, &child);
550 else
551 g_object_unref (item);
552
553 g_signal_handlers_unblock_by_func (model,
554 midori_bookmarks_row_deleted_cb,
555 bookmarks);
321}556}
322557
323static void558static void
324midori_bookmarks_update_item_in_model(MidoriBookmarks* bookmarks,559midori_bookmarks_update_item_in_model(MidoriBookmarks* bookmarks,
325 GtkTreeStore* model,560 GtkTreeStore* model,
326 GtkTreeIter* iter,561 GtkTreeIter* iter,
327 KatzeItem* item)562 KatzeItem* item)
328{563{
329 g_signal_handlers_block_by_func (model,564 g_signal_handlers_block_by_func (model,
330 midori_bookmarks_row_changed_cb,565 midori_bookmarks_row_changed_cb,
@@ -350,18 +585,48 @@
350 bookmarks);585 bookmarks);
351}586}
352587
588static gboolean
589midori_bookmarks_idle_pending (MidoriBookmarks* bookmarks)
590{
591 if (bookmarks->pending_inserts
592 || bookmarks->added_paths
593 || bookmarks->reordered_paths
594 || g_hash_table_size (bookmarks->updated_items))
595 return TRUE;
596 return FALSE;
597}
598
599/**
600 * midori_bookmarks_idle_start:
601 * @bookmarks: the bookmarks panel
602 *
603 * Internal function that checks whether idle processing is pending,
604 * if not, add a new one.
605 **/
606static void
607midori_bookmarks_idle_start (MidoriBookmarks* bookmarks)
608{
609 if (midori_bookmarks_idle_pending (bookmarks))
610 return;
611
612 g_idle_add (midori_bookmarks_idle_func, bookmarks);
613}
614
353static void615static void
354midori_bookmarks_add_item (KatzeItem* item,616midori_bookmarks_add_item (KatzeItem* item,
355 MidoriBookmarks* bookmarks);617 MidoriBookmarks* bookmarks);
618
356static void619static void
357midori_bookmarks_add_item_cb (KatzeArray* array,620midori_bookmarks_add_item_cb (KatzeArray* array,
358 KatzeItem* item,621 KatzeItem* item,
359 MidoriBookmarks* bookmarks)622 MidoriBookmarks* bookmarks)
360{623{
361 midori_bookmarks_add_item (item, bookmarks);624 midori_bookmarks_idle_start (bookmarks);
625
626 g_object_ref (item);
627 bookmarks->pending_inserts = g_list_append (bookmarks->pending_inserts, item);
362}628}
363629
364
365static void630static void
366midori_bookmarks_add_item (KatzeItem* item,631midori_bookmarks_add_item (KatzeItem* item,
367 MidoriBookmarks* bookmarks)632 MidoriBookmarks* bookmarks)
@@ -370,18 +635,16 @@
370 GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));635 GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));
371 GtkTreeIter iter;636 GtkTreeIter iter;
372637
373 if (!parentid)638 if (parentid == katze_item_get_meta_integer (KATZE_ITEM (bookmarks->bookmarks_db), "id"))
374 {639 midori_bookmarks_add_item_to_model (bookmarks, model, NULL, item);
375 midori_bookmarks_add_item_to_model (GTK_TREE_STORE (model), NULL, item);
376 }
377 else if (midori_bookmarks_reach_item (model, &iter, parentid))640 else if (midori_bookmarks_reach_item (model, &iter, parentid))
378 {641 {
379 GtkTreePath* path = gtk_tree_model_get_path(model, &iter);642 GtkTreePath* path = gtk_tree_model_get_path(model, &iter);
643 gint n_children = gtk_tree_model_iter_n_children (model, &iter);
380644
381 if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (bookmarks->treeview), path))645 if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (bookmarks->treeview), path)
382 {646 || !n_children)
383 midori_bookmarks_add_item_to_model (GTK_TREE_STORE (model), &iter, item);647 midori_bookmarks_add_item_to_model (bookmarks, model, &iter, item);
384 }
385648
386 gtk_tree_path_free (path);649 gtk_tree_path_free (path);
387 }650 }
@@ -389,8 +652,8 @@
389652
390static void653static void
391midori_bookmarks_update_item_cb (KatzeArray* array,654midori_bookmarks_update_item_cb (KatzeArray* array,
392 KatzeItem* item,655 KatzeItem* item,
393 MidoriBookmarks* bookmarks)656 MidoriBookmarks* bookmarks)
394{657{
395 gint64 id = katze_item_get_meta_integer (item, "id");658 gint64 id = katze_item_get_meta_integer (item, "id");
396 gint64 parentid = katze_item_get_meta_integer (item, "parentid");659 gint64 parentid = katze_item_get_meta_integer (item, "parentid");
@@ -433,7 +696,7 @@
433 midori_bookmarks_add_item (item, bookmarks);696 midori_bookmarks_add_item (item, bookmarks);
434 }697 }
435 }698 }
436 else if (parentid == 0)699 else if (parentid == katze_item_get_meta_integer (KATZE_ITEM (bookmarks->bookmarks_db), "id"))
437 {700 {
438 midori_bookmarks_update_item_in_model (bookmarks, GTK_TREE_STORE (model), &iter, item);701 midori_bookmarks_update_item_in_model (bookmarks, GTK_TREE_STORE (model), &iter, item);
439 }702 }
@@ -457,6 +720,10 @@
457 GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));720 GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));
458 GtkTreeIter iter;721 GtkTreeIter iter;
459722
723 g_assert (KATZE_IS_ITEM (item));
724
725 midori_bookmarks_idle_remove_item (bookmarks, item);
726
460 if (midori_bookmarks_reach_item (model, &iter, id))727 if (midori_bookmarks_reach_item (model, &iter, id))
461 {728 {
462 GtkTreeIter parent;729 GtkTreeIter parent;
@@ -486,12 +753,869 @@
486midori_bookmarks_update_cb (KatzeArray* array,753midori_bookmarks_update_cb (KatzeArray* array,
487 MidoriBookmarks* bookmarks)754 MidoriBookmarks* bookmarks)
488{755{
756#if 1
757 g_print ("midori_bookmarks_update_cb: ignored ********\n");
758#else
489 GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));759 GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));
760
490 gtk_tree_store_clear (GTK_TREE_STORE (model));761 gtk_tree_store_clear (GTK_TREE_STORE (model));
491 midori_bookmarks_read_from_db_to_model (bookmarks,762 midori_bookmarks_read_from_db_to_model (bookmarks,
492 GTK_TREE_STORE (model), NULL, 0, bookmarks->filter);763 GTK_TREE_STORE (model), NULL, 0, bookmarks->filter);
493}764#endif
494765}
766
767gboolean
768midori_bookmarks_tree_set_row_drag_data (GtkSelectionData *selection_data,
769 GtkTreeModel *tree_model,
770 GList* rows)
771{
772 TreeRowData *trd;
773 gint len;
774 gint struct_size;
775 gint length;
776 gint i;
777 GString *data;
778
779 g_return_val_if_fail (selection_data != NULL, FALSE);
780 g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
781 g_return_val_if_fail (rows != NULL, FALSE);
782
783 data = g_string_new("");
784
785 length = g_list_length (rows);
786 for (i = 0; i < length; i++)
787 {
788 GtkTreePath *path = (GtkTreePath *)g_list_nth_data (rows, i);
789 gchar *path_str = gtk_tree_path_to_string (path);
790
791 g_string_append (data, path_str);
792 if (i < length-1)
793 g_string_append_c (data, '\n');
794 }
795
796 len = data->len;
797
798 /* the old allocate-end-of-struct-to-hold-string trick */
799 struct_size = sizeof (TreeRowData) + len + 1 -
800 (sizeof (TreeRowData) - G_STRUCT_OFFSET (TreeRowData, path));
801
802 trd = g_malloc (struct_size);
803
804 strcpy (trd->path, data->str);
805
806 g_string_free (data, TRUE);
807
808 trd->model = tree_model;
809
810 gtk_selection_data_set (selection_data,
811 gdk_atom_intern_static_string (MIDORI_BOOKMARKS_TREE_MODEL_TARGET),
812 8, /* bytes */
813 (void*)trd,
814 struct_size);
815
816 g_free (trd);
817
818 return TRUE;
819}
820
821static gboolean
822midori_bookmarks_tree_store_drag_data_get (GtkTreeDragSource* drag_source,
823 GtkTreePath* source_path,
824 GtkSelectionData* selection_data)
825{
826 MidoriBookmarksTreeStore *tree_store;
827 gboolean status = FALSE;
828
829 g_return_val_if_fail (selection_data != NULL, FALSE);
830 g_return_val_if_fail (GTK_IS_TREE_MODEL (drag_source), FALSE);
831 g_return_val_if_fail (source_path != NULL, FALSE);
832
833 tree_store = MIDORI_BOOKMARKS_TREE_STORE(drag_source);
834
835 if (tree_store->stock_got_rows)
836 {
837 g_list_free_full (tree_store->stock_got_rows, (GDestroyNotify) gtk_tree_path_free);
838 tree_store->stock_got_rows = NULL;
839 }
840
841 if (gtk_selection_data_get_target (selection_data) ==
842 gdk_atom_intern_static_string (MIDORI_BOOKMARKS_TREE_MODEL_TARGET))
843 {
844 GtkTreeModel *model;
845 GList* rows;
846 if (katze_tree_view_get_selected_rows (
847 tree_store->_view, &model, &rows))
848 {
849 status = midori_bookmarks_tree_set_row_drag_data (selection_data, model, rows);
850
851 tree_store->stock_got_rows = rows;
852 }
853 }
854
855 return status;
856}
857
858static void
859update_path_list_for_insert (GList * rows, GtkTreePath* path)
860{
861 gint length = g_list_length (rows);
862 gint i;
863
864 for (i = 0; i < length; i++ )
865 {
866 GtkTreePath *src_path_r = (GtkTreePath *)g_list_nth_data (rows, i);
867 gint la = gtk_tree_path_get_depth (path);
868 gint lb = gtk_tree_path_get_depth (src_path_r);
869 gint *ia = gtk_tree_path_get_indices (path);
870 gint *ib = gtk_tree_path_get_indices (src_path_r);
871 gint j;
872
873 if (la > lb) /* insert was donne in a deeper branch than source */
874 continue;
875
876 if (ia[la-1] > ib[la-1]) /* insert was donne after source */
877 continue;
878
879 for (j = 0; j < la; j++)
880 {
881 if (ia[j] != ib[j]) break;
882 }
883
884 if (j < la-1) /* insert and source are not in the same branch */
885 continue;
886
887 /* source at depth level of insert must be incremented due to the insert */
888 ib[la-1] += 1;
889 }
890}
891
892static gint
893midori_tree_path_compare (const GtkTreePath *a,
894 const GtkTreePath *b)
895{
896 if (!gtk_tree_path_get_depth ((GtkTreePath *)a))
897 {
898 if (!gtk_tree_path_get_depth ((GtkTreePath *)b))
899 return 0;
900
901 return -1;
902 }
903
904 if (!gtk_tree_path_get_depth ((GtkTreePath *)b))
905 return 1;
906
907 return gtk_tree_path_compare (a, b);
908}
909
910static GList*
911update_path_list_for_delete (GList* rows, GtkTreePath* removed_path)
912{
913 GList* new_rows = rows;
914
915 while (rows)
916 {
917 GtkTreePath *source_path = (GtkTreePath *)rows->data;
918 gint la = gtk_tree_path_get_depth (removed_path);
919 gint lb = gtk_tree_path_get_depth (source_path);
920 gint *ia = gtk_tree_path_get_indices (removed_path);
921 gint *ib = gtk_tree_path_get_indices (source_path);
922 gint cmp = midori_tree_path_compare (removed_path, source_path);
923 gint j;
924
925 if (cmp == 1) /* removal was done after source => kip source as it is */
926 goto keep_source;
927
928 if (cmp == 0) /* source is removed => remove source */
929 goto remove_source;
930
931 /* if removal is an ancestor of the source => remove source */
932 if (gtk_tree_path_is_ancestor (removed_path, source_path))
933 goto remove_source;
934
935 if (la > lb) /* removal was donne in a deeper branch than source */
936 goto keep_source;
937
938 for (j = 0; j < la; j++)
939 {
940 if (ia[j] != ib[j]) break;
941 }
942
943 if (j < la-1) /* removal and source are not in the same branch */
944 goto keep_source;
945
946 /* source at depth level of removal must be decremented due to the removal */
947 ib[la-1] -= 1;
948
949 if (ib[la-1] >= 0)
950 goto keep_source;
951
952 remove_source:
953 /* remove source entry */
954 gtk_tree_path_free (source_path);
955 {
956 GList *next_rows = g_list_next (rows);
957 new_rows = g_list_delete_link (new_rows, rows);
958 rows = next_rows;
959 }
960 continue;
961
962 keep_source:
963 rows = g_list_next (rows);
964 }
965
966 return new_rows;
967}
968
969static gboolean
970midori_bookmarks_tree_store_drag_data_delete (GtkTreeDragSource* drag_source,
971 GtkTreePath* source_path)
972{
973 gboolean status = TRUE;
974 MidoriBookmarksTreeStore *tree_store = MIDORI_BOOKMARKS_TREE_STORE(drag_source);
975 GtkTreeModel* model = GTK_TREE_MODEL(drag_source);
976
977 if (!tree_store->stock_got_rows)
978 return TRUE;
979
980 while (tree_store->stock_got_rows)
981 {
982 GtkTreePath *prev = (GtkTreePath *)tree_store->stock_got_rows->data;
983 GtkTreeIter iter;
984
985 tree_store->stock_got_rows = g_list_delete_link (tree_store->stock_got_rows,
986 tree_store->stock_got_rows);
987
988 if (gtk_tree_model_get_iter (model, &iter, prev))
989 {
990 /* remove item updating source paths */
991 gtk_tree_store_remove (GTK_TREE_STORE (drag_source), &iter);
992
993 tree_store->stock_got_rows = update_path_list_for_delete (tree_store->stock_got_rows, prev);
994 }
995 else
996 status = FALSE;
997
998 gtk_tree_path_free (prev);
999 }
1000
1001 return status;
1002}
1003
1004static gboolean
1005midori_bookmarks_tree_store_get_rows_drag_data (GtkSelectionData *selection_data,
1006 GtkTreeModel **tree_model,
1007 GList **rows)
1008{
1009 TreeRowData *trd;
1010
1011 g_return_val_if_fail (selection_data != NULL, FALSE);
1012
1013 if (tree_model)
1014 *tree_model = NULL;
1015
1016 if (rows)
1017 *rows = NULL;
1018
1019 if (gtk_selection_data_get_target (selection_data) !=
1020 gdk_atom_intern_static_string (MIDORI_BOOKMARKS_TREE_MODEL_TARGET))
1021 return FALSE;
1022
1023 if (gtk_selection_data_get_length (selection_data) < 0)
1024 return FALSE;
1025
1026 trd = (void*) gtk_selection_data_get_data (selection_data);
1027
1028 if (tree_model)
1029 *tree_model = trd->model;
1030
1031 if (rows)
1032 {
1033 GList *list = NULL;
1034 gchar *trd_path = g_strdup (trd->path);
1035 gchar *path_str;
1036
1037 path_str = strtok(trd_path, "\n");
1038 while (path_str && *path_str)
1039 {
1040 list = g_list_append (list, gtk_tree_path_new_from_string (path_str));
1041 path_str = strtok (NULL, "\n");
1042 }
1043
1044 *rows = list;
1045 g_free (trd_path);
1046 }
1047
1048 return TRUE;
1049}
1050
1051#if !GTK_CHECK_VERSION (3,0,0)
1052gboolean
1053gtk_tree_model_iter_previous (GtkTreeModel *tree_model,
1054 GtkTreeIter *iter)
1055{
1056 GtkTreePath* path = gtk_tree_model_get_path (tree_model, iter);
1057 gboolean result = gtk_tree_path_prev (path);
1058
1059 if (result)
1060 result = gtk_tree_model_get_iter (tree_model, iter, path);
1061 else
1062 {
1063 GtkTreeIter invalid = {0};
1064 *iter = invalid;
1065 }
1066
1067 gtk_tree_path_free (path);
1068 return result;
1069}
1070#endif
1071
1072static gboolean
1073midori_bookmarks_tree_store_row_drop_possible (GtkTreeDragDest* drag_dest,
1074 GtkTreePath* dest_path,
1075 GtkSelectionData* selection_data)
1076{
1077 GtkTreeModel* dest_model = GTK_TREE_MODEL(drag_dest);
1078 GtkTreePath *parent;
1079 GtkTreeIter dest_parent;
1080 GtkTreeIter *dest_parent_p = NULL;
1081 gboolean row_drop_possible = TRUE;
1082 GtkTreeViewDropPosition drop_position;
1083
1084 gtk_tree_view_get_drag_dest_row (MIDORI_BOOKMARKS_TREE_STORE (dest_model)->_view,
1085 NULL, &drop_position);
1086
1087 parent = gtk_tree_path_copy (dest_path);
1088 if ((gtk_tree_path_get_depth (parent) > 1)
1089 && gtk_tree_path_up (parent)
1090 && gtk_tree_model_get_iter (dest_model, &dest_parent, parent))
1091 dest_parent_p = &dest_parent;
1092
1093 gtk_tree_path_free (parent);
1094
1095 if (dest_parent_p)
1096 {
1097 KatzeItem* item;
1098
1099 gtk_tree_model_get (dest_model, dest_parent_p, 0, &item, -1);
1100
1101 if (!KATZE_ITEM_IS_FOLDER (item))
1102 {
1103#ifdef DEBUG_DROP
1104 gchar *dest_path_str = gtk_tree_path_to_string (dest_path);
1105
1106 g_print ("%s: can only drop into folders\n", dest_path_str);
1107 g_free (dest_path_str);
1108#endif /* DEBUG_DROP */
1109 row_drop_possible = FALSE;
1110 }
1111
1112 if (item)
1113 g_object_unref (item);
1114 }
1115
1116 if (row_drop_possible
1117 && (gtk_selection_data_get_target (selection_data) ==
1118 gdk_atom_intern_static_string (MIDORI_BOOKMARKS_TREE_MODEL_TARGET)))
1119 {
1120 GtkTreeModel *src_model;
1121 GList* rows;
1122
1123 if (midori_bookmarks_tree_store_get_rows_drag_data (selection_data,
1124 &src_model, &rows))
1125 {
1126 GtkTreeIter dest_iter;
1127 GList* src_row;
1128 gboolean dest_is_folder = FALSE;
1129 /* gboolean dest_is_bookmark = FALSE; */
1130 gboolean src_has_folders = FALSE;
1131 gboolean src_has_bookmarks = FALSE;
1132
1133 if (gtk_tree_model_get_iter (dest_model, &dest_iter, dest_path))
1134 {
1135 if (gtk_tree_model_iter_has_child (dest_model, &dest_iter))
1136 dest_is_folder = TRUE;
1137/*
1138 else
1139 {
1140 KatzeItem* item;
1141 gtk_tree_model_get (dest_model, &dest_iter, 0, &item, -1);
1142 if (item)
1143 {
1144 dest_is_bookmark = TRUE;
1145 g_object_unref (item);
1146 }
1147 }
1148*/
1149 }
1150
1151 for (src_row = rows ; src_row ; src_row = g_list_next (src_row))
1152 {
1153 GtkTreePath* src_path = (GtkTreePath*)src_row->data;
1154 GtkTreeIter src_iter;
1155 KatzeItem* item;
1156
1157 if (!gtk_tree_model_get_iter (src_model, &src_iter, src_path))
1158 continue;
1159
1160 gtk_tree_model_get (src_model, &src_iter, 0, &item, -1);
1161 if (item)
1162 {
1163 if (!src_has_folders && KATZE_ITEM_IS_FOLDER (item))
1164 src_has_folders = TRUE;
1165 else if (!src_has_bookmarks && KATZE_ITEM_IS_BOOKMARK (item))
1166 src_has_bookmarks = TRUE;
1167
1168 g_object_unref (item);
1169 }
1170 if (src_has_bookmarks && src_has_folders)
1171 break;
1172 }
1173
1174 if (src_has_bookmarks)
1175 {
1176 switch (drop_position)
1177 {
1178 case GTK_TREE_VIEW_DROP_BEFORE:
1179 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
1180 if (dest_is_folder)
1181 {
1182#ifdef DEBUG_DROP
1183 gchar *dest_path_str = gtk_tree_path_to_string (dest_path);
1184
1185 g_print ("%s: cannot drop bookmarks in folders group\n", dest_path_str);
1186 g_free (dest_path_str);
1187#endif /* DEBUG_DROP */
1188 row_drop_possible = FALSE;
1189 goto done;
1190 }
1191 break;
1192 case GTK_TREE_VIEW_DROP_AFTER:
1193 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
1194 if (dest_is_folder)
1195 {
1196 gboolean next_dest_is_folder = FALSE;
1197
1198 if (gtk_tree_model_iter_next (dest_model, &dest_iter))
1199 if (gtk_tree_model_iter_has_child (dest_model, &dest_iter))
1200 next_dest_is_folder = TRUE;
1201
1202 if (next_dest_is_folder)
1203 {
1204#ifdef DEBUG_DROP
1205 gchar *dest_path_str = gtk_tree_path_to_string (dest_path);
1206
1207 g_print ("%s: cannot drop bookmarks in folders group\n", dest_path_str);
1208 g_free (dest_path_str);
1209#endif /* DEBUG_DROP */
1210 row_drop_possible = FALSE;
1211 goto done;
1212 }
1213 }
1214 break;
1215 default:
1216 break;
1217 }
1218 }
1219 else if (src_has_folders)
1220 {
1221 gboolean prev_dest_is_folder = TRUE;
1222
1223 if (gtk_tree_model_iter_previous (dest_model, &dest_iter))
1224 if (!gtk_tree_model_iter_has_child (dest_model, &dest_iter))
1225 prev_dest_is_folder = FALSE;
1226
1227 if (!prev_dest_is_folder)
1228 {
1229#ifdef DEBUG_DROP
1230 gchar *dest_path_str = gtk_tree_path_to_string (dest_path);
1231
1232 g_print ("%s: cannot drop folders in bookmarks group\n", dest_path_str);
1233 g_free (dest_path_str);
1234#endif /* DEBUG_DROP */
1235 row_drop_possible = FALSE;
1236 goto done;
1237 }
1238 }
1239
1240 if (src_model == dest_model)
1241 {
1242 for (src_row = rows ; src_row ; src_row = g_list_next (src_row))
1243 {
1244 GtkTreePath* src_path = (GtkTreePath*)src_row->data;
1245
1246 /* Can't drop into ourself. */
1247 if (gtk_tree_path_is_ancestor (src_path, dest_path))
1248 {
1249#ifdef DEBUG_DROP
1250 g_print ("cannot drop into source folders\n");
1251#endif /* DEBUG_DROP */
1252 row_drop_possible = FALSE;
1253 goto done;
1254 }
1255 update_path_list_for_insert (rows, dest_path);
1256 }
1257 }
1258 done:
1259 g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
1260 }
1261 else
1262 row_drop_possible = FALSE;
1263 }
1264 else
1265 row_drop_possible = FALSE;
1266
1267#ifdef DEBUG_DROP
1268 if (row_drop_possible)
1269 {
1270 gchar *dest_path_str = gtk_tree_path_to_string (dest_path);
1271 gchar *drop_position_str = "unknown";
1272 switch (drop_position)
1273 {
1274 case GTK_TREE_VIEW_DROP_BEFORE:
1275 drop_position_str = "before";
1276 break;
1277 case GTK_TREE_VIEW_DROP_AFTER:
1278 drop_position_str = "after";
1279 break;
1280 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
1281 drop_position_str = "into or before";
1282 break;
1283 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
1284 drop_position_str = "into or after";
1285 break;
1286 }
1287
1288 g_print ("%s: row drop possible (%s)\n", dest_path_str, drop_position_str);
1289 g_free (dest_path_str);
1290 }
1291#endif /* DEBUG_DROP */
1292
1293 return row_drop_possible;
1294}
1295
1296static void
1297copy_node_data (GtkTreeStore *src_store,
1298 GtkTreeIter *src_iter,
1299 GtkTreeStore *dest_store,
1300 GtkTreeIter *dest_iter)
1301{
1302 gint i;
1303 gint n_columns;
1304 GtkTreeModel* src_model = GTK_TREE_MODEL (src_store);
1305
1306 n_columns = gtk_tree_model_get_n_columns (src_model);
1307
1308 for (i = 0; i < n_columns; i++)
1309 {
1310 void *item;
1311
1312 gtk_tree_model_get (src_model, src_iter, i, &item, -1);
1313 gtk_tree_store_set (dest_store, dest_iter, i, item, -1);
1314 }
1315}
1316
1317static void
1318recursive_node_copy (GtkTreeStore *src_store,
1319 GtkTreeIter *src_iter,
1320 GtkTreeStore *dest_store,
1321 GtkTreeIter *dest_iter)
1322{
1323 GtkTreeIter child;
1324 GtkTreeModel *src_model = GTK_TREE_MODEL (src_store);
1325
1326 copy_node_data (src_store, src_iter, dest_store, dest_iter);
1327
1328 if (gtk_tree_model_iter_children (src_model, &child, src_iter))
1329 {
1330 /* Need to create children and recurse. Note our
1331 * dependence on persistent iterators here.
1332 */
1333 do
1334 {
1335 GtkTreeIter copy;
1336
1337 /* Gee, a really slow algorithm... ;-) FIXME */
1338 gtk_tree_store_append (dest_store,
1339 &copy,
1340 dest_iter);
1341
1342 recursive_node_copy (src_store, &child, dest_store, &copy);
1343 }
1344 while (gtk_tree_model_iter_next (src_model, &child));
1345 }
1346}
1347
1348static gboolean
1349midori_bookmarks_tree_store_drag_data_received (GtkTreeDragDest *drag_dest,
1350 GtkTreePath *dest_path,
1351 GtkSelectionData *selection_data)
1352{
1353 gboolean status = TRUE;
1354
1355 g_return_val_if_fail (selection_data != NULL, FALSE);
1356 g_return_val_if_fail (GTK_IS_TREE_MODEL (drag_dest), FALSE);
1357 g_return_val_if_fail (dest_path != NULL, FALSE);
1358
1359 if (gtk_selection_data_get_target (selection_data) ==
1360 gdk_atom_intern_static_string (MIDORI_BOOKMARKS_TREE_MODEL_TARGET))
1361 {
1362 GtkTreeStore *dest_store = GTK_TREE_STORE (drag_dest);
1363 GtkTreeModel *dest_model = GTK_TREE_MODEL (drag_dest);
1364 GtkTreeModel *src_model;
1365 GList* rows;
1366
1367 if (midori_bookmarks_tree_store_get_rows_drag_data (selection_data,
1368 &src_model, &rows))
1369 {
1370 GtkTreeStore *src_store = GTK_TREE_STORE (src_model);
1371 GtkTreePath *prev = gtk_tree_path_copy (dest_path);
1372
1373 gint count = 0;
1374 gint length = g_list_length (rows);
1375 gint i;
1376
1377 for (i = 0; i < length; i++)
1378 {
1379 GtkTreeIter dest_iter;
1380 GtkTreeIter src_iter;
1381 GtkTreePath *src_path = (GtkTreePath *)g_list_nth_data (rows, i);
1382
1383 if (!gtk_tree_model_get_iter (src_model, &src_iter, src_path))
1384 continue;
1385
1386 /* Get the path to insert _after_ (dest is the path to insert _before_) */
1387 if (i == 0)
1388 {
1389 if (!gtk_tree_path_prev (prev))
1390 { /* Get the parent, NULL if parent is the root */
1391 GtkTreeIter dest_parent;
1392 GtkTreePath *parent = gtk_tree_path_copy (dest_path);
1393 GtkTreeIter *dest_parent_p = NULL;
1394
1395 if (gtk_tree_path_up (parent) &&
1396 gtk_tree_path_get_depth (parent) > 0)
1397 {
1398 gtk_tree_model_get_iter (dest_model,
1399 &dest_parent, parent);
1400 dest_parent_p = &dest_parent;
1401 }
1402 gtk_tree_path_free (parent);
1403
1404 gtk_tree_store_prepend (dest_store, &dest_iter, dest_parent_p);
1405 }
1406 else if (gtk_tree_model_get_iter (dest_model, &dest_iter, prev))
1407 {
1408 GtkTreeIter tmp_iter = dest_iter;
1409
1410 gtk_tree_store_insert_after (dest_store, &dest_iter, NULL,
1411 &tmp_iter);
1412 }
1413 }
1414 else if (gtk_tree_model_get_iter (dest_model, &dest_iter, prev))
1415 {
1416 GtkTreeIter tmp_iter = dest_iter;
1417
1418 gtk_tree_store_insert_after (dest_store, &dest_iter, NULL,
1419 &tmp_iter);
1420 }
1421
1422 gtk_tree_path_free (prev);
1423
1424 recursive_node_copy (src_store, &src_iter, dest_store, &dest_iter);
1425 count++;
1426
1427 prev = gtk_tree_model_get_path (dest_model, &dest_iter);
1428
1429 if (src_store != dest_store)
1430 continue;
1431
1432 update_path_list_for_insert (rows, prev);
1433 }
1434
1435 gtk_tree_path_free (prev);
1436
1437 g_assert (count == length);
1438
1439 if (src_store == dest_store)
1440 {
1441 MidoriBookmarksTreeStore *tree_store = MIDORI_BOOKMARKS_TREE_STORE(src_store);
1442
1443 g_list_free_full (tree_store->stock_got_rows, (GDestroyNotify) gtk_tree_path_free);
1444 tree_store->stock_got_rows = rows;
1445 }
1446 else
1447 g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
1448 }
1449 }
1450
1451 return status;
1452}
1453
1454static void
1455midori_bookmarks_set_item_positon (GtkTreeModel* model,
1456 GtkTreeIter* iter,
1457 gint64 parentid,
1458 MidoriBookmarks* bookmarks)
1459{
1460 KatzeItem* item;
1461 gint position = 0;
1462 GtkTreeIter next = *iter;
1463
1464 do {
1465 gboolean update = FALSE;
1466 gtk_tree_model_get (model, &next, 0, &item, -1);
1467
1468 if (!KATZE_IS_ITEM (item))
1469 continue;
1470
1471 if (position != katze_item_get_meta_integer (item, "pos_panel"))
1472 {
1473 katze_item_set_meta_integer (item, "pos_panel", position);
1474 update = TRUE;
1475 }
1476 if (parentid != katze_item_get_meta_integer (item, "parentid"))
1477 {
1478 katze_item_set_meta_integer (item, "parentid", parentid);
1479 update = TRUE;
1480 }
1481
1482 if (update)
1483 midori_bookmarks_update_item (bookmarks, item);
1484
1485 position++;
1486
1487 g_object_unref (item);
1488 }
1489 while (gtk_tree_model_iter_next (model, &next));
1490}
1491
1492static void
1493assert_reorder_are_folders (GtkTreeModel* model,
1494 MidoriBookmarks* bookmarks)
1495{
1496 GList* iter;
1497 for (iter = bookmarks->reordered_paths; iter ; iter = g_list_next (iter))
1498 {
1499 GtkTreePath* path = (GtkTreePath*)iter->data;
1500 GtkTreeIter tree_iter;
1501
1502 if (!gtk_tree_path_get_depth (path))
1503 continue;
1504
1505 if (gtk_tree_model_get_iter (model, &tree_iter, path))
1506 {
1507 KatzeItem *item;
1508
1509 gtk_tree_model_get (model, &tree_iter, 0, &item, -1);
1510
1511 g_assert (KATZE_ITEM_IS_FOLDER (item));
1512 }
1513 }
1514}
1515
1516static void
1517add_parent_to_reorder (GtkTreeModel* model,
1518 GtkTreePath* path,
1519 MidoriBookmarks* bookmarks)
1520{
1521 GtkTreePath* path_copy = gtk_tree_path_copy (path);
1522 GList* found;
1523
1524 midori_bookmarks_idle_start (bookmarks);
1525
1526 if (gtk_tree_path_get_depth (path_copy) > 1
1527 && gtk_tree_path_up (path_copy))
1528 {
1529 GtkTreeIter iter;
1530 if (gtk_tree_model_get_iter (model, &iter, path_copy))
1531 {
1532 KatzeItem* item;
1533 gtk_tree_model_get (model, &iter, 0, &item, -1);
1534 if (item)
1535 {
1536 g_assert (KATZE_ITEM_IS_FOLDER (item));
1537 g_object_unref (item);
1538 }
1539 else
1540 g_assert_not_reached ();
1541 }
1542 else
1543 g_assert_not_reached ();
1544 }
1545 else
1546 {
1547 gtk_tree_path_free (path_copy);
1548 path_copy = gtk_tree_path_new ();
1549 }
1550
1551 if ((found = g_list_find_custom (bookmarks->reordered_paths,
1552 path_copy, (GCompareFunc)midori_tree_path_compare)) != NULL)
1553 {
1554 gtk_tree_path_free (path_copy);
1555 return;
1556 }
1557
1558 bookmarks->reordered_paths = g_list_append (bookmarks->reordered_paths, path_copy);
1559}
1560
1561static void
1562midori_bookmarks_row_inserted_cb (GtkTreeModel* model,
1563 GtkTreePath* path,
1564 GtkTreeIter* iter,
1565 MidoriBookmarks* bookmarks)
1566{
1567 midori_bookmarks_idle_start (bookmarks);
1568
1569 update_path_list_for_insert (bookmarks->added_paths, path);
1570 update_path_list_for_insert (bookmarks->reordered_paths, path);
1571 assert_reorder_are_folders (model, bookmarks);
1572
1573 if (g_list_find_custom (bookmarks->added_paths,
1574 path, (GCompareFunc)midori_tree_path_compare))
1575 return;
1576
1577 bookmarks->added_paths = g_list_append (bookmarks->added_paths, gtk_tree_path_copy (path));
1578}
1579
1580#ifdef DEBUG_LIST
1581static void
1582print_path_list (GList* iter)
1583{
1584 for ( ; iter ; iter = g_list_next (iter))
1585 {
1586 gchar* str = gtk_tree_path_to_string ((GtkTreePath*)iter->data);
1587 g_print ("%s ", str);
1588 g_free (str);
1589 }
1590 g_print ("\n");
1591}
1592#endif /* DEBUG_LIST */
1593
1594static void
1595midori_bookmarks_row_deleted_cb (GtkTreeModel* model,
1596 GtkTreePath* path,
1597 MidoriBookmarks* bookmarks)
1598{
1599#ifdef DEBUG_LIST
1600 gchar* str = gtk_tree_path_to_string (path);
1601 g_print ("midori_bookmarks_row_deleted_cb: path: %s\n", str);
1602 g_free (str);
1603#endif /* DEBUG_LIST */
1604
1605 midori_bookmarks_idle_start (bookmarks);
1606
1607 bookmarks->added_paths = update_path_list_for_delete (bookmarks->added_paths, path);
1608#ifdef DEBUG_LIST
1609 print_path_list (bookmarks->reordered_paths);
1610#endif /* DEBUG_LIST */
1611 bookmarks->reordered_paths = update_path_list_for_delete (bookmarks->reordered_paths, path);
1612#ifdef DEBUG_LIST
1613 print_path_list (bookmarks->reordered_paths);
1614#endif /* DEBUG_LIST */
1615 assert_reorder_are_folders (model, bookmarks);
1616 add_parent_to_reorder (model, path, bookmarks);
1617 assert_reorder_are_folders (model, bookmarks);
1618}
4951619
496static void1620static void
497midori_bookmarks_row_changed_cb (GtkTreeModel* model,1621midori_bookmarks_row_changed_cb (GtkTreeModel* model,
@@ -499,41 +1623,8 @@
499 GtkTreeIter* iter,1623 GtkTreeIter* iter,
500 MidoriBookmarks* bookmarks)1624 MidoriBookmarks* bookmarks)
501{1625{
502 KatzeItem* item;1626 add_parent_to_reorder (model, path, bookmarks);
503 GtkTreeIter parent;1627 assert_reorder_are_folders (model, bookmarks);
504 KatzeItem* new_parent = NULL;
505 gint64 parentid;
506
507 gtk_tree_model_get (model, iter, 0, &item, -1);
508
509 if (gtk_tree_model_iter_parent (model, &parent, iter))
510 {
511 gtk_tree_model_get (model, &parent, 0, &new_parent, -1);
512
513 /* Bookmarks must not be moved into non-folder items */
514 if (!KATZE_ITEM_IS_FOLDER (new_parent))
515 parentid = 0;
516 else
517 parentid = katze_item_get_meta_integer (new_parent, "id");
518 }
519 else
520 parentid = 0;
521
522 katze_item_set_meta_integer (item, "parentid", parentid);
523
524 g_signal_handlers_block_by_func (bookmarks->bookmarks_db,
525 midori_bookmarks_update_item_cb,
526 bookmarks);
527
528 midori_bookmarks_db_update_item (bookmarks->bookmarks_db, item);
529
530 g_signal_handlers_unblock_by_func (bookmarks->bookmarks_db,
531 midori_bookmarks_update_item_cb,
532 bookmarks);
533
534 g_object_unref (item);
535 if (new_parent)
536 g_object_unref (new_parent);
537}1628}
5381629
539static void1630static void
@@ -596,7 +1687,7 @@
596 GtkTreeIter iter;1687 GtkTreeIter iter;
5971688
598 if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (bookmarks->treeview),1689 if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (bookmarks->treeview),
599 &model, &iter))1690 &model, &iter))
600 {1691 {
601 KatzeItem* item;1692 KatzeItem* item;
602 MidoriBrowser* browser;1693 MidoriBrowser* browser;
@@ -616,15 +1707,17 @@
616static void1707static void
617midori_bookmarks_toolbar_update (MidoriBookmarks *bookmarks)1708midori_bookmarks_toolbar_update (MidoriBookmarks *bookmarks)
618{1709{
619 gboolean selected;1710 gint selected;
6201711
621 selected = katze_tree_view_get_selected_iter (1712 selected = katze_tree_view_get_selected_rows (
622 GTK_TREE_VIEW (bookmarks->treeview), NULL, NULL);1713 GTK_TREE_VIEW (bookmarks->treeview), NULL, NULL);
623 gtk_widget_set_sensitive (GTK_WIDGET (bookmarks->delete), selected);1714 gtk_widget_set_sensitive (
624 gtk_widget_set_sensitive (GTK_WIDGET (bookmarks->edit), selected);1715 GTK_WIDGET (bookmarks->delete), (selected > 0 ? TRUE : FALSE));
1716 gtk_widget_set_sensitive (
1717 GTK_WIDGET (bookmarks->edit), (selected == 1 ? TRUE : FALSE));
625}1718}
6261719
627static gchar* 1720static gchar*
628midori_bookmarks_statusbar_bookmarks_str (gint count)1721midori_bookmarks_statusbar_bookmarks_str (gint count)
629{1722{
630 if (!count)1723 if (!count)
@@ -634,7 +1727,7 @@
634 return g_strdup_printf (ngettext ("%d bookmark", "%d bookmarks", count), count);1727 return g_strdup_printf (ngettext ("%d bookmark", "%d bookmarks", count), count);
635}1728}
6361729
637static gchar* 1730static gchar*
638midori_bookmarks_statusbar_subfolders_str (gint count)1731midori_bookmarks_statusbar_subfolders_str (gint count)
639{1732{
640 if (!count)1733 if (!count)
@@ -648,78 +1741,141 @@
648midori_bookmarks_statusbar_update (MidoriBookmarks *bookmarks)1741midori_bookmarks_statusbar_update (MidoriBookmarks *bookmarks)
649{1742{
650 gchar* text = NULL;1743 gchar* text = NULL;
6511744 GtkTreeModel* model;
652 if (bookmarks->hovering_item)1745 GList *rows;
653 {1746 gint selected;
654 KatzeItem* item = bookmarks->hovering_item;1747
6551748 selected = katze_tree_view_get_selected_rows (
656 g_assert (!KATZE_ITEM_IS_SEPARATOR (item));1749 GTK_TREE_VIEW (bookmarks->treeview), &model, &rows);
6571750
658 if (KATZE_ITEM_IS_FOLDER (item))1751 if (selected > 1)
1752 {
1753 gint i;
1754 gint selected_folders_count = 0;
1755 gint selected_bookmarks_count = 0;
1756 gchar* selected_folders_str = midori_bookmarks_statusbar_subfolders_str (selected_folders_count);
1757 gchar* selected_bookmarks_str = midori_bookmarks_statusbar_bookmarks_str (selected_bookmarks_count);
1758
1759 for (i = 0 ; i < selected ; i++)
1760 {
1761 GtkTreeIter iter;
1762 KatzeItem* item;
1763
1764 if (!gtk_tree_model_get_iter (
1765 model, &iter, (GtkTreePath *)g_list_nth_data (rows, i)))
1766 continue;
1767
1768 gtk_tree_model_get (model, &iter, 0, &item, -1);
1769
1770 g_assert (!KATZE_ITEM_IS_SEPARATOR (item));
1771
1772 if (KATZE_ITEM_IS_FOLDER (item))
1773 {
1774 selected_folders_count++;
1775 }
1776 else
1777 {
1778 selected_bookmarks_count++;
1779 }
1780 }
1781
1782 selected_folders_str = midori_bookmarks_statusbar_subfolders_str (selected_folders_count);
1783 selected_bookmarks_str = midori_bookmarks_statusbar_bookmarks_str (selected_bookmarks_count);
1784
1785 if (!selected_bookmarks_count && !selected_folders_count)
1786 g_assert_not_reached ();
1787 else if (!selected_bookmarks_count && (selected_folders_count >= 1))
1788 /* i18n: Selection containing [[n] folder(s)] and no bookmark */
1789 text = g_strdup_printf (_("Selection containing %s and no bookmark"),
1790 selected_folders_str);
1791 else if ((selected_bookmarks_count >= 1) && !selected_folders_count)
1792 /* i18n: Selection containing [[n] bookmark(s)] */
1793 text = g_strdup_printf (_("Selection containing %s"), selected_bookmarks_str);
1794 else if ((selected_bookmarks_count >= 1) && (selected_folders_count >= 1))
1795 /* i18n: Selection containing [[n] bookmark(s)] and [[n] folder(s)] */
1796 text = g_strdup_printf (_("Selection containing %s and %s"),
1797 selected_bookmarks_str, selected_folders_str);
1798
1799 g_free (selected_folders_str);
1800 g_free (selected_bookmarks_str);
1801
1802 g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
1803 }
1804 else
1805 {
1806 if (selected)
1807 g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
1808
1809 if (bookmarks->hovering_item)
1810 {
1811 KatzeItem* item = bookmarks->hovering_item;
1812
1813 if (KATZE_ITEM_IS_FOLDER (item))
1814 {
1815 gint child_folders_count = midori_bookmarks_db_count_recursive (bookmarks->bookmarks_db,
1816 "uri = ''", NULL, item, FALSE);
1817 gint child_bookmarks_count = midori_bookmarks_db_count_recursive (bookmarks->bookmarks_db,
1818 "uri <> ''", NULL, item, FALSE);
1819 gchar* child_folders_str = midori_bookmarks_statusbar_subfolders_str (child_folders_count);
1820 gchar* child_bookmarks_str = midori_bookmarks_statusbar_bookmarks_str (child_bookmarks_count);
1821
1822 if (!child_bookmarks_count && !child_folders_count)
1823 /* i18n: Empty folder */
1824 text = g_strdup_printf (_("Empty folder"));
1825 else if (!child_bookmarks_count && (child_folders_count >= 1))
1826 /* i18n: Folder containing [[n] folder(s)] and no bookmark */
1827 text = g_strdup_printf (_("Folder containing %s and no bookmark"),
1828 child_folders_str);
1829 else if ((child_bookmarks_count >= 1) && !child_folders_count)
1830 /* i18n: Folder containing [[n] bookmark(s)] */
1831 text = g_strdup_printf (_("Folder containing %s"), child_bookmarks_str);
1832 else if ((child_bookmarks_count >= 1) && (child_folders_count >= 1))
1833 /* i18n: Folder containing [[n] bookmark(s)] and [[n] folder(s)] */
1834 text = g_strdup_printf (_("Folder containing %s and %s"),
1835 child_bookmarks_str, child_folders_str);
1836
1837 g_free (child_folders_str);
1838 g_free (child_bookmarks_str);
1839 }
1840 else if (KATZE_ITEM_IS_BOOKMARK (item))
1841 {
1842 const gchar* uri = katze_item_get_uri (item);
1843
1844 /* i18n: Bookmark leading to: [bookmark uri] */
1845 text = g_strdup_printf (_("Bookmark leading to: %s"), uri);
1846 }
1847 }
1848 else
659 {1849 {
660 gint child_folders_count = midori_bookmarks_db_count_recursive (bookmarks->bookmarks_db,1850 gint child_folders_count = midori_bookmarks_db_count_recursive (bookmarks->bookmarks_db,
661 "uri = ''", NULL, item, FALSE);1851 "uri = ''", NULL, NULL, FALSE);
662 gint child_bookmarks_count = midori_bookmarks_db_count_recursive (bookmarks->bookmarks_db,1852 gint child_bookmarks_count = midori_bookmarks_db_count_recursive (bookmarks->bookmarks_db,
663 "uri <> ''", NULL, item, FALSE);1853 "uri <> ''", NULL, NULL, FALSE);
664 gchar* child_folders_str = midori_bookmarks_statusbar_subfolders_str (child_folders_count);1854 gchar* child_folders_str = midori_bookmarks_statusbar_subfolders_str (child_folders_count);
665 gchar* child_bookmarks_str = midori_bookmarks_statusbar_bookmarks_str (child_bookmarks_count);1855 gchar* child_bookmarks_str = midori_bookmarks_statusbar_bookmarks_str (child_bookmarks_count);
6661856
667 if (!child_bookmarks_count && !child_folders_count)1857 if (!child_bookmarks_count && (child_folders_count >= 1))
668 /* i18n: Empty folder */1858 /* i18n: [[n] folder(s)] and no bookmark */
669 text = g_strdup_printf (_("Empty folder"));1859 text = g_strdup_printf (_("%s and no bookmark"),
670 else if (!child_bookmarks_count && (child_folders_count >= 1))
671 /* i18n: Folder containing [[n] folder(s)] and no bookmark */
672 text = g_strdup_printf (_("Folder containing %s and no bookmark"),
673 child_folders_str);1860 child_folders_str);
674 else if ((child_bookmarks_count >= 1) && !child_folders_count)1861 else if ((child_bookmarks_count >= 1) && !child_folders_count)
675 /* i18n: Folder containing [[n] bookmark(s)] */1862 text = g_strdup (child_bookmarks_str);
676 text = g_strdup_printf (_("Folder containing %s"), child_bookmarks_str);
677 else if ((child_bookmarks_count >= 1) && (child_folders_count >= 1))1863 else if ((child_bookmarks_count >= 1) && (child_folders_count >= 1))
678 /* i18n: Folder containing [[n] bookmark(s)] and [[n] folder(s)] */1864 /* i18n: [[n] bookmark(s)] and [[n] folder(s)] */
679 text = g_strdup_printf (_("Folder containing %s and %s"),1865 text = g_strdup_printf (_("%s and %s"),
680 child_bookmarks_str, child_folders_str);1866 child_bookmarks_str, child_folders_str);
6811867
682 g_free (child_folders_str);1868 g_free (child_folders_str);
683 g_free (child_bookmarks_str);1869 g_free (child_bookmarks_str);
684 }1870 }
685 else if (KATZE_ITEM_IS_BOOKMARK (item))
686 {
687 const gchar* uri = katze_item_get_uri (item);
688
689 /* i18n: Bookmark leading to: [bookmark uri] */
690 text = g_strdup_printf (_("Bookmark leading to: %s"), uri);
691 }
692 }
693 else
694 {
695 gint child_folders_count = midori_bookmarks_db_count_recursive (bookmarks->bookmarks_db,
696 "uri = ''", NULL, NULL, FALSE);
697 gint child_bookmarks_count = midori_bookmarks_db_count_recursive (bookmarks->bookmarks_db,
698 "uri <> ''", NULL, NULL, FALSE);
699 gchar* child_folders_str = midori_bookmarks_statusbar_subfolders_str (child_folders_count);
700 gchar* child_bookmarks_str = midori_bookmarks_statusbar_bookmarks_str (child_bookmarks_count);
701
702 if (!child_bookmarks_count && (child_folders_count >= 1))
703 /* i18n: [[n] folder(s)] and no bookmark */
704 text = g_strdup_printf (_("%s and no bookmark"),
705 child_folders_str);
706 else if ((child_bookmarks_count >= 1) && !child_folders_count)
707 text = g_strdup (child_bookmarks_str);
708 else if ((child_bookmarks_count >= 1) && (child_folders_count >= 1))
709 /* i18n: [[n] bookmark(s)] and [[n] folder(s)] */
710 text = g_strdup_printf (_("%s and %s"),
711 child_bookmarks_str, child_folders_str);
712
713 g_free (child_folders_str);
714 g_free (child_bookmarks_str);
715 }1871 }
7161872
717 if (text)1873 if (text)
718 {1874 {
719 MidoriBrowser* browser = midori_browser_get_for_widget (bookmarks->treeview);1875 MidoriBrowser* browser = midori_browser_get_for_widget (bookmarks->treeview);
720 1876
721 g_object_set (browser, "statusbar-text", text, NULL);1877 g_object_set (browser, "statusbar-text", text, NULL);
722 1878
723 g_free(text);1879 g_free(text);
724 }1880 }
725}1881}
@@ -729,19 +1885,33 @@
729 MidoriBookmarks* bookmarks)1885 MidoriBookmarks* bookmarks)
730{1886{
731 GtkTreeModel* model;1887 GtkTreeModel* model;
732 GtkTreeIter iter;1888 GList* rows;
7331889 GList* iter_row;
734 if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (bookmarks->treeview),1890
735 &model, &iter))1891 if (!katze_tree_view_get_selected_rows(GTK_TREE_VIEW (bookmarks->treeview),
1892 &model, &rows))
1893 return;
1894
1895 for (iter_row = rows ; iter_row ; iter_row = g_list_next (iter_row))
736 {1896 {
737 KatzeItem* item;1897 GtkTreeIter iter;
7381898
739 gtk_tree_model_get (model, &iter, 0, &item, -1);1899 if (gtk_tree_model_get_iter (model, &iter, (GtkTreePath *)iter_row->data))
7401900 {
741 midori_bookmarks_db_remove_item (bookmarks->bookmarks_db, item);1901 KatzeItem* item;
7421902
743 g_object_unref (item);1903 gtk_tree_model_get (model, &iter, 0, &item, -1);
1904
1905 if (item)
1906 {
1907 midori_bookmarks_db_remove_item (bookmarks->bookmarks_db, item);
1908
1909 g_object_unref (item);
1910 }
1911 }
744 }1912 }
1913
1914 g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
745}1915}
7461916
747static GtkWidget*1917static GtkWidget*
@@ -759,7 +1929,7 @@
759 toolitem = gtk_tool_button_new_from_stock (STOCK_BOOKMARK_ADD);1929 toolitem = gtk_tool_button_new_from_stock (STOCK_BOOKMARK_ADD);
760 gtk_widget_set_name (GTK_WIDGET (toolitem), "BookmarkAdd");1930 gtk_widget_set_name (GTK_WIDGET (toolitem), "BookmarkAdd");
761 gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),1931 gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),
762 _("Add a new bookmark"));1932 _("Add a new bookmark"));
763 gtk_tool_item_set_is_important (toolitem, TRUE);1933 gtk_tool_item_set_is_important (toolitem, TRUE);
764 g_signal_connect (toolitem, "clicked",1934 g_signal_connect (toolitem, "clicked",
765 G_CALLBACK (midori_bookmarks_add_clicked_cb), bookmarks);1935 G_CALLBACK (midori_bookmarks_add_clicked_cb), bookmarks);
@@ -767,7 +1937,7 @@
767 gtk_widget_show (GTK_WIDGET (toolitem));1937 gtk_widget_show (GTK_WIDGET (toolitem));
768 toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_EDIT);1938 toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_EDIT);
769 gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),1939 gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),
770 _("Edit the selected bookmark"));1940 _("Edit the selected bookmark"));
771 g_signal_connect (toolitem, "clicked",1941 g_signal_connect (toolitem, "clicked",
772 G_CALLBACK (midori_bookmarks_edit_clicked_cb), bookmarks);1942 G_CALLBACK (midori_bookmarks_edit_clicked_cb), bookmarks);
773 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);1943 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
@@ -775,7 +1945,7 @@
775 bookmarks->edit = GTK_WIDGET (toolitem);1945 bookmarks->edit = GTK_WIDGET (toolitem);
776 toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_DELETE);1946 toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_DELETE);
777 gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),1947 gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),
778 _("Delete the selected bookmark"));1948 _("Delete the selected bookmark"));
779 g_signal_connect (toolitem, "clicked",1949 g_signal_connect (toolitem, "clicked",
780 G_CALLBACK (midori_bookmarks_delete_clicked_cb), bookmarks);1950 G_CALLBACK (midori_bookmarks_delete_clicked_cb), bookmarks);
781 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);1951 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
@@ -791,7 +1961,7 @@
791 toolitem = gtk_tool_button_new_from_stock (STOCK_FOLDER_NEW);1961 toolitem = gtk_tool_button_new_from_stock (STOCK_FOLDER_NEW);
792 gtk_widget_set_name (GTK_WIDGET (toolitem), "BookmarkFolderAdd");1962 gtk_widget_set_name (GTK_WIDGET (toolitem), "BookmarkFolderAdd");
793 gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),1963 gtk_widget_set_tooltip_text (GTK_WIDGET (toolitem),
794 _("Add a new folder"));1964 _("Add a new folder"));
795 g_signal_connect (toolitem, "clicked",1965 g_signal_connect (toolitem, "clicked",
796 G_CALLBACK (midori_bookmarks_add_clicked_cb), bookmarks);1966 G_CALLBACK (midori_bookmarks_add_clicked_cb), bookmarks);
797 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);1967 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), toolitem, -1);
@@ -841,6 +2011,12 @@
841 G_CALLBACK (midori_bookmarks_remove_item_cb), bookmarks);2011 G_CALLBACK (midori_bookmarks_remove_item_cb), bookmarks);
842 g_signal_connect (bookmarks->bookmarks_db, "update",2012 g_signal_connect (bookmarks->bookmarks_db, "update",
843 G_CALLBACK (midori_bookmarks_update_cb), bookmarks);2013 G_CALLBACK (midori_bookmarks_update_cb), bookmarks);
2014 g_signal_connect_after (model, "row-inserted",
2015 G_CALLBACK (midori_bookmarks_row_inserted_cb),
2016 bookmarks);
2017 g_signal_connect_after (model, "row-deleted",
2018 G_CALLBACK (midori_bookmarks_row_deleted_cb),
2019 bookmarks);
844 g_signal_connect_after (model, "row-changed",2020 g_signal_connect_after (model, "row-changed",
845 G_CALLBACK (midori_bookmarks_row_changed_cb),2021 G_CALLBACK (midori_bookmarks_row_changed_cb),
846 bookmarks);2022 bookmarks);
@@ -856,12 +2032,12 @@
8562032
857 switch (prop_id)2033 switch (prop_id)
858 {2034 {
859 case PROP_APP:2035 case PROP_APP:
860 midori_bookmarks_set_app (bookmarks, g_value_get_object (value));2036 midori_bookmarks_set_app (bookmarks, g_value_get_object (value));
861 break;2037 break;
862 default:2038 default:
863 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);2039 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
864 break;2040 break;
865 }2041 }
866}2042}
8672043
@@ -875,12 +2051,12 @@
8752051
876 switch (prop_id)2052 switch (prop_id)
877 {2053 {
878 case PROP_APP:2054 case PROP_APP:
879 g_value_set_object (value, bookmarks->app);2055 g_value_set_object (value, bookmarks->app);
880 break;2056 break;
881 default:2057 default:
882 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);2058 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
883 break;2059 break;
884 }2060 }
885}2061}
8862062
@@ -918,8 +2094,8 @@
918 if (item && katze_item_get_name (item))2094 if (item && katze_item_get_name (item))
919 {2095 {
920 g_object_set (renderer, "markup", NULL,2096 g_object_set (renderer, "markup", NULL,
921 "ellipsize", PANGO_ELLIPSIZE_END,2097 "ellipsize", PANGO_ELLIPSIZE_END,
922 "text", katze_item_get_name (item), NULL);2098 "text", katze_item_get_name (item), NULL);
923 }2099 }
924 else2100 else
925 g_object_set (renderer, "markup", _("<i>Separator</i>"), NULL);2101 g_object_set (renderer, "markup", _("<i>Separator</i>"), NULL);
@@ -976,7 +2152,7 @@
976 menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);2152 menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
977 if (label)2153 if (label)
978 gtk_label_set_text_with_mnemonic (GTK_LABEL (gtk_bin_get_child (2154 gtk_label_set_text_with_mnemonic (GTK_LABEL (gtk_bin_get_child (
979 GTK_BIN (menuitem))), label);2155 GTK_BIN (menuitem))), label);
980 if (!strcmp (stock_id, GTK_STOCK_EDIT))2156 if (!strcmp (stock_id, GTK_STOCK_EDIT))
981 gtk_widget_set_sensitive (menuitem,2157 gtk_widget_set_sensitive (menuitem,
982 !KATZE_ITEM_IS_SEPARATOR (item));2158 !KATZE_ITEM_IS_SEPARATOR (item));
@@ -1007,39 +2183,103 @@
1007 }2183 }
1008}2184}
10092185
1010static void2186static GtkWidget*
1011midori_bookmarks_open_in_tab_activate_cb (GtkWidget* menuitem,2187midori_bookmarks_open_bookmark_in_tab (KatzeItem *item,
1012 MidoriBookmarks* bookmarks)2188 MidoriBrowser* browser)
1013{2189{
1014 KatzeItem* item;2190 const gchar* uri = katze_item_get_uri (item);
1015 const gchar* uri;2191
10162192 if (!uri || !*uri)
1017 item = (KatzeItem*)g_object_get_data (G_OBJECT (menuitem), "KatzeItem");2193 return NULL;
1018 if (KATZE_ITEM_IS_FOLDER (item))2194
2195 return midori_browser_add_item (browser, item);
2196}
2197
2198static GtkWidget*
2199midori_bookmarks_open_folder_in_tab (gint64 parentid,
2200 MidoriBookmarks* bookmarks,
2201 MidoriBrowser* browser)
2202{
2203 GtkWidget* last_view = NULL;
2204 KatzeArray* array;
2205
2206 array = midori_bookmarks_read_from_db (bookmarks, parentid, NULL);
2207
2208 if (KATZE_IS_ARRAY (array))
1019 {2209 {
1020 KatzeItem* child;2210 KatzeItem* child;
1021 KatzeArray* array;2211
1022
1023 array = midori_bookmarks_read_from_db (bookmarks,
1024 katze_item_get_meta_integer (item, "parentid"), NULL);
1025
1026 g_return_if_fail (KATZE_IS_ARRAY (array));
1027 KATZE_ARRAY_FOREACH_ITEM (child, array)2212 KATZE_ARRAY_FOREACH_ITEM (child, array)
1028 {2213 {
1029 if ((uri = katze_item_get_uri (child)) && *uri)2214 GtkWidget* view = midori_bookmarks_open_bookmark_in_tab (child, browser);
2215 if (view)
2216 last_view = view;
2217 }
2218 }
2219
2220 return last_view;
2221}
2222
2223static void
2224midori_bookmarks_open_in_tab_activate_cb (GtkWidget* menuitem,
2225 MidoriBookmarks* bookmarks)
2226{
2227 GtkWidget* last_view = NULL;
2228 MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (bookmarks));
2229 GtkTreeModel* model;
2230 GList* rows;
2231 gint length;
2232
2233 length = katze_tree_view_get_selected_rows (GTK_TREE_VIEW (bookmarks->treeview),
2234 &model, &rows);
2235
2236 if (!length)
2237 {
2238 KatzeItem* root = KATZE_ITEM (bookmarks->bookmarks_db);
2239 KatzeItem* item = KATZE_ITEM (g_object_get_data (G_OBJECT (menuitem), "KatzeItem"));
2240
2241 if (item != root)
2242 return;
2243
2244 last_view = midori_bookmarks_open_folder_in_tab (0, bookmarks, browser);
2245 }
2246 else
2247 {
2248 gint i;
2249
2250 for (i = 0 ; i < length; i++)
2251 {
2252 GtkTreeIter iter;
2253
2254 if (gtk_tree_model_get_iter (
2255 model, &iter, (GtkTreePath *)g_list_nth_data (rows, i)))
1030 {2256 {
1031 MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (bookmarks));2257 GtkWidget* view = NULL;
1032 GtkWidget* view = midori_browser_add_item (browser, child);2258 KatzeItem* item;
1033 midori_browser_set_current_tab_smartly (browser, view);2259
2260 gtk_tree_model_get (model, &iter, 0, &item, -1);
2261
2262 if (KATZE_ITEM_IS_SEPARATOR(item))
2263 continue;
2264
2265 if (KATZE_ITEM_IS_FOLDER (item))
2266 view = midori_bookmarks_open_folder_in_tab (
2267 katze_item_get_meta_integer (item, "id"), bookmarks, browser);
2268 else
2269 view = midori_bookmarks_open_bookmark_in_tab (item, browser);
2270
2271 g_object_unref (item);
2272
2273 if (view)
2274 last_view = view;
1034 }2275 }
1035 }2276 }
1036 }2277
1037 else if ((uri = katze_item_get_uri (item)) && *uri)2278 g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
1038 {2279 }
1039 MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (bookmarks));2280
1040 GtkWidget* view = midori_browser_add_item (browser, item);2281 if (last_view)
1041 midori_browser_set_current_tab_smartly (browser, view);2282 midori_browser_set_current_tab_smartly (browser, last_view);
1042 }
1043}2283}
10442284
1045static void2285static void
@@ -1067,18 +2307,20 @@
1067 KatzeItem* item,2307 KatzeItem* item,
1068 MidoriBookmarks* bookmarks)2308 MidoriBookmarks* bookmarks)
1069{2309{
2310 KatzeItem* root = KATZE_ITEM (bookmarks->bookmarks_db);
1070 GtkWidget* menu;2311 GtkWidget* menu;
1071 GtkWidget* menuitem;2312 GtkWidget* menuitem;
10722313
1073 menu = gtk_menu_new ();2314 menu = gtk_menu_new ();
1074 if (KATZE_ITEM_IS_FOLDER (item))2315 if ((item == root)
2316 || KATZE_ITEM_IS_FOLDER (item))
1075 {2317 {
1076 gint child_bookmarks_count = midori_bookmarks_db_count_recursive (bookmarks->bookmarks_db,2318 gint child_bookmarks_count = midori_bookmarks_db_count_recursive (bookmarks->bookmarks_db,
1077 "uri <> ''", NULL, item, FALSE);2319 "uri <> ''", NULL, item, FALSE);
10782320
1079 midori_bookmarks_popup_item (menu,2321 midori_bookmarks_popup_item (menu,
1080 STOCK_TAB_NEW, _("Open all in _Tabs"), item, 2322 STOCK_TAB_NEW, _("Open all in _Tabs"), item,
1081 (!child_bookmarks_count ? NULL : midori_bookmarks_open_in_tab_activate_cb), 2323 (!child_bookmarks_count ? NULL : midori_bookmarks_open_in_tab_activate_cb),
1082 bookmarks);2324 bookmarks);
1083 }2325 }
1084 else2326 else
@@ -1094,11 +2336,59 @@
1094 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);2336 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1095 gtk_widget_show (menuitem);2337 gtk_widget_show (menuitem);
1096 midori_bookmarks_popup_item (menu, GTK_STOCK_EDIT, NULL,2338 midori_bookmarks_popup_item (menu, GTK_STOCK_EDIT, NULL,
1097 item, midori_bookmarks_edit_clicked_cb, bookmarks);2339 item, (item == root) ? NULL : midori_bookmarks_edit_clicked_cb, bookmarks);
1098 midori_bookmarks_popup_item (menu, GTK_STOCK_DELETE, NULL,2340 midori_bookmarks_popup_item (menu, GTK_STOCK_DELETE, NULL,
1099 item, midori_bookmarks_delete_clicked_cb, bookmarks);2341 item, (item == root) ? NULL : midori_bookmarks_delete_clicked_cb, bookmarks);
11002342
1101 katze_widget_popup (widget, GTK_MENU (menu), event, KATZE_MENU_POSITION_CURSOR);2343 katze_widget_popup (widget, GTK_MENU (menu), event, KATZE_MENU_POSITION_CURSOR);
2344}
2345
2346static void
2347midori_bookmarks_multi_popup (GtkWidget* widget,
2348 GdkEventButton* event,
2349 MidoriBookmarks* bookmarks,
2350 GtkTreeModel* model,
2351 gint count,
2352 GList* rows)
2353{
2354 GtkWidget* menu;
2355 GtkWidget* menuitem;
2356
2357 menu = gtk_menu_new ();
2358
2359 midori_bookmarks_popup_item (menu,
2360 STOCK_TAB_NEW, _("Open all in _Tabs"),
2361 KATZE_ITEM(bookmarks->bookmarks_db), midori_bookmarks_open_in_tab_activate_cb, bookmarks);
2362 menuitem = gtk_separator_menu_item_new ();
2363 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
2364 gtk_widget_show (menuitem);
2365
2366 midori_bookmarks_popup_item (menu, GTK_STOCK_EDIT, NULL,
2367 NULL, NULL, bookmarks);
2368 midori_bookmarks_popup_item (menu, GTK_STOCK_DELETE, NULL,
2369 KATZE_ITEM(bookmarks->bookmarks_db), midori_bookmarks_delete_clicked_cb, bookmarks);
2370
2371 katze_widget_popup (widget, GTK_MENU (menu), event, KATZE_MENU_POSITION_CURSOR);
2372}
2373
2374static gboolean
2375midori_bookmarks_do_block_selection (GtkTreeSelection *selection,
2376 GtkTreeModel *model,
2377 GtkTreePath *path,
2378 gboolean path_currently_selected,
2379 gpointer data)
2380{
2381 return FALSE;
2382}
2383
2384static gboolean
2385midori_bookmarks_do_not_block_selection (GtkTreeSelection *selection,
2386 GtkTreeModel *model,
2387 GtkTreePath *path,
2388 gboolean path_currently_selected,
2389 gpointer data)
2390{
2391 return TRUE;
1102}2392}
11032393
1104static gboolean2394static gboolean
@@ -1109,32 +2399,194 @@
1109 GtkTreeModel* model;2399 GtkTreeModel* model;
1110 GtkTreeIter iter;2400 GtkTreeIter iter;
11112401
1112 if (event->button != 2 && event->button != 3)2402 if (bookmarks->pending_event)
2403 {
2404 GtkTreeView* treeview = GTK_TREE_VIEW(widget);
2405 GtkTreeSelection* selection = gtk_tree_view_get_selection (treeview);
2406 gint x = bookmarks->stock_pending_event.x;
2407 gint y = bookmarks->stock_pending_event.y;
2408
2409 bookmarks->pending_event = NULL;
2410 gtk_tree_selection_set_select_function (
2411 selection, midori_bookmarks_do_not_block_selection, NULL, NULL);
2412
2413 if (x != event->x || y != event->y)
2414 return FALSE;
2415 }
2416
2417 if (event->button == 3)
2418 return TRUE;
2419
2420 if (event->button != 2)
1113 return FALSE;2421 return FALSE;
11142422
1115 if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget), &model, &iter))2423 if (katze_tree_view_get_selected_iter (GTK_TREE_VIEW (widget), &model, &iter))
1116 {2424 {
2425 gboolean done = FALSE;
1117 KatzeItem* item;2426 KatzeItem* item;
11182427
1119 gtk_tree_model_get (model, &iter, 0, &item, -1);2428 gtk_tree_model_get (model, &iter, 0, &item, -1);
11202429
1121 if (event->button == 2)2430 if (KATZE_ITEM_IS_BOOKMARK (item))
1122 {2431 {
1123 const gchar* uri;2432 MidoriBrowser* browser = midori_browser_get_for_widget (widget);
1124 if (KATZE_ITEM_IS_BOOKMARK (item) && (uri = katze_item_get_uri (item)) && *uri)2433 GtkWidget* view = midori_bookmarks_open_bookmark_in_tab (
2434 item, browser);
2435
2436 if (widget)
1125 {2437 {
1126 MidoriBrowser* browser = midori_browser_get_for_widget (widget);2438 midori_browser_set_current_tab_smartly (browser, view);
1127 GtkWidget* view = midori_browser_add_uri (browser, uri);2439 done = TRUE;
1128 midori_browser_set_current_tab (browser, view);
1129 }2440 }
1130 }2441 }
1131 else2442
1132 midori_bookmarks_popup (widget, event, item, bookmarks);2443 g_object_unref (item);
11332444
1134 if (item != NULL)2445 return done;
1135 g_object_unref (item);2446 }
1136 return TRUE;2447
1137 }2448 return FALSE;
2449}
2450
2451static gboolean
2452midori_bookmarks_block_selection(GtkWidget* widget,
2453 GdkEventButton* event,
2454 MidoriBookmarks* bookmarks)
2455{
2456 GtkTreeView* treeview = GTK_TREE_VIEW(widget);
2457 GtkTreePath* path;
2458 GtkTreeSelection* selection;
2459 gint cell_x;
2460 gint cell_y;
2461
2462 if (!gtk_tree_view_get_path_at_pos (
2463 treeview, event->x, event->y,
2464 &path, NULL, &cell_x, &cell_y))
2465 return FALSE;
2466
2467 gtk_widget_grab_focus (widget);
2468
2469 selection = gtk_tree_view_get_selection (treeview);
2470
2471 if (gtk_tree_selection_path_is_selected (selection, path)
2472 && !(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)))
2473 {
2474 bookmarks->pending_event = &bookmarks->stock_pending_event;
2475 bookmarks->stock_pending_event.x = event->x;
2476 bookmarks->stock_pending_event.y = event->y;
2477 gtk_tree_selection_set_select_function (
2478 selection, midori_bookmarks_do_block_selection, NULL, NULL);
2479 }
2480 else
2481 {
2482 bookmarks->pending_event = NULL;
2483 gtk_tree_selection_set_select_function (
2484 selection, midori_bookmarks_do_not_block_selection, NULL, NULL);
2485 }
2486
2487 return FALSE;
2488}
2489
2490static gboolean
2491midori_bookmarks_button_press_event_cb (GtkWidget* widget,
2492 GdkEventButton* event,
2493 MidoriBookmarks* bookmarks)
2494{
2495 GtkTreeView* treeview = GTK_TREE_VIEW(widget);
2496 GtkTreePath* path;
2497 GtkTreeSelection* selection;
2498 GtkTreeModel* model;
2499 gint selected;
2500 GList* rows;
2501 gint cell_x;
2502 gint cell_y;
2503
2504 if (event->button == 1)
2505 return midori_bookmarks_block_selection (widget, event, bookmarks);
2506
2507 if (event->button != 3)
2508 return FALSE;
2509
2510 selection = gtk_tree_view_get_selection (treeview);
2511
2512 if (!gtk_tree_view_get_path_at_pos (
2513 treeview, event->x, event->y,
2514 &path, NULL, &cell_x, &cell_y))
2515 {
2516 /* FIXME: popup opening below treeview
2517 * Rationale: the user is actually in ROOT folder
2518 * we may need to have a non editable, non deletable, ROOT folder popup
2519 * Open all in Tabs
2520 * Separator
2521 * Edit [inactive]
2522 * Delete [inactive]
2523 * Here we just mimic the Files behaviour:
2524 * 1- unselect all
2525 * 2- let popup based on selection process
2526 */
2527
2528 gtk_tree_selection_unselect_all (selection);
2529 }
2530 else if (!gtk_tree_selection_path_is_selected (selection, path))
2531 {
2532 /* Use case: popup opening on item not in selection
2533 * Rationale: the user is addressing a single item not in selection
2534 * we may need a single item popup with callbacks working on the item,
2535 * not the selection.
2536 * Here we just mimic the Files behaviour:
2537 * 1- change the selection to the item the popup is opened on
2538 * 2- let popup based on selection process
2539 */
2540
2541 gtk_tree_selection_unselect_all (selection);
2542 gtk_tree_selection_select_path (selection, path);
2543 }
2544
2545 selected = katze_tree_view_get_selected_rows(GTK_TREE_VIEW (widget), &model, &rows);
2546
2547 if (!selected)
2548 {
2549 KatzeItem* root = KATZE_ITEM (bookmarks->bookmarks_db);
2550
2551 midori_bookmarks_popup (widget, event, root, bookmarks);
2552
2553 return TRUE;
2554 }
2555
2556 if (selected == 1)
2557 {
2558 GtkTreeIter iter;
2559 KatzeItem* item;
2560
2561 if (!gtk_tree_model_get_iter (
2562 model, &iter, (GtkTreePath *)g_list_nth_data (rows, 0)))
2563 {
2564 g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
2565
2566 return FALSE;
2567 }
2568
2569 gtk_tree_model_get (model, &iter, 0, &item, -1);
2570
2571 midori_bookmarks_popup (widget, event, item, bookmarks);
2572
2573 g_object_unref (item);
2574
2575 g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
2576
2577 return TRUE;
2578 }
2579
2580 if (selected > 1)
2581 {
2582 midori_bookmarks_multi_popup (widget, event, bookmarks,
2583 model, selected, rows);
2584
2585 g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
2586
2587 return TRUE;
2588 }
2589
1138 return FALSE;2590 return FALSE;
1139}2591}
11402592
@@ -1165,39 +2617,74 @@
1165 }2617 }
1166}2618}
11672619
1168static void2620static gboolean
1169midori_bookmarks_row_expanded_cb (GtkTreeView* treeview,2621midori_bookmarks_test_expand_row_cb (GtkTreeView* treeview,
1170 GtkTreeIter* iter,2622 GtkTreeIter* iter,
1171 GtkTreePath* path,2623 GtkTreePath* path,
1172 MidoriBookmarks* bookmarks)2624 MidoriBookmarks* bookmarks)
1173{2625{
1174 GtkTreeModel* model;2626 GtkTreeModel* model;
2627 GtkTreeIter child;
1175 KatzeItem* item;2628 KatzeItem* item;
2629 gint64 id;
11762630
1177 model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));2631 model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
2632
1178 gtk_tree_model_get (model, iter, 0, &item, -1);2633 gtk_tree_model_get (model, iter, 0, &item, -1);
2634
2635 g_return_val_if_fail (KATZE_IS_ITEM(item), TRUE);
2636
2637 g_signal_handlers_block_by_func (model,
2638 midori_bookmarks_row_deleted_cb,
2639 bookmarks);
2640
2641 id = katze_item_get_meta_integer (item, "id");
2642
2643 g_object_unref (item);
2644
2645 while (gtk_tree_model_iter_children (model, &child, iter))
2646 gtk_tree_store_remove (GTK_TREE_STORE (model), &child);
2647 /* That's an invisible dummy, so we always have an expander */
2648 gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &child, iter,
2649 0, 0, NULL, -1);
2650
2651 g_signal_handlers_unblock_by_func (model,
2652 midori_bookmarks_row_deleted_cb,
2653 bookmarks);
2654
1179 midori_bookmarks_read_from_db_to_model (bookmarks, GTK_TREE_STORE (model),2655 midori_bookmarks_read_from_db_to_model (bookmarks, GTK_TREE_STORE (model),
1180 iter, katze_item_get_meta_integer (item, "id"), NULL);2656 iter, id, NULL);
1181 g_object_unref (item);2657
2658 return FALSE;
1182}2659}
11832660
1184static void2661static void
1185midori_bookmarks_row_collapsed_cb (GtkTreeView *treeview,2662midori_bookmarks_row_collapsed_cb (GtkTreeView *treeview,
1186 GtkTreeIter *parent,2663 GtkTreeIter *parent,
1187 GtkTreePath *path,2664 GtkTreePath *path,
1188 gpointer user_data)2665 MidoriBookmarks* bookmarks)
1189{2666{
1190 GtkTreeModel* model;2667 GtkTreeModel* model;
1191 GtkTreeStore* treestore;2668 GtkTreeStore* treestore;
1192 GtkTreeIter child;2669 GtkTreeIter child;
11932670
1194 model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));2671 model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
2672
2673 g_signal_handlers_block_by_func (model,
2674 midori_bookmarks_row_deleted_cb,
2675 bookmarks);
2676
1195 treestore = GTK_TREE_STORE (model);2677 treestore = GTK_TREE_STORE (model);
1196 while (gtk_tree_model_iter_nth_child (model, &child, parent, 0))2678 while (gtk_tree_model_iter_nth_child (model, &child, parent, 0))
1197 gtk_tree_store_remove (treestore, &child);2679 gtk_tree_store_remove (treestore, &child);
1198 /* That's an invisible dummy, so we always have an expander */2680 /* That's an invisible dummy, so we always have an expander */
1199 gtk_tree_store_insert_with_values (treestore, &child, parent,2681 gtk_tree_store_insert_with_values (treestore, &child, parent,
1200 0, 0, NULL, -1);2682 0, 0, NULL, -1);
2683
2684 g_signal_handlers_block_by_func (model,
2685 midori_bookmarks_row_deleted_cb,
2686 bookmarks);
2687
1201}2688}
12022689
1203static void2690static void
@@ -1205,26 +2692,27 @@
1205 MidoriBookmarks *bookmarks)2692 MidoriBookmarks *bookmarks)
1206{2693{
1207 midori_bookmarks_toolbar_update (bookmarks);2694 midori_bookmarks_toolbar_update (bookmarks);
2695 midori_bookmarks_statusbar_update (bookmarks);
1208}2696}
12092697
1210static KatzeItem*2698static KatzeItem*
1211midori_bookmarks_get_item_at_pos (GtkTreeView *treeview,2699midori_bookmarks_get_item_at_pos (GtkTreeView *treeview,
1212 gint x, gint y)2700 gint x, gint y)
1213{ 2701{
1214 GtkTreeModel* model = gtk_tree_view_get_model (treeview);2702 GtkTreeModel* model = gtk_tree_view_get_model (treeview);
1215 GtkTreePath* path;2703 GtkTreePath* path;
1216 GtkTreeIter iter;2704 GtkTreeIter iter;
1217 KatzeItem* item = NULL;2705 KatzeItem* item = NULL;
12182706
1219 gtk_tree_view_get_path_at_pos (treeview, x, y,2707 gtk_tree_view_get_path_at_pos (treeview, x, y,
1220 &path, NULL, NULL, NULL);2708 &path, NULL, NULL, NULL);
1221 2709
1222 if (!path)2710 if (!path)
1223 return NULL;2711 return NULL;
1224 2712
1225 if (gtk_tree_model_get_iter (model, &iter, path))2713 if (gtk_tree_model_get_iter (model, &iter, path))
1226 gtk_tree_model_get (model, &iter, 0, &item, -1);2714 gtk_tree_model_get (model, &iter, 0, &item, -1);
1227 2715
1228 gtk_tree_path_free (path);2716 gtk_tree_path_free (path);
12292717
1230 return item;2718 return item;
@@ -1296,7 +2784,7 @@
12962784
1297 if (bookmarks->hovering_item)2785 if (bookmarks->hovering_item)
1298 g_object_unref (bookmarks->hovering_item);2786 g_object_unref (bookmarks->hovering_item);
1299 2787
1300 bookmarks->hovering_item = NULL;2788 bookmarks->hovering_item = NULL;
13012789
1302 g_object_set (browser, "statusbar-text", "", NULL);2790 g_object_set (browser, "statusbar-text", "", NULL);
@@ -1337,6 +2825,186 @@
1337 midori_bookmarks_filter_timeout_cb, bookmarks, NULL);2825 midori_bookmarks_filter_timeout_cb, bookmarks, NULL);
1338}2826}
13392827
2828static GtkTargetEntry midori_bookmarks_dnd_target_entries[]=
2829{
2830 {MIDORI_BOOKMARKS_TREE_MODEL_TARGET, GTK_TARGET_SAME_WIDGET, 0},
2831};
2832
2833#define MIDORI_BOOKMARKS_DND_NB_TARGET_ENTRIES \
2834 G_N_ELEMENTS (midori_bookmarks_dnd_target_entries)
2835
2836static guint
2837item_hash (gconstpointer item)
2838{
2839 gint64 id = katze_item_get_meta_integer (KATZE_ITEM (item), "id");
2840 return g_int64_hash (&id);
2841}
2842
2843static gboolean
2844item_equal (gconstpointer item_a, gconstpointer item_b)
2845{
2846 gint64 id_a = katze_item_get_meta_integer (KATZE_ITEM (item_a), "id");
2847 gint64 id_b = katze_item_get_meta_integer (KATZE_ITEM (item_b), "id");
2848 return (id_a == id_b)? TRUE : FALSE;
2849}
2850
2851static gboolean
2852midori_bookmarks_idle_func (gpointer data)
2853{
2854 MidoriBookmarks* bookmarks = MIDORI_BOOKMARKS (data);
2855 GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));
2856 GHashTableIter hash_iter;
2857 gpointer key, value;
2858 GList* list_iter;
2859
2860 /* update remaining additions */
2861 assert_reorder_are_folders (model, bookmarks);
2862 for (list_iter = bookmarks->added_paths; list_iter ; list_iter = g_list_next (list_iter))
2863 {
2864 GtkTreePath* path = (GtkTreePath*)list_iter->data;
2865
2866 add_parent_to_reorder (model, path, bookmarks);
2867 assert_reorder_are_folders (model, bookmarks);
2868 }
2869
2870 g_list_free_full (bookmarks->added_paths, (GDestroyNotify) gtk_tree_path_free);
2871 bookmarks->added_paths = NULL;
2872
2873 /* do actual reordering */
2874 for (list_iter = bookmarks->reordered_paths; list_iter ; list_iter = g_list_next (list_iter))
2875 {
2876 GtkTreeIter local_iter;
2877 GtkTreePath* path = (GtkTreePath*)list_iter->data;
2878
2879 if (gtk_tree_path_get_depth (path))
2880 {
2881 GtkTreeIter parent;
2882
2883 if (gtk_tree_model_get_iter (model, &parent, path))
2884 {
2885 KatzeItem *item;
2886 gint64 id;
2887
2888 gtk_tree_model_get (model, &parent, 0, &item, -1);
2889
2890 g_assert (KATZE_ITEM_IS_FOLDER (item));
2891
2892 id = katze_item_get_meta_integer (item, "id");
2893
2894 if (gtk_tree_model_iter_children (model, &local_iter, &parent))
2895 midori_bookmarks_set_item_positon(model, &local_iter, id, bookmarks);
2896
2897 /* update folder array for menu update */
2898 katze_array_update (KATZE_ARRAY (item));
2899
2900 g_object_unref (item);
2901 }
2902 }
2903 else
2904 {
2905 if (gtk_tree_model_get_iter_first (model, &local_iter))
2906 midori_bookmarks_set_item_positon(model, &local_iter,
2907 katze_item_get_meta_integer (KATZE_ITEM (bookmarks->bookmarks_db), "id"),
2908 bookmarks);
2909
2910 g_signal_handlers_block_by_func (bookmarks->bookmarks_db,
2911 midori_bookmarks_update_cb,
2912 bookmarks);
2913
2914 /* update folder array for menu update */
2915 katze_array_update (KATZE_ARRAY (bookmarks->bookmarks_db));
2916
2917 g_signal_handlers_unblock_by_func (bookmarks->bookmarks_db,
2918 midori_bookmarks_update_cb,
2919 bookmarks);
2920 }
2921 }
2922
2923 g_list_free_full (bookmarks->reordered_paths, (GDestroyNotify) gtk_tree_path_free);
2924 bookmarks->reordered_paths = NULL;
2925
2926 /* then finalize updates */
2927 g_signal_handlers_block_by_func (bookmarks->bookmarks_db,
2928 midori_bookmarks_update_item_cb,
2929 bookmarks);
2930
2931 g_hash_table_iter_init (&hash_iter, bookmarks->updated_items);
2932
2933 while (g_hash_table_iter_next (&hash_iter, &key, &value))
2934 {
2935 midori_bookmarks_db_update_item (bookmarks->bookmarks_db, KATZE_ITEM (value));
2936 g_object_unref (value);
2937 }
2938
2939 g_signal_handlers_unblock_by_func (bookmarks->bookmarks_db,
2940 midori_bookmarks_update_item_cb,
2941 bookmarks);
2942
2943 g_hash_table_remove_all (bookmarks->updated_items);
2944
2945 /* process pending additions of inserted bookmarks */
2946 for (list_iter = bookmarks->pending_inserts; list_iter; list_iter = g_list_next (list_iter))
2947 {
2948 KatzeItem *item = KATZE_ITEM (list_iter->data);
2949 gint64 id = katze_item_get_meta_integer (item, "id");
2950 GtkTreeIter iter;
2951
2952 if (!midori_bookmarks_reach_item (model, &iter, id))
2953 midori_bookmarks_add_item (item, bookmarks);
2954
2955 g_object_unref (item);
2956 }
2957
2958 g_list_free (bookmarks->pending_inserts);
2959 bookmarks->pending_inserts = NULL;
2960 return midori_bookmarks_idle_pending (bookmarks);
2961}
2962
2963static void
2964midori_bookmarks_update_item (MidoriBookmarks* bookmarks, KatzeItem *item)
2965{
2966 midori_bookmarks_idle_start (bookmarks);
2967
2968 if (g_hash_table_lookup (bookmarks->updated_items, item))
2969 return;
2970
2971 g_object_ref (item);
2972 g_hash_table_insert (bookmarks->updated_items, item, item);
2973}
2974
2975static void
2976midori_bookmarks_idle_remove_item (MidoriBookmarks* bookmarks, KatzeItem *item)
2977{
2978 gpointer found;
2979
2980 if (KATZE_ITEM_IS_FOLDER (item))
2981 {
2982 gint64 id = katze_item_get_meta_integer (item, "id");
2983 GHashTableIter iter;
2984 gpointer key, value;
2985
2986 g_hash_table_iter_init (&iter, bookmarks->updated_items);
2987
2988 while (g_hash_table_iter_next (&iter, &key, &value))
2989 {
2990 KatzeItem *hash_item = KATZE_ITEM(key);
2991
2992 gint64 parentid = katze_item_get_meta_integer (hash_item, "parentid");
2993 if (parentid == id)
2994 {
2995 g_hash_table_iter_remove (&iter);
2996 g_object_unref (hash_item);
2997 }
2998 }
2999 }
3000
3001 if ((found = g_hash_table_lookup (bookmarks->updated_items, item)) != NULL)
3002 {
3003 g_hash_table_remove (bookmarks->updated_items, found);
3004 g_object_unref (found);
3005 }
3006}
3007
1340static void3008static void
1341midori_bookmarks_init (MidoriBookmarks* bookmarks)3009midori_bookmarks_init (MidoriBookmarks* bookmarks)
1342{3010{
@@ -1349,6 +3017,8 @@
1349 GtkCellRenderer* renderer_text;3017 GtkCellRenderer* renderer_text;
1350 GtkTreeSelection* selection;3018 GtkTreeSelection* selection;
13513019
3020 bookmarks->pending_event = NULL;
3021
1352 /* Create the filter entry */3022 /* Create the filter entry */
1353 entry = sokoke_search_entry_new (_("Search Bookmarks"));3023 entry = sokoke_search_entry_new (_("Search Bookmarks"));
1354 g_signal_connect_after (entry, "changed",3024 g_signal_connect_after (entry, "changed",
@@ -1359,7 +3029,7 @@
1359 gtk_box_pack_start (GTK_BOX (bookmarks), box, FALSE, FALSE, 5);3029 gtk_box_pack_start (GTK_BOX (bookmarks), box, FALSE, FALSE, 5);
13603030
1361 /* Create the treeview */3031 /* Create the treeview */
1362 model = gtk_tree_store_new (2, KATZE_TYPE_ITEM, G_TYPE_STRING);3032 model = midori_bookmarks_tree_store_new (2, KATZE_TYPE_ITEM, G_TYPE_STRING);
1363 treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));3033 treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
1364 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);3034 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
1365 gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (treeview), 1);3035 gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (treeview), 1);
@@ -1376,19 +3046,32 @@
1376 (GtkTreeCellDataFunc)midori_bookmarks_treeview_render_text_cb,3046 (GtkTreeCellDataFunc)midori_bookmarks_treeview_render_text_cb,
1377 treeview, NULL);3047 treeview, NULL);
1378 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);3048 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1379 gtk_tree_view_set_reorderable (GTK_TREE_VIEW (treeview), TRUE);3049 gtk_tree_view_set_reorderable (GTK_TREE_VIEW (treeview), FALSE);
3050 gtk_tree_view_enable_model_drag_source (
3051 GTK_TREE_VIEW (treeview),
3052 GDK_BUTTON1_MASK,
3053 midori_bookmarks_dnd_target_entries,
3054 MIDORI_BOOKMARKS_DND_NB_TARGET_ENTRIES,
3055 GDK_ACTION_MOVE|GDK_ACTION_LINK);
3056 gtk_tree_view_enable_model_drag_dest (
3057 GTK_TREE_VIEW (treeview),
3058 midori_bookmarks_dnd_target_entries,
3059 MIDORI_BOOKMARKS_DND_NB_TARGET_ENTRIES,
3060 GDK_ACTION_MOVE|GDK_ACTION_LINK);
1380 g_object_unref (model);3061 g_object_unref (model);
1381 g_object_connect (treeview,3062 g_object_connect (treeview,
1382 "signal::row-activated",3063 "signal::row-activated",
1383 midori_bookmarks_row_activated_cb, bookmarks,3064 midori_bookmarks_row_activated_cb, bookmarks,
3065 "signal::button-press-event",
3066 midori_bookmarks_button_press_event_cb, bookmarks,
1384 "signal::button-release-event",3067 "signal::button-release-event",
1385 midori_bookmarks_button_release_event_cb, bookmarks,3068 midori_bookmarks_button_release_event_cb, bookmarks,
1386 "signal::key-release-event",3069 "signal::key-release-event",
1387 midori_bookmarks_key_release_event_cb, bookmarks,3070 midori_bookmarks_key_release_event_cb, bookmarks,
1388 "signal::popup-menu",3071 "signal::popup-menu",
1389 midori_bookmarks_popup_menu_cb, bookmarks,3072 midori_bookmarks_popup_menu_cb, bookmarks,
1390 "signal::row-expanded",3073 "signal::test-expand-row",
1391 midori_bookmarks_row_expanded_cb, bookmarks,3074 midori_bookmarks_test_expand_row_cb, bookmarks,
1392 "signal::row-collapsed",3075 "signal::row-collapsed",
1393 midori_bookmarks_row_collapsed_cb, bookmarks,3076 midori_bookmarks_row_collapsed_cb, bookmarks,
1394 "signal::enter-notify-event",3077 "signal::enter-notify-event",
@@ -1398,18 +3081,27 @@
1398 "signal::leave-notify-event",3081 "signal::leave-notify-event",
1399 midori_bookmarks_leave_notify_event_cb, bookmarks,3082 midori_bookmarks_leave_notify_event_cb, bookmarks,
1400 NULL);3083 NULL);
1401 gtk_widget_add_events (GTK_WIDGET (treeview), 3084
1402 GDK_POINTER_MOTION_MASK3085 MIDORI_BOOKMARKS_TREE_STORE (model)->_view = GTK_TREE_VIEW (treeview);
1403 | GDK_POINTER_MOTION_HINT_MASK);3086
3087 gtk_widget_add_events (GTK_WIDGET (treeview),
3088 GDK_POINTER_MOTION_MASK
3089 | GDK_POINTER_MOTION_HINT_MASK);
14043090
1405 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));3091 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
3092 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
1406 g_signal_connect_after (selection, "changed",3093 g_signal_connect_after (selection, "changed",
1407 G_CALLBACK (midori_bookmarks_selection_changed_cb),3094 G_CALLBACK (midori_bookmarks_selection_changed_cb),
1408 bookmarks);3095 bookmarks);
1409 gtk_widget_show (treeview);3096 gtk_widget_show (treeview);
1410 gtk_box_pack_start (GTK_BOX (bookmarks), treeview, TRUE, TRUE, 0);3097 gtk_box_pack_start (GTK_BOX (bookmarks), treeview, TRUE, TRUE, 0);
1411 bookmarks->treeview = treeview;3098 bookmarks->treeview = treeview;
3099 bookmarks->pending_inserts = NULL;
1412 bookmarks->hovering_item = NULL;3100 bookmarks->hovering_item = NULL;
3101 bookmarks->pending_inserts = NULL;
3102 bookmarks->updated_items = g_hash_table_new (item_hash, item_equal);
3103 bookmarks->added_paths = NULL;
3104 bookmarks->reordered_paths = NULL;
1413}3105}
14143106
1415static void3107static void
@@ -1420,5 +3112,16 @@
1420 if (bookmarks->app)3112 if (bookmarks->app)
1421 g_object_unref (bookmarks->app);3113 g_object_unref (bookmarks->app);
1422 if (bookmarks->hovering_item)3114 if (bookmarks->hovering_item)
1423 g_object_unref (bookmarks->hovering_item);3115 g_object_unref (bookmarks->hovering_item);
3116
3117 if (g_idle_remove_by_data (bookmarks))
3118 {
3119 g_list_free_full (bookmarks->pending_inserts, (GDestroyNotify) g_object_unref);
3120 bookmarks->pending_inserts = NULL;
3121 g_hash_table_unref (bookmarks->updated_items);
3122 g_list_free_full (bookmarks->added_paths, (GDestroyNotify) gtk_tree_path_free);
3123 bookmarks->added_paths = NULL;
3124 g_list_free_full (bookmarks->reordered_paths, (GDestroyNotify) gtk_tree_path_free);
3125 bookmarks->reordered_paths = NULL;
3126 }
1424}3127}
14253128
=== modified file 'tests/bookmarks.c'
--- tests/bookmarks.c 2013-08-05 19:52:52 +0000
+++ tests/bookmarks.c 2014-01-26 19:44:25 +0000
@@ -128,7 +128,7 @@
128 }128 }
129129
130 db_items = midori_bookmarks_db_query_recursive (db_bookmarks,130 db_items = midori_bookmarks_db_query_recursive (db_bookmarks,
131 "*", "title='%q'", katze_item_get_name (test_item), FALSE);131 "*", "title='%q'", katze_item_get_name (test_item), NULL, FALSE);
132132
133 /* FIXME g_assert_cmpint (katze_array_get_length (db_items), ==, 1); */133 /* FIXME g_assert_cmpint (katze_array_get_length (db_items), ==, 1); */
134 db_item = katze_array_get_nth_item (db_items, 0);134 db_item = katze_array_get_nth_item (db_items, 0);

Subscribers

People subscribed via source and target branches

to all changes: