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

Proposed by André Auzi
Status: Superseded
Proposed branch: lp:~aauzi/midori/fix-1179200
Merge into: lp:midori
Diff against target: 3290 lines (+1933/-637)
12 files modified
katze/katze-array.c (+37/-30)
katze/katze-array.h (+37/-0)
katze/katze-item.c (+8/-2)
midori/midori-array.c (+17/-248)
midori/midori-array.h (+5/-20)
midori/midori-bookmarks-db.c (+1213/-69)
midori/midori-bookmarks-db.h (+60/-21)
midori/midori-browser.c (+87/-48)
midori/midori-frontend.c (+5/-5)
midori/midori.h (+1/-1)
panels/midori-bookmarks.c (+463/-179)
panels/midori-bookmarks.h (+0/-14)
To merge this branch: bzr merge lp:~aauzi/midori/fix-1179200
Reviewer Review Type Date Requested Status
Midori Devs Pending
André Auzi Pending
Review via email: mp+167609@code.launchpad.net

This proposal supersedes a proposal from 2013-05-21.

To post a comment you must log in.
Revision history for this message
Cris Dywan (kalikiana) wrote : Posted in a previous version of this proposal

- if (item->parent)
- katze_array_update ((KatzeArray*)item->parent);
+ if (item->parent && g_strcmp0(icon, picon))
+ katze_array_update_item ((KatzeArray*)item->parent, item);

katze_array_update_item replaces katze_array_update if I see correctly, so that should be mentioned by marking the old one as Deprecated for clarity.

The checks like g_strcmp0(icon, picon) seem to avoid updating if nothing changed - in that case, why not do this for all values in each function?

Revision history for this message
Cris Dywan (kalikiana) wrote : Posted in a previous version of this proposal

A side note on the comment "panels/midori-bookmarks seems to be a view": yes, historically the code is badly mixed, in an ideal world both the panel and the toolbar should be independent views. Much like the Transfers extension these days.

Revision history for this message
André Auzi (aauzi) wrote : Posted in a previous version of this proposal

> - if (item->parent)
> - katze_array_update ((KatzeArray*)item->parent);
> + if (item->parent && g_strcmp0(icon, picon))
> + katze_array_update_item ((KatzeArray*)item->parent, item);
>
> katze_array_update_item replaces katze_array_update if I see correctly, so
> that should be mentioned by marking the old one as Deprecated for clarity.

Not exactly... I kept the update for one purpose, the update of the whole data structure.

Basically here, the update in the bookmark panel, clears the whole tree and reloads it.

It thought this use case was still needed for features like bookmark imports, especially the way it is still designed.

Basically, the array_tree is a container. update is signal signaling an item and its containees, update_item only the item.

You probably have noticed that the update_item in the panel basically:
* finds the item in the tree
* unlinks it from where it is
* finds its new parent
* and relinks the item at its new position.

It doesn't do much if the item and its new parent is not visible.

So far, the bookmark bar does not implement such behaviour, it only refresh the whol bar on item change. This would probablye have to be changed for correct DND reordering of the bookmark bar.

> The checks like g_strcmp0(icon, picon) seem to avoid updating if nothing
> changed - in that case, why not do this for all values in each function?

Well, I didn't do it because it would most probably generate a lot of useless signal traffic.
The design I choose make midori/midori-bookmarks robust to poor design that would do multiple updates of the items but I wouldn't not encourage it. I like the speed of midori as it is.

I therefore just kept the automatic signal of the container on containee change where it was in place (I believe it's due to site title and favicon update after page load, isn't it?)

Revision history for this message
André Auzi (aauzi) wrote : Posted in a previous version of this proposal

> A side note on the comment "panels/midori-bookmarks seems to be a view": yes,
> historically the code is badly mixed, in an ideal world both the panel and the
> toolbar should be independent views. Much like the Transfers extension these
> days.

Yes, I've identified the Model-View-Controller design pattern in the way the code is organised:
* the data base is the Model
* the midori/midori-bookmarks is the Controller
* and bookmarkbar and bookmarkpanel are Views of this model.

With this design pattern actions on the model should go through the controller and that's what I've implemented for delete and update.
I did not do it for insert for two reasons:
1. I didn't intend to change the whole design. I believe there are historical reasons to designs decision that may not be obvious on quick examination. The less I touch the better everybody is :)
2. I do not have a satisfying solution for the provision of the parentid on the insert of a child item I've seen in the file import. No solution => no change.

Revision history for this message
Cris Dywan (kalikiana) wrote : Posted in a previous version of this proposal

> > The checks like g_strcmp0(icon, picon) seem to avoid updating if nothing
> > changed - in that case, why not do this for all values in each function?

> Well, I didn't do it because it would most probably generate a lot of useless signal traffic.
> The design I choose make midori/midori-bookmarks robust to poor design that would do multiple updates of the > items but I wouldn't not encourage it. I like the speed of midori as it is.

> I therefore just kept the automatic signal of the container on containee change where it was in place
> (I believe it's due to site title and favicon update after page load, isn't it?)

What I meant was to wrap the whole of the values that change, for example:

{
     gchar* pname;
     g_return_if_fail (KATZE_IS_ITEM (item));
     pname = item->name;
     if (item->parent && g_strcmp0(name, pname))
     {
         katze_assign (item->name, g_strdup (name));
         katze_array_update((KatzeArray*)item->parent);
         g_object_notify (G_OBJECT (item), "name");
     }
}

I also realize you're doing "pname = item->name" before g_return_if_fail - don't, it will crash if the assertion is hit. Do it as I do above to be on the safe side.

Revision history for this message
André Auzi (aauzi) wrote : Posted in a previous version of this proposal

> What I meant was to wrap the whole of the values that change, for example:
>
> {
> gchar* pname;
> g_return_if_fail (KATZE_IS_ITEM (item));
> pname = item->name;
> if (item->parent && g_strcmp0(name, pname))
> {
> katze_assign (item->name, g_strdup (name));
> katze_array_update((KatzeArray*)item->parent);
> g_object_notify (G_OBJECT (item), "name");
> }
> }
>
> I also realize you're doing "pname = item->name" before g_return_if_fail -
> don't, it will crash if the assertion is hit. Do it as I do above to be on the
> safe side.

OK, understood and agreed.
I will change that.

Revision history for this message
André Auzi (aauzi) wrote : Posted in a previous version of this proposal
Download full text (4.1 KiB)

> > A side note on the comment "panels/midori-bookmarks seems to be a view":
> yes,
> > historically the code is badly mixed, in an ideal world both the panel and
> the
> > toolbar should be independent views. Much like the Transfers extension these
> > days.
>
> Yes, I've identified the Model-View-Controller design pattern in the way the
> code is organised:
> * the data base is the Model
> * the midori/midori-bookmarks is the Controller
> * and bookmarkbar and bookmarkpanel are Views of this model.
>
> With this design pattern actions on the model should go through the controller
> and that's what I've implemented for delete and update.
> I did not do it for insert for two reasons:

Let's do a little follow up on this topic.

Thanks to your remark in Bug #1185595 I felt encouraged to investigate the way bookmarks are retrieved from the database.

My investigations led me to two observations:
 1- katze_array_query_recursive is specialized to "bookmarks" table query due to the fact that the bookmarks table name is hard encoded in it
 2- katze_array_query_recursize lacks the feature of identifying folders item and populate them as katze_array of type KATZE_TYPE_ITEM.

My conclusions are the following:
 1- katze_array_query_recursive should be replaced by something like midori_bookmarks_query_recursive
 2- midori_bookmarks_query_recursive should allways select the column 'uri' of bookmarks in order to identify a folder item
 3- it should then parse the result rows for 'uri' value in order to determine if it can populate a katze_item or a katze_array of type KATZE_TYPE_ITEM

The connection with this bug fix proposal is the following.

The new function midori_bookmarks_query_recursive should be implemented in what I identify as the data base controller: midory/midory-bookmarks.c.

This would allow us to implement one additional steps forward in the direction of convergence of the bookmarks data and fix a concern pfor and I share, the triplication of data between bookmarks menu, bookmarkbar item and bookmarks side panel.

The hash table I used to implement packing of updates, or something similar, can also be used for items retrieval, before populating new items, midori_bookmarks_query_recursive should search the bookmarks array for their existence and only populate a new one a last resort.

Of course, the rows data should be inserted in an existing item, different client view may need different metadata.

To integrate well with the existing fix proposal, midori_bookmarks_query_recursive should flush the pending updates.

pfor, again, tipped me on how this flush could be sped up further: updates should be enclosed into SQLite transactions.

Finally, I was mentioning I did not have a solution for the insert, I think it is not the case anymore.

The katze_array_add_item callback of midori/midori-bookmarks.c should actually process the item added in order to make them available in the bookmarks array hash table.

This callback should change a folder implemented in katze_item into an empty katze_array of type
 KATZE_ARRAY_ITEM before inserting it in the database

It should also go through a katze_array of type KATZE_ARRAY:
 1- insert all child bookm...

Read more...

Revision history for this message
André Auzi (aauzi) wrote : Posted in a previous version of this proposal

> The consequences on the client views are the following:
> 1- they should ignore add_item of katze_array which are not type
> KATZE_TYPE_ITEM
> 2- they should ignore add_item of katze_item of a folder
>

Additional note:

The consequence on client side may be totally removed if midori_bookmarks derives from katze_array and implements the preprocessing of folders (convert in katze_array of type KATZE_ARRAY_ITEM) and the population of the content of a katze_array is done in a specialization of katze_array_add_item.

By doing so we could ensure that *valid* items would be signaled to the client views.

Revision history for this message
André Auzi (aauzi) wrote : Posted in a previous version of this proposal

Ok, I've prototyped the ideas shared in the previous comment.

Now, all the database operations are implemented in midori/midori-bookmarks.c using transactions.

The result is impressive, my 883 bookmarks are now imported in #500ms where it was previously taking more than 6s.

The katze_array_query(_recursive) are now replaced by a fixed midori_bookmarks_query_recursive which ensures that the items are not duplicated between the different views.

Well, this is not clean code yet (far from it) but I was so excited by the impressive improvement that I wanted to share it for maybe some stress test feedback.

I therefore resubmit it as it is and will implement suggested changes in a clean update.

review: Needs Resubmitting
Revision history for this message
André Auzi (aauzi) wrote : Posted in a previous version of this proposal

Well, this is now clean enough.

lp:~aauzi/midori/fix-1179200 updated
6179. By André Auzi

implement complete derivation from KatzeArray for proper database interaction.
midori/midori-bookmarks.[ch] -> midori/midori-bookmarks-db.[ch]
class MidoriBookmarksDb created.

6180. By André Auzi

merge lp:midori
move midori_array_count_recursive into midori_bookmarks_db_count_recursive

6181. By André Auzi

fix relay method selection

6182. By André Auzi

revert changes in katze-item and katze-array,
localize them in midori-bookmarks-db

6183. By André Auzi

merge lp:midori

6184. By André Auzi

insert change 6208 from lp:midori

6185. By André Auzi

cosmetics coding style

6186. By André Auzi

adapt bookmarks unit tests and fix add item issue

6187. By André Auzi

cleanup update_item implementation

6188. By André Auzi

merge lp:midori

6189. By André Auzi

merge lp:midori

6190. By André Auzi

fix potential memory leak

Unmerged revisions

6190. By André Auzi

fix potential memory leak

6189. By André Auzi

merge lp:midori

6188. By André Auzi

merge lp:midori

6187. By André Auzi

cleanup update_item implementation

6186. By André Auzi

adapt bookmarks unit tests and fix add item issue

6185. By André Auzi

cosmetics coding style

6184. By André Auzi

insert change 6208 from lp:midori

6183. By André Auzi

merge lp:midori

6182. By André Auzi

revert changes in katze-item and katze-array,
localize them in midori-bookmarks-db

6181. By André Auzi

fix relay method selection

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 2012-08-08 23:02:56 +0000
+++ katze/katze-array.c 2013-06-11 20:53:24 +0000
@@ -25,40 +25,11 @@
25 * #KatzeArray is a type aware container for items.25 * #KatzeArray is a type aware container for items.
26 */26 */
2727
28struct _KatzeArray
29{
30 KatzeItem parent_instance;
31
32 GType type;
33 GList* items;
34};
35
36struct _KatzeArrayClass
37{
38 KatzeItemClass parent_class;
39
40 /* Signals */
41 void
42 (*add_item) (KatzeArray* array,
43 gpointer item);
44 void
45 (*remove_item) (KatzeArray* array,
46 gpointer item);
47 void
48 (*move_item) (KatzeArray* array,
49 gpointer item,
50 gint index);
51 void
52 (*clear) (KatzeArray* array);
53
54 void
55 (*update) (KatzeArray* array);
56};
57
58G_DEFINE_TYPE (KatzeArray, katze_array, KATZE_TYPE_ITEM);28G_DEFINE_TYPE (KatzeArray, katze_array, KATZE_TYPE_ITEM);
5929
60enum {30enum {
61 ADD_ITEM,31 ADD_ITEM,
32 UPDATE_ITEM,
62 REMOVE_ITEM,33 REMOVE_ITEM,
63 MOVE_ITEM,34 MOVE_ITEM,
64 CLEAR,35 CLEAR,
@@ -95,6 +66,13 @@
95}66}
9667
97static void68static void
69_katze_array_update_item (KatzeArray* array,
70 gpointer item)
71{
72 _katze_array_update (array);
73}
74
75static void
98_katze_array_remove_item (KatzeArray* array,76_katze_array_remove_item (KatzeArray* array,
99 gpointer item)77 gpointer item)
100{78{
@@ -147,6 +125,17 @@
147 G_TYPE_NONE, 1,125 G_TYPE_NONE, 1,
148 G_TYPE_POINTER);126 G_TYPE_POINTER);
149127
128 signals[UPDATE_ITEM] = g_signal_new (
129 "update-item",
130 G_TYPE_FROM_CLASS (class),
131 (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
132 G_STRUCT_OFFSET (KatzeArrayClass, update_item),
133 0,
134 NULL,
135 g_cclosure_marshal_VOID__POINTER,
136 G_TYPE_NONE, 1,
137 G_TYPE_POINTER);
138
150 signals[REMOVE_ITEM] = g_signal_new (139 signals[REMOVE_ITEM] = g_signal_new (
151 "remove-item",140 "remove-item",
152 G_TYPE_FROM_CLASS (class),141 G_TYPE_FROM_CLASS (class),
@@ -213,6 +202,7 @@
213 gobject_class->finalize = katze_array_finalize;202 gobject_class->finalize = katze_array_finalize;
214203
215 class->add_item = _katze_array_add_item;204 class->add_item = _katze_array_add_item;
205 class->update_item = _katze_array_update_item;
216 class->remove_item = _katze_array_remove_item;206 class->remove_item = _katze_array_remove_item;
217 class->move_item = _katze_array_move_item;207 class->move_item = _katze_array_move_item;
218 class->clear = _katze_array_clear;208 class->clear = _katze_array_clear;
@@ -301,6 +291,23 @@
301}291}
302292
303/**293/**
294 * katze_array_update_item:
295 * @array: a #KatzeArray
296 * @item: an item
297 *
298 * Notify an update of the item of the array.
299 *
300 **/
301void
302katze_array_update_item (KatzeArray* array,
303 gpointer item)
304{
305 g_return_if_fail (KATZE_IS_ARRAY (array));
306
307 g_signal_emit (array, signals[UPDATE_ITEM], 0, item);
308}
309
310/**
304 * katze_array_remove_item:311 * katze_array_remove_item:
305 * @array: a #KatzeArray312 * @array: a #KatzeArray
306 * @item: an item313 * @item: an item
307314
=== modified file 'katze/katze-array.h'
--- katze/katze-array.h 2011-01-19 20:58:26 +0000
+++ katze/katze-array.h 2013-06-11 20:53:24 +0000
@@ -32,6 +32,39 @@
32typedef struct _KatzeArray KatzeArray;32typedef struct _KatzeArray KatzeArray;
33typedef struct _KatzeArrayClass KatzeArrayClass;33typedef struct _KatzeArrayClass KatzeArrayClass;
3434
35struct _KatzeArray
36{
37 KatzeItem parent_instance;
38
39 GType type;
40 GList* items;
41};
42
43struct _KatzeArrayClass
44{
45 KatzeItemClass parent_class;
46
47 /* Signals */
48 void
49 (*add_item) (KatzeArray* array,
50 gpointer item);
51 void
52 (*update_item) (KatzeArray* array,
53 gpointer item);
54 void
55 (*remove_item) (KatzeArray* array,
56 gpointer item);
57 void
58 (*move_item) (KatzeArray* array,
59 gpointer item,
60 gint index);
61 void
62 (*clear) (KatzeArray* array);
63
64 void
65 (*update) (KatzeArray* array);
66};
67
35GType68GType
36katze_array_get_type (void) G_GNUC_CONST;69katze_array_get_type (void) G_GNUC_CONST;
3770
@@ -47,6 +80,10 @@
47 gpointer item);80 gpointer item);
4881
49void82void
83katze_array_update_item (KatzeArray* array,
84 gpointer item);
85
86void
50katze_array_remove_item (KatzeArray* array,87katze_array_remove_item (KatzeArray* array,
51 gpointer item);88 gpointer item);
5289
5390
=== modified file 'katze/katze-item.c'
--- katze/katze-item.c 2013-05-31 22:00:38 +0000
+++ katze/katze-item.c 2013-06-11 20:53:24 +0000
@@ -316,9 +316,12 @@
316{316{
317 g_return_if_fail (KATZE_IS_ITEM (item));317 g_return_if_fail (KATZE_IS_ITEM (item));
318318
319 if (!g_strcmp0 (item->name, name))
320 return;
321
319 katze_assign (item->name, g_strdup (name));322 katze_assign (item->name, g_strdup (name));
320 if (item->parent)323 if (item->parent)
321 katze_array_update ((KatzeArray*)item->parent);324 katze_array_update_item ((KatzeArray*)item->parent, item);
322 g_object_notify (G_OBJECT (item), "name");325 g_object_notify (G_OBJECT (item), "name");
323}326}
324327
@@ -420,9 +423,12 @@
420{423{
421 g_return_if_fail (KATZE_IS_ITEM (item));424 g_return_if_fail (KATZE_IS_ITEM (item));
422425
426 if (!g_strcmp0 (katze_item_get_meta_string (item, "icon"), icon))
427 return;
428
423 katze_item_set_meta_string (item, "icon", icon);429 katze_item_set_meta_string (item, "icon", icon);
424 if (item->parent)430 if (item->parent)
425 katze_array_update ((KatzeArray*)item->parent);431 katze_array_update_item ((KatzeArray*)item->parent, item);
426 g_object_notify (G_OBJECT (item), "icon");432 g_object_notify (G_OBJECT (item), "icon");
427}433}
428434
429435
=== modified file 'midori/midori-array.c'
--- midori/midori-array.c 2013-05-30 21:57:04 +0000
+++ midori/midori-array.c 2013-06-11 20:53:24 +0000
@@ -97,15 +97,15 @@
97 if (katze_str_equal ((gchar*)cur->name, "title"))97 if (katze_str_equal ((gchar*)cur->name, "title"))
98 {98 {
99 gchar* value = g_strstrip ((gchar*)xmlNodeGetContent (cur));99 gchar* value = g_strstrip ((gchar*)xmlNodeGetContent (cur));
100 katze_item_set_name (KATZE_ITEM (array), value);
101 xmlFree (value);
102 }
103 else if (katze_str_equal ((gchar*)cur->name, "desc"))
104 {
105 gchar* value = g_strstrip ((gchar*)xmlNodeGetContent (cur));
100 katze_item_set_text (KATZE_ITEM (array), value);106 katze_item_set_text (KATZE_ITEM (array), value);
101 xmlFree (value);107 xmlFree (value);
102 }108 }
103 else if (katze_str_equal ((gchar*)cur->name, "desc"))
104 {
105 gchar* value = g_strstrip ((gchar*)xmlNodeGetContent (cur));
106 katze_item_set_name (KATZE_ITEM (array), value);
107 xmlFree (value);
108 }
109 else if (katze_str_equal ((gchar*)cur->name, "info"))109 else if (katze_str_equal ((gchar*)cur->name, "info"))
110 katze_xbel_parse_info ((KatzeItem*)array, cur);110 katze_xbel_parse_info ((KatzeItem*)array, cur);
111 else if (katze_str_equal ((gchar*)cur->name, "folder"))111 else if (katze_str_equal ((gchar*)cur->name, "folder"))
@@ -986,7 +986,17 @@
986 return FALSE;986 return FALSE;
987}987}
988988
989static void989/**
990 * katze_item_set_value_from_columne:
991 * @stmt: prepared statement
992 * @column: column to read
993 * @item: #KatzeItem to populate
994 *
995 * Stores the column in the given #KatzeItem.
996 *
997 * Since: 0.2.7
998 **/
999void
990katze_item_set_value_from_column (sqlite3_stmt* stmt,1000katze_item_set_value_from_column (sqlite3_stmt* stmt,
991 gint column,1001 gint column,
992 KatzeItem* item)1002 KatzeItem* item)
@@ -1103,244 +1113,3 @@
1103 return katze_array_from_statement (stmt);1113 return katze_array_from_statement (stmt);
1104}1114}
11051115
1106/**
1107 * midori_array_query_recursive:
1108 * @array: the main bookmark array
1109 * @fields: comma separated list of fields
1110 * @condition: condition, like "folder = '%q'"
1111 * @value: a value to be inserted if @condition contains %q
1112 * @recursive: if %TRUE include children
1113 *
1114 * Stores the result in a #KatzeArray.
1115 *
1116 * Return value: a #KatzeArray on success, %NULL otherwise
1117 *
1118 * Since: 0.4.4
1119 **/
1120KatzeArray*
1121midori_array_query_recursive (KatzeArray* bookmarks,
1122 const gchar* fields,
1123 const gchar* condition,
1124 const gchar* value,
1125 gboolean recursive)
1126{
1127 sqlite3* db;
1128 gchar* sqlcmd;
1129 char* sqlcmd_value;
1130 KatzeArray* array;
1131 KatzeItem* item;
1132 GList* list;
1133
1134 g_return_val_if_fail (KATZE_IS_ARRAY (bookmarks), NULL);
1135 g_return_val_if_fail (fields, NULL);
1136 g_return_val_if_fail (condition, NULL);
1137 db = g_object_get_data (G_OBJECT (bookmarks), "db");
1138 g_return_val_if_fail (db != NULL, NULL);
1139
1140 sqlcmd = g_strdup_printf ("SELECT %s FROM bookmarks WHERE %s "
1141 "ORDER BY (uri='') ASC, title DESC", fields, condition);
1142 if (strstr (condition, "%q"))
1143 {
1144 sqlcmd_value = sqlite3_mprintf (sqlcmd, value ? value : "");
1145 array = katze_array_from_sqlite (db, sqlcmd_value);
1146 sqlite3_free (sqlcmd_value);
1147 }
1148 else
1149 array = katze_array_from_sqlite (db, sqlcmd);
1150 g_free (sqlcmd);
1151
1152 if (!recursive)
1153 return array;
1154
1155 KATZE_ARRAY_FOREACH_ITEM_L (item, array, list)
1156 {
1157 if (KATZE_ITEM_IS_FOLDER (item))
1158 {
1159 gchar* parentid = g_strdup_printf ("%" G_GINT64_FORMAT,
1160 katze_item_get_meta_integer (item, "id"));
1161 KatzeArray* subarray = midori_array_query_recursive (bookmarks,
1162 fields, "parentid=%q", parentid, TRUE);
1163 katze_item_set_name (KATZE_ITEM (subarray), katze_item_get_name (item));
1164 katze_array_add_item (array, subarray);
1165
1166 g_free (parentid);
1167 }
1168 }
1169 g_list_free (list);
1170 return array;
1171}
1172
1173/**
1174 * midori_array_query:
1175 * @array: the main bookmark array
1176 * @fields: comma separated list of fields
1177 * @condition: condition, like "folder = '%q'"
1178 * @value: a value to be inserted if @condition contains %q
1179 *
1180 * Stores the result in a #KatzeArray.
1181 *
1182 * Return value: a #KatzeArray on success, %NULL otherwise
1183 *
1184 * Since: 0.4.3
1185 *
1186 * Deprecated: 0.4.4: Use midori_array_query_recursive() instead.
1187 **/
1188KatzeArray*
1189midori_array_query (KatzeArray* bookmarks,
1190 const gchar* fields,
1191 const gchar* condition,
1192 const gchar* value)
1193{
1194 return midori_array_query_recursive (bookmarks, fields, condition, value, FALSE);
1195}
1196
1197static gint64
1198count_from_sqlite (sqlite3* db,
1199 const gchar* sqlcmd)
1200{
1201 gint64 count = -1;
1202 sqlite3_stmt* stmt;
1203 gint result;
1204
1205 result = sqlite3_prepare_v2 (db, sqlcmd, -1, &stmt, NULL);
1206 if (result != SQLITE_OK)
1207 return -1;
1208
1209 g_assert (sqlite3_column_count (stmt) == 1);
1210
1211 if ((result = sqlite3_step (stmt)) == SQLITE_ROW)
1212 count = sqlite3_column_int64(stmt, 0);
1213
1214 sqlite3_clear_bindings (stmt);
1215 sqlite3_reset (stmt);
1216
1217 return count;
1218}
1219
1220static gint64
1221midori_array_count_recursive_by_id (KatzeArray* bookmarks,
1222 const gchar* condition,
1223 const gchar* value,
1224 gint64 id,
1225 gboolean recursive)
1226{
1227 gint64 count = -1;
1228 sqlite3* db;
1229 gchar* sqlcmd;
1230 char* sqlcmd_value;
1231 sqlite3_stmt* stmt;
1232 gint result;
1233 GList* ids;
1234 GList* iter_ids;
1235
1236 g_return_val_if_fail (condition, -1);
1237 g_return_val_if_fail (KATZE_IS_ARRAY (bookmarks), -1);
1238 db = g_object_get_data (G_OBJECT (bookmarks), "db");
1239 g_return_val_if_fail (db != NULL, -1);
1240
1241 g_assert(!strstr("parentid", condition));
1242
1243 if (id > 0)
1244 sqlcmd = g_strdup_printf ("SELECT COUNT(*) FROM bookmarks "
1245 "WHERE parentid = %" G_GINT64_FORMAT " AND %s",
1246 id,
1247 condition);
1248 else
1249 sqlcmd = g_strdup_printf ("SELECT COUNT(*) FROM bookmarks "
1250 "WHERE parentid IS NULL AND %s ",
1251 condition);
1252
1253 if (strstr (condition, "%q"))
1254 {
1255 sqlcmd_value = sqlite3_mprintf (sqlcmd, value ? value : "");
1256 count = count_from_sqlite (db, sqlcmd_value);
1257 sqlite3_free (sqlcmd_value);
1258 }
1259 else
1260 count = count_from_sqlite (db, sqlcmd);
1261
1262 g_free (sqlcmd);
1263
1264 if (!recursive || (count < 0))
1265 return count;
1266
1267 ids = NULL;
1268
1269 if (id > 0)
1270 sqlcmd_value = sqlite3_mprintf (
1271 "SELECT id FROM bookmarks "
1272 "WHERE parentid = %" G_GINT64_FORMAT " AND uri = ''", id);
1273 else
1274 sqlcmd_value = sqlite3_mprintf (
1275 "SELECT id FROM bookmarks "
1276 "WHERE parentid IS NULL AND uri = ''");
1277
1278 if (sqlite3_prepare_v2 (db, sqlcmd_value, -1, &stmt, NULL) == SQLITE_OK)
1279 {
1280 g_assert (sqlite3_column_count (stmt) == 1);
1281
1282 if ((result = sqlite3_step (stmt)) == SQLITE_ROW)
1283 {
1284 gint64* pid = g_new (gint64, 1);
1285
1286 *pid = sqlite3_column_int64(stmt, 0);
1287 ids = g_list_append (ids, pid);
1288 }
1289
1290 sqlite3_clear_bindings (stmt);
1291 sqlite3_reset (stmt);
1292 }
1293
1294 sqlite3_free (sqlcmd_value);
1295
1296 iter_ids = ids;
1297 while (iter_ids)
1298 {
1299 gint64 sub_count = midori_array_count_recursive_by_id (bookmarks,
1300 condition,
1301 value,
1302 *(gint64*)(iter_ids->data),
1303 recursive);
1304
1305 if (sub_count < 0)
1306 {
1307 g_list_free_full (ids, g_free);
1308 return -1;
1309 }
1310
1311 count += sub_count;
1312 iter_ids = g_list_next (iter_ids);
1313 }
1314
1315 g_list_free_full (ids, g_free);
1316 return count;
1317}
1318
1319/**
1320 * midori_array_count_recursive:
1321 * @array: the main bookmark array
1322 * @condition: condition, like "folder = '%q'"
1323 * @value: a value to be inserted if @condition contains %q
1324 * @recursive: if %TRUE include children
1325 *
1326 * Return value: the number of elements on success, -1 otherwise
1327 *
1328 * Since: 0.5.2
1329 **/
1330gint64
1331midori_array_count_recursive (KatzeArray* bookmarks,
1332 const gchar* condition,
1333 const gchar* value,
1334 KatzeItem* folder,
1335 gboolean recursive)
1336{
1337 gint64 id = -1;
1338
1339 g_return_val_if_fail (!folder || KATZE_ITEM_IS_FOLDER (folder), -1);
1340
1341 id = folder ? katze_item_get_meta_integer (folder, "id") : 0;
1342
1343 return midori_array_count_recursive_by_id (bookmarks, condition,
1344 value, id,
1345 recursive);
1346}
13471116
=== modified file 'midori/midori-array.h'
--- midori/midori-array.h 2013-05-21 21:46:26 +0000
+++ midori/midori-array.h 2013-06-11 20:53:24 +0000
@@ -27,31 +27,16 @@
27 const gchar* format,27 const gchar* format,
28 GError** error);28 GError** error);
2929
30void
31katze_item_set_value_from_column (sqlite3_stmt* stmt,
32 gint column,
33 KatzeItem* item);
34
30KatzeArray*35KatzeArray*
31katze_array_from_statement (sqlite3_stmt* stmt);36katze_array_from_statement (sqlite3_stmt* stmt);
3237
33KatzeArray*38KatzeArray*
34midori_array_query (KatzeArray* array,
35 const gchar* fields,
36 const gchar* condition,
37 const gchar* value);
38
39KatzeArray*
40midori_array_query_recursive (KatzeArray* array,
41 const gchar* fields,
42 const gchar* condition,
43 const gchar* value,
44 gboolean recursive);
45
46KatzeArray*
47katze_array_from_sqlite (sqlite3* db,39katze_array_from_sqlite (sqlite3* db,
48 const gchar* sqlcmd);40 const gchar* sqlcmd);
4941
50gint64
51midori_array_count_recursive (KatzeArray* bookmarks,
52 const gchar* condition,
53 const gchar* value,
54 KatzeItem* folder,
55 gboolean recursive);
56
57#endif /* !__MIDORI_ARRAY_H__ */42#endif /* !__MIDORI_ARRAY_H__ */
5843
=== renamed file 'midori/midori-bookmarks.c' => 'midori/midori-bookmarks-db.c'
--- midori/midori-bookmarks.c 2012-11-25 15:37:41 +0000
+++ midori/midori-bookmarks-db.c 2013-06-11 20:53:24 +0000
@@ -10,8 +10,8 @@
10 See the file COPYING for the full license text.10 See the file COPYING for the full license text.
11*/11*/
1212
13#include "midori-bookmarks.h"13#include "midori-bookmarks-db.h"
14#include "panels/midori-bookmarks.h"14
15#include "midori-app.h"15#include "midori-app.h"
16#include "midori-array.h"16#include "midori-array.h"
17#include "sokoke.h"17#include "sokoke.h"
@@ -25,42 +25,818 @@
25 #include <unistd.h>25 #include <unistd.h>
26#endif26#endif
2727
28void28/**
29midori_bookmarks_dbtracer (void* dummy,29 * SECTION:midory-bookmarks-db
30 const char* query)30 * @short_description: A #KatzeArray connected to a database
31{31 * @see_also: #KatzeArray
32 g_printerr ("%s\n", query);32 *
33}33 * #MidoriBookmarksDb is a #KatzeArray specialized for database
3434 * interraction.
35void35 */
36midori_bookmarks_add_item_cb (KatzeArray* array,36
37 KatzeItem* item,37struct _MidoriBookmarksDb
38 sqlite3* db)38{
39{39 KatzeArray parent_instance;
40 midori_bookmarks_insert_item_db (db, item,40
41 katze_item_get_meta_integer (item, "parentid"));41 sqlite3* db;
42}42 GList* pending_inserts;
4343 GHashTable* pending_updates;
44void44 GHashTable* pending_deletes;
45midori_bookmarks_remove_item_cb (KatzeArray* array,45 GHashTable* all_items;
46 KatzeItem* item,46 gboolean in_idle_func;
47 sqlite3* db)47};
48{48
49 gchar* sqlcmd;49struct _MidoriBookmarksDbClass
50 char* errmsg = NULL;50{
5151 KatzeArrayClass parent_class;
5252};
53 sqlcmd = sqlite3_mprintf (53
54 "DELETE FROM bookmarks WHERE id = %" G_GINT64_FORMAT ";",54G_DEFINE_TYPE (MidoriBookmarksDb, midori_bookmarks_db, KATZE_TYPE_ARRAY);
55
56static void
57_midori_bookmarks_db_add_item (KatzeArray* array,
58 gpointer item);
59
60static void
61_midori_bookmarks_db_update_item (KatzeArray* array,
62 gpointer item);
63
64static void
65_midori_bookmarks_db_remove_item (KatzeArray* array,
66 gpointer item);
67
68static void
69_midori_bookmarks_db_move_item (KatzeArray* array,
70 gpointer item,
71 gint position);
72
73static void
74_midori_bookmarks_db_clear (KatzeArray* array);
75
76static void
77midori_bookmarks_db_force_idle (MidoriBookmarksDb* bookmarks);
78
79static void
80midori_bookmarks_db_finalize (GObject* object);
81
82static gint64
83midori_bookmarks_db_insert_item_db (sqlite3* db,
84 KatzeItem* item,
85 gint64 parentid);
86
87static gboolean
88midori_bookmarks_db_update_item_db (sqlite3* db,
89 KatzeItem* item);
90
91static gboolean
92midori_bookmarks_db_remove_item_db (sqlite3* db,
93 KatzeItem* item);
94
95static guint
96item_hash (gconstpointer item)
97{
98 gint64 id = katze_item_get_meta_integer (KATZE_ITEM (item), "id");
99 return g_int64_hash (&id);
100}
101
102static gboolean
103item_equal (gconstpointer item_a, gconstpointer item_b)
104{
105 gint64 id_a = katze_item_get_meta_integer (KATZE_ITEM (item_a), "id");
106 gint64 id_b = katze_item_get_meta_integer (KATZE_ITEM (item_b), "id");
107 return (id_a == id_b)? TRUE : FALSE;
108}
109
110static void
111midori_bookmarks_db_class_init (MidoriBookmarksDbClass* class)
112{
113 GObjectClass* gobject_class;
114 KatzeArrayClass* katze_array_class;
115
116 gobject_class = G_OBJECT_CLASS (class);
117 gobject_class->finalize = midori_bookmarks_db_finalize;
118
119 katze_array_class = KATZE_ARRAY_CLASS (class);
120
121 katze_array_class->add_item = _midori_bookmarks_db_add_item;
122 katze_array_class->update_item = _midori_bookmarks_db_update_item;
123 katze_array_class->remove_item = _midori_bookmarks_db_remove_item;
124 katze_array_class->move_item = _midori_bookmarks_db_move_item;
125 katze_array_class->clear = _midori_bookmarks_db_clear;
126}
127
128static void
129midori_bookmarks_db_init (MidoriBookmarksDb* bookmarks)
130{
131 bookmarks->db = NULL;
132 bookmarks->pending_inserts = NULL;
133 bookmarks->pending_updates = g_hash_table_new (item_hash, item_equal);
134 bookmarks->pending_deletes = g_hash_table_new (item_hash, item_equal);
135 bookmarks->all_items = g_hash_table_new (item_hash, item_equal);
136
137 bookmarks->in_idle_func = FALSE;
138
139 katze_item_set_meta_integer (KATZE_ITEM (bookmarks), "id", 0);
140 g_hash_table_insert (bookmarks->all_items, bookmarks, bookmarks);
141 /* g_object_ref (bookmarks); */
142}
143
144static void
145midori_bookmarks_db_finalize (GObject* object)
146{
147 MidoriBookmarksDb* bookmarks = MIDORI_BOOKMARKS_DB (object);
148
149 if (bookmarks->db)
150 {
151 midori_bookmarks_db_force_idle (bookmarks);
152 sqlite3_close (bookmarks->db);
153 }
154
155 g_list_free (bookmarks->pending_inserts);
156 g_hash_table_unref (bookmarks->pending_updates);
157 g_hash_table_unref (bookmarks->pending_deletes);
158 g_hash_table_unref (bookmarks->all_items);
159
160 G_OBJECT_CLASS (midori_bookmarks_db_parent_class)->finalize (object);
161}
162
163/**
164 * midori_bookmarks_db_get_item_parent:
165 * @bookmarks: the main bookmarks array
166 * @item: a #KatzeItem
167 *
168 * Internal function that find the parent of the @item thanks to its %parentid
169 **/
170static KatzeArray*
171midori_bookmarks_db_get_item_parent (MidoriBookmarksDb* bookmarks,
172 gpointer item)
173{
174 KatzeArray* parent;
175 gint64 parentid;
176
177 parentid = katze_item_get_meta_integer (KATZE_ITEM (item), "parentid");
178
179 if (parentid == 0)
180 {
181 parent = KATZE_ARRAY (bookmarks);
182 }
183 else
184 {
185 KatzeItem *search = katze_item_new ();
186
187 katze_item_set_meta_integer(search, "id", parentid);
188
189 parent = KATZE_ARRAY (g_hash_table_lookup (bookmarks->all_items, search));
190
191 g_object_unref (search);
192 }
193
194 return parent;
195}
196
197/**
198 * _midori_bookmarks_db_add_item:
199 * @array: the main bookmarks array
200 * @item: a #KatzeItem
201 *
202 * Internal function that overloads the #KatzeArray %katze_array_add_item().
203 * It relays the add item to the appropriate #KatzeArray.
204 **/
205static void
206_midori_bookmarks_db_add_item (KatzeArray* array,
207 gpointer item)
208{
209 MidoriBookmarksDb *bookmarks;
210 KatzeArray* parent;
211
212 g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (array));
213 g_return_if_fail (KATZE_IS_ITEM (item));
214
215 bookmarks = MIDORI_BOOKMARKS_DB (array);
216 g_return_if_fail (bookmarks->in_idle_func);
217
218 parent = katze_item_get_parent (KATZE_ITEM (item));
219
220 g_return_if_fail (!parent);
221
222 parent = midori_bookmarks_db_get_item_parent (bookmarks, item);
223
224 g_return_if_fail (parent);
225
226 KATZE_ARRAY_CLASS (midori_bookmarks_db_parent_class)->add_item (parent, item);
227}
228
229/**
230 * _midori_bookmarks_db_update_item:
231 * @array: the main bookmarks array
232 * @item: a #KatzeItem
233 *
234 * Internal function that overloads the #KatzeArray %katze_array_update_item().
235 * It relays the update item to the appropriate #KatzeArray.
236 **/
237static void
238_midori_bookmarks_db_update_item (KatzeArray* array,
239 gpointer item)
240{
241 MidoriBookmarksDb *bookmarks;
242 KatzeArray* parent;
243
244 g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (array));
245 g_return_if_fail (KATZE_IS_ITEM (item));
246
247 bookmarks = MIDORI_BOOKMARKS_DB (array);
248 g_return_if_fail (bookmarks->in_idle_func);
249
250 parent = katze_item_get_parent (KATZE_ITEM (item));
251
252 g_return_if_fail (parent);
253
254 KATZE_ARRAY_CLASS (midori_bookmarks_db_parent_class)->update_item (parent, item);
255}
256
257/**
258 * _midori_bookmarks_db_remove_item:
259 * @array: the main bookmarks array
260 * @item: a #KatzeItem
261 *
262 * Internal function that overloads the #KatzeArray %katze_array_remove_item().
263 * It relays the remove item to the appropriate #KatzeArray.
264 **/
265static void
266_midori_bookmarks_db_remove_item (KatzeArray* array,
267 gpointer item)
268{
269 MidoriBookmarksDb *bookmarks;
270 KatzeArray* parent;
271
272 g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (array));
273 g_return_if_fail (KATZE_IS_ITEM (item));
274
275 bookmarks = MIDORI_BOOKMARKS_DB (array);
276 g_return_if_fail (bookmarks->in_idle_func);
277
278 parent = katze_item_get_parent (KATZE_ITEM (item));
279
280 g_return_if_fail (parent);
281
282 KATZE_ARRAY_CLASS (midori_bookmarks_db_parent_class)->remove_item (parent, item);
283}
284
285/**
286 * _midori_bookmarks_db_move_item:
287 * @array: the main bookmarks array
288 * @item: a #KatzeItem
289 * @position: the new @item position
290 *
291 * Internal function that overloads the #KatzeArray %katze_array_move_item().
292 * It relays the move @item to the appropriate #KatzeArray.
293 **/
294static void
295_midori_bookmarks_db_move_item (KatzeArray* array,
296 gpointer item,
297 gint position)
298{
299 MidoriBookmarksDb *bookmarks;
300 KatzeArray* parent;
301
302 g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (array));
303 g_return_if_fail (KATZE_IS_ITEM (item));
304
305 parent = katze_item_get_parent (KATZE_ITEM (item));
306
307 g_return_if_fail (parent);
308
309 KATZE_ARRAY_CLASS (midori_bookmarks_db_parent_class)->move_item (parent, item, position);
310}
311
312/**
313 * _midori_bookmarks_db_clear:
314 * @array: the main bookmarks array
315 *
316 * Internal function that overloads the #KatzeArray %katze_array_clear().
317 * It deletes the whole bookmarks data.
318 **/
319static void
320_midori_bookmarks_db_clear (KatzeArray* array)
321{
322 MidoriBookmarksDb *bookmarks;
323 g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (array));
324
325 bookmarks = MIDORI_BOOKMARKS_DB (array);
326
327 g_critical ("_midori_bookmarks_db_clear: not implemented\n");
328}
329
330/**
331 * midori_bookmarks_db_begin_transaction:
332 * @db: the removed #KatzeItem
333 *
334 * Internal function that starts an SQL transaction.
335 **/
336static gboolean
337midori_bookmarks_db_begin_transaction (sqlite3* db)
338{
339 char* errmsg = NULL;
340
341 if (sqlite3_exec (db, "BEGIN TRANSACTION;", NULL, NULL, &errmsg) != SQLITE_OK)
342 {
343 g_printerr (_("Failed to begin transaction: %s\n"), errmsg);
344 sqlite3_free (errmsg);
345 return FALSE;
346 }
347
348 return TRUE;
349}
350
351/**
352 * midori_bookmarks_db_end_transaction:
353 * @db: the removed #KatzeItem
354 * @commit : boolean
355 *
356 * Internal function that ends an SQL transaction.
357 * If @commit is %TRUE, the transaction is ended by a COMMIT.
358 * It is ended by a ROLLBACK otherwise.
359 **/
360static void
361midori_bookmarks_db_end_transaction (sqlite3* db, gboolean commit)
362{
363 char* errmsg = NULL;
364 if (sqlite3_exec (db, (commit ? "COMMIT;" : "ROLLBACK;"), NULL, NULL, &errmsg) != SQLITE_OK)
365 {
366 if (commit)
367 g_printerr (_("Failed to end transaction: %s\n"), errmsg);
368 else
369 g_printerr (_("Failed to cancel transaction: %s\n"), errmsg);
370 sqlite3_free (errmsg);
371 }
372}
373
374/**
375 * midori_bookmarks_db_add_item_recursive:
376 * @item: the removed #KatzeItem
377 * @bookmarks : the main bookmarks array
378 *
379 * Internal function that creates memory records of the added @item.
380 * If @item is a #KatzeArray, the function recursiveley adds records
381 * of all its childs.
382 **/
383static gint
384midori_bookmarks_db_add_item_recursive (MidoriBookmarksDb* bookmarks,
385 KatzeItem* item)
386{
387 GList* list;
388 KatzeArray* array;
389 gint64 id = 0;
390 gint count = 0;
391 gint64 parentid = katze_item_get_meta_integer (item, "parentid");
392
393 id = midori_bookmarks_db_insert_item_db (bookmarks->db, item, parentid);
394 count++;
395
396 g_object_ref (item);
397 g_hash_table_insert (bookmarks->all_items, item, item);
398
399 if (!KATZE_IS_ARRAY (item))
400 return count;
401
402 array = KATZE_ARRAY (item);
403
404 KATZE_ARRAY_FOREACH_ITEM_L (item, array, list)
405 {
406 katze_item_set_meta_integer (item, "parentid", id);
407 count += midori_bookmarks_db_add_item_recursive (bookmarks, item);
408 }
409
410 g_list_free (list);
411 return count;
412}
413
414/**
415 * midori_bookmarks_db_remove_item_recursive:
416 * @item: the removed #KatzeItem
417 * @bookmarks : the main bookmarks array
418 *
419 * Internal function that removes memory records of the removed @item.
420 * If @item is a #KatzeArray, the function recursiveley removes records
421 * of all its childs.
422 **/
423static void
424midori_bookmarks_db_remove_item_recursive (KatzeItem* item,
425 MidoriBookmarksDb* bookmarks)
426{
427 gint64 id = katze_item_get_meta_integer (item, "id");
428 GHashTableIter hash_iter;
429 gpointer key, value;
430 gpointer found;
431 KatzeArray* array;
432 KatzeItem* child;
433 GList* list;
434
435 if (NULL != (found = g_list_find (bookmarks->pending_inserts, item)))
436 {
437 g_object_unref (((GList*)found)->data);
438 bookmarks->pending_inserts = g_list_delete_link (bookmarks->pending_inserts,
439 ((GList*)found));
440 }
441
442 if (NULL != (found = g_hash_table_lookup (bookmarks->pending_updates, item)))
443 {
444 g_hash_table_remove (bookmarks->pending_updates, found);
445 g_object_unref (found);
446 }
447
448 if (NULL != (found = g_hash_table_lookup (bookmarks->all_items, item)))
449 {
450 g_hash_table_remove (bookmarks->all_items, found);
451 g_object_unref (found);
452 }
453
454 if (!KATZE_IS_ARRAY (item))
455 return;
456
457 array = KATZE_ARRAY (item);
458
459 KATZE_ARRAY_FOREACH_ITEM_L (child, array, list)
460 {
461 midori_bookmarks_db_remove_item_recursive (child, bookmarks);
462 }
463
464 g_list_free (list);
465}
466
467/**
468 * midori_bookmarks_db_idle_func:
469 * @data: the main bookmark array
470 *
471 * Internal function executed during idle time that Packs pending database
472 * operations in one transaction.
473 *
474 * Pending operations are either:
475 * a. a list of pending add items,
476 * all child #KatzeItem of a #KatzeArray are recursively added.
477 * Each added #KatzeItem is memorized for future use.
478 * (See %midori_bookmarks_db_array_from_statement())
479 * b. a hash table of items to update,
480 * c. or a hash table of items to remove
481 * the database CASCADE on delete takes care of removal of the childs
482 * #KatzeItem of a #KatzeArray in the database
483 *
484 * When database operations are done, the #KatzeArray equivalent operations
485 * are called to:
486 * 1. update the #KatzeArray tree content
487 * 2. signal the client views of the #KatzeArray tree content change.
488 **/
489static gboolean
490midori_bookmarks_db_idle_func (gpointer data)
491{
492 GTimer *timer = g_timer_new();
493 gint count = 0;
494 gulong microseconds;
495 gboolean with_transaction;
496 MidoriBookmarksDb* bookmarks = MIDORI_BOOKMARKS_DB (data);
497 GList* list_iter;
498 GHashTableIter hash_iter;
499 gpointer key, value;
500
501 bookmarks->in_idle_func = TRUE;
502
503 g_timer_start (timer);
504
505 with_transaction = midori_bookmarks_db_begin_transaction (bookmarks->db);
506
507 for (list_iter = bookmarks->pending_inserts; list_iter; list_iter = g_list_next (list_iter))
508 {
509 KatzeItem *item = KATZE_ITEM (list_iter->data);
510
511 count += midori_bookmarks_db_add_item_recursive (bookmarks, item);
512 katze_array_add_item (KATZE_ARRAY (bookmarks), item);
513
514 g_object_unref (item);
515 }
516
517 g_hash_table_iter_init (&hash_iter, bookmarks->pending_updates);
518
519 while (g_hash_table_iter_next (&hash_iter, &key, &value))
520 {
521 KatzeItem *item = KATZE_ITEM (value);
522
523 midori_bookmarks_db_update_item_db (bookmarks->db, item);
524 katze_array_update_item (KATZE_ARRAY (bookmarks), item);
525 g_object_unref (item);
526 count++;
527 }
528
529 g_hash_table_iter_init (&hash_iter, bookmarks->pending_deletes);
530
531 while (g_hash_table_iter_next (&hash_iter, &key, &value))
532 {
533 KatzeItem *item = KATZE_ITEM (value);
534
535 midori_bookmarks_db_remove_item_db (bookmarks->db, item);
536 katze_array_remove_item (KATZE_ARRAY (bookmarks), item);
537 g_object_unref (item);
538 count++;
539 }
540
541 if (with_transaction)
542 midori_bookmarks_db_end_transaction (bookmarks->db, TRUE);
543
544 g_timer_elapsed (timer, &microseconds);
545 g_print ("midori_bookmarks_db_idle: %d DB operation(s) in %lu micro-seconds\n",
546 count, microseconds);
547
548 g_timer_destroy (timer);
549
550 g_hash_table_remove_all (bookmarks->pending_deletes);
551 g_hash_table_remove_all (bookmarks->pending_updates);
552 g_list_free (bookmarks->pending_inserts);
553 bookmarks->pending_inserts = NULL;
554
555 bookmarks->in_idle_func = FALSE;
556
557 return FALSE;
558}
559
560/**
561 * midori_bookmarks_db_idle_start:
562 * @bookmarks: the main bookmark array
563 *
564 * Internal function that checks whether idle processing is pending,
565 * if not, add a new one.
566 **/
567static void
568midori_bookmarks_db_idle_start (MidoriBookmarksDb* bookmarks)
569{
570 g_return_if_fail (bookmarks->db != NULL);
571
572 if (bookmarks->pending_inserts
573 || g_hash_table_size (bookmarks->pending_updates)
574 || g_hash_table_size (bookmarks->pending_deletes))
575 return;
576
577 g_idle_add (midori_bookmarks_db_idle_func, bookmarks);
578}
579
580/**
581 * midori_bookmarks_db_insert_item_db:
582 * @db: the #sqlite3
583 * @item: #KatzeItem the item to insert
584 *
585 * Internal function that does the actual SQL INSERT of the @item in @db.
586 *
587 * Since: 0.5.2
588 **/
589static gint64
590midori_bookmarks_db_insert_item_db (sqlite3* db,
591 KatzeItem* item,
592 gint64 parentid)
593{
594 gchar* sqlcmd;
595 char* errmsg = NULL;
596 KatzeItem* old_parent;
597 gchar* new_parentid;
598 gchar* id = NULL;
599 const gchar* uri = NULL;
600 const gchar* desc = NULL;
601 gint64 seq = 0;
602
603 /* Bookmarks must have a name, import may produce invalid items */
604 g_return_val_if_fail (katze_item_get_name (item), seq);
605
606 if (!db)
607 return seq;
608
609 if (katze_item_get_meta_integer (item, "id") > 0)
610 id = g_strdup_printf ("%" G_GINT64_FORMAT, katze_item_get_meta_integer(item, "id"));
611 else
612 id = g_strdup_printf ("NULL");
613
614 if (KATZE_ITEM_IS_BOOKMARK (item))
615 uri = katze_item_get_uri (item);
616
617 if (katze_item_get_text (item))
618 desc = katze_item_get_text (item);
619
620 /* Use folder, otherwise fallback to parent folder */
621 old_parent = katze_item_get_parent (item);
622 if (parentid > 0)
623 new_parentid = g_strdup_printf ("%" G_GINT64_FORMAT, parentid);
624 else if (old_parent && katze_item_get_meta_integer (old_parent, "id") > 0)
625 new_parentid = g_strdup_printf ("%" G_GINT64_FORMAT, katze_item_get_meta_integer (old_parent, "id"));
626 else
627 new_parentid = g_strdup_printf ("NULL");
628
629 sqlcmd = sqlite3_mprintf (
630 "INSERT INTO bookmarks (id, parentid, title, uri, desc, toolbar, app) "
631 "VALUES (%q, %q, '%q', '%q', '%q', %d, %d)",
632 id,
633 new_parentid,
634 katze_item_get_name (item),
635 katze_str_non_null (uri),
636 katze_str_non_null (desc),
637 katze_item_get_meta_boolean (item, "toolbar"),
638 katze_item_get_meta_boolean (item, "app"));
639
640 if (sqlite3_exec (db, sqlcmd, NULL, NULL, &errmsg) == SQLITE_OK)
641 {
642 /* Get insert id */
643 if (g_str_equal (id, "NULL"))
644 {
645 KatzeArray* seq_array;
646
647 sqlite3_free (sqlcmd);
648 sqlcmd = sqlite3_mprintf (
649 "SELECT seq FROM sqlite_sequence WHERE name = 'bookmarks'");
650
651 seq_array = katze_array_from_sqlite (db, sqlcmd);
652 if (katze_array_get_nth_item (seq_array, 0))
653 {
654 KatzeItem* seq_item = katze_array_get_nth_item (seq_array, 0);
655
656 seq = katze_item_get_meta_integer (seq_item, "seq");
657 katze_item_set_meta_integer (item, "id", seq);
658 }
659 g_object_unref (seq_array);
660 }
661 }
662 else
663 {
664 g_printerr (_("Failed to add bookmark item: %s\n"), errmsg);
665 sqlite3_free (errmsg);
666 }
667
668 sqlite3_free (sqlcmd);
669 g_free (new_parentid);
670 g_free (id);
671
672 return seq;
673}
674
675/**
676 * midori_bookmarks_db_update_item_db:
677 * @db: the #sqlite3
678 * @item: #KatzeItem the item to update
679 *
680 * Internal function that does the actual SQL UPDATE of the @item in @db.
681 *
682 * Since: 0.5.2
683 **/
684static gboolean
685midori_bookmarks_db_update_item_db (sqlite3* db,
686 KatzeItem* item)
687{
688 gchar* sqlcmd;
689 char* errmsg = NULL;
690 gchar* parentid;
691 gboolean updated;
692
693 if (katze_item_get_meta_integer (item, "parentid") > 0)
694 parentid = g_strdup_printf ("%" G_GINT64_FORMAT,
695 katze_item_get_meta_integer (item, "parentid"));
696 else
697 parentid = g_strdup_printf ("NULL");
698
699 sqlcmd = sqlite3_mprintf (
700 "UPDATE bookmarks SET "
701 "parentid=%q, title='%q', uri='%q', desc='%q', toolbar=%d, app=%d "
702 "WHERE id = %" G_GINT64_FORMAT ";",
703 parentid,
704 katze_item_get_name (item),
705 katze_str_non_null (katze_item_get_uri (item)),
706 katze_str_non_null (katze_item_get_meta_string (item, "desc")),
707 katze_item_get_meta_boolean (item, "toolbar"),
708 katze_item_get_meta_boolean (item, "app"),
55 katze_item_get_meta_integer (item, "id"));709 katze_item_get_meta_integer (item, "id"));
56710
57 if (sqlite3_exec (db, sqlcmd, NULL, NULL, &errmsg) != SQLITE_OK)711 updated = TRUE;
58 {712 if (sqlite3_exec (db, sqlcmd, NULL, NULL, &errmsg) != SQLITE_OK)
59 g_printerr (_("Failed to remove history item: %s\n"), errmsg);713 {
60 sqlite3_free (errmsg);714 updated = FALSE;
61 }715 g_printerr (_("Failed to update bookmark : %s\n"), errmsg);
62716 sqlite3_free (errmsg);
63 sqlite3_free (sqlcmd);717 }
718
719 sqlite3_free (sqlcmd);
720 g_free (parentid);
721
722 return updated;
723}
724
725/**
726 * midori_bookmarks_db_remove_item_db:
727 * @db: the #sqlite3
728 * @item: #KatzeItem the item to delete
729 *
730 * Internal function that does the actual SQL DELETE of the @item in @db.
731 *
732 * Since: 0.5.2
733 **/
734static gboolean
735midori_bookmarks_db_remove_item_db (sqlite3* db,
736 KatzeItem* item)
737{
738 char* errmsg = NULL;
739 gchar* sqlcmd;
740 gboolean removed = TRUE;
741
742 sqlcmd = sqlite3_mprintf (
743 "DELETE FROM bookmarks WHERE id = %" G_GINT64_FORMAT ";",
744 katze_item_get_meta_integer (item, "id"));
745
746 if (sqlite3_exec (db, sqlcmd, NULL, NULL, &errmsg) != SQLITE_OK)
747 {
748 g_printerr (_("Failed to remove bookmark item: %s\n"), errmsg);
749 sqlite3_free (errmsg);
750 removed = FALSE;
751 }
752
753 sqlite3_free (sqlcmd);
754 return removed;
755}
756
757/**
758 * midori_bookmarks_db_add_item:
759 * @bookmarks: the main bookmark array
760 * @item: #KatzeItem the item to update
761 *
762 * Adds the @item in the bookmark data base.
763 *
764 * Since: 0.5.2
765 **/
766void
767midori_bookmarks_db_add_item (MidoriBookmarksDb* bookmarks, KatzeItem* item)
768{
769 g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (bookmarks));
770 g_return_if_fail (KATZE_IS_ITEM (item));
771 g_return_if_fail (NULL == katze_item_get_meta_string (item, "id"));
772
773 gpointer found = g_list_find (bookmarks->pending_inserts, item);
774
775 if (found)
776 return;
777
778 midori_bookmarks_db_idle_start (bookmarks);
779
780 g_object_ref (item);
781 bookmarks->pending_inserts = g_list_append (bookmarks->pending_inserts, item);
782}
783
784/**
785 * midori_bookmarks_db_update_item:
786 * @bookmarks: the main bookmark array
787 * @item: #KatzeItem the item to update
788 *
789 * Updates the @item in the bookmark data base.
790 *
791 * Since: 0.5.2
792 **/
793void
794midori_bookmarks_db_update_item (MidoriBookmarksDb* bookmarks, KatzeItem* item)
795{
796 g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (bookmarks));
797 g_return_if_fail (KATZE_IS_ITEM (item));
798 g_return_if_fail (katze_item_get_meta_string (item, "id"));
799 g_return_if_fail (0 != katze_item_get_meta_integer (item, "id"));
800
801 gpointer found = g_hash_table_lookup (bookmarks->pending_updates, item);
802
803 if (found)
804 return;
805
806 midori_bookmarks_db_idle_start (bookmarks);
807
808 g_object_ref (item);
809 g_hash_table_insert (bookmarks->pending_updates, item, item);
810}
811
812/**
813 * midori_bookmarks_db_remove_item:
814 * @bookmarks: the main bookmark array
815 * @item: #KatzeItem the item to remove
816 *
817 * Removes the @item from the bookmark data base.
818 *
819 * Since: 0.5.2
820 **/
821void
822midori_bookmarks_db_remove_item (MidoriBookmarksDb* bookmarks, KatzeItem* item)
823{
824 g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (bookmarks));
825 g_return_if_fail (KATZE_IS_ITEM (item));
826 g_return_if_fail (katze_item_get_meta_string (item, "id"));
827 g_return_if_fail (0 != katze_item_get_meta_integer (item, "id"));
828
829 gpointer found = g_hash_table_lookup (bookmarks->pending_deletes, item);
830
831 if (found)
832 return;
833
834 midori_bookmarks_db_idle_start (bookmarks);
835
836 midori_bookmarks_db_remove_item_recursive (item, bookmarks);
837
838 g_object_ref (item);
839 g_hash_table_insert (bookmarks->pending_deletes, item, item);
64}840}
65841
66#define _APPEND_TO_SQL_ERRORMSG(custom_errmsg) \842#define _APPEND_TO_SQL_ERRORMSG(custom_errmsg) \
@@ -74,8 +850,8 @@
74 g_string_append (errmsg_str, custom_errmsg); \850 g_string_append (errmsg_str, custom_errmsg); \
75 } while (0)851 } while (0)
76852
77gboolean853static gboolean
78midori_bookmarks_import_from_old_db (sqlite3* db,854midori_bookmarks_db_import_from_old_db (sqlite3* db,
79 const gchar* oldfile,855 const gchar* oldfile,
80 gchar** errmsg)856 gchar** errmsg)
81{857{
@@ -130,8 +906,24 @@
130}906}
131#undef _APPEND_TO_SQL_ERRORMSG907#undef _APPEND_TO_SQL_ERRORMSG
132908
133KatzeArray*909static void
134midori_bookmarks_new (char** errmsg)910midori_bookmarks_db_dbtracer (void* dummy,
911 const char* query)
912{
913 g_printerr ("%s\n", query);
914}
915
916/**
917 * midori_bookmarks_db_new:
918 *
919 * Initializes the bookmark data base.
920 *
921 * Returns: the main bookmarks array
922 *
923 * Since: 0.5.2
924 **/
925MidoriBookmarksDb*
926midori_bookmarks_db_new (char** errmsg)
135{927{
136 sqlite3* db;928 sqlite3* db;
137 gchar* oldfile;929 gchar* oldfile;
@@ -141,6 +933,7 @@
141 gchar* sql_errmsg = NULL;933 gchar* sql_errmsg = NULL;
142 gchar* import_errmsg = NULL;934 gchar* import_errmsg = NULL;
143 KatzeArray* array;935 KatzeArray* array;
936 MidoriBookmarksDb* bookmarks;
144937
145 g_return_val_if_fail (errmsg != NULL, NULL);938 g_return_val_if_fail (errmsg != NULL, NULL);
146939
@@ -158,7 +951,7 @@
158 }951 }
159952
160 if (midori_debug ("bookmarks"))953 if (midori_debug ("bookmarks"))
161 sqlite3_trace (db, midori_bookmarks_dbtracer, NULL);954 sqlite3_trace (db, midori_bookmarks_db_dbtracer, NULL);
162955
163 create_stmt = /* Table structure */956 create_stmt = /* Table structure */
164 "CREATE TABLE IF NOT EXISTS bookmarks "957 "CREATE TABLE IF NOT EXISTS bookmarks "
@@ -269,7 +1062,7 @@
2691062
270 if (oldfile_exists)1063 if (oldfile_exists)
271 /* import from old db */1064 /* import from old db */
272 if (!midori_bookmarks_import_from_old_db (db, oldfile, &import_errmsg))1065 if (!midori_bookmarks_db_import_from_old_db (db, oldfile, &import_errmsg))
273 {1066 {
274 *errmsg = g_strdup_printf (_("Couldn't import from old database: %s\n"),1067 *errmsg = g_strdup_printf (_("Couldn't import from old database: %s\n"),
275 import_errmsg ? import_errmsg : "(err = NULL)");1068 import_errmsg ? import_errmsg : "(err = NULL)");
@@ -279,13 +1072,11 @@
279 init_success:1072 init_success:
280 g_free (newfile);1073 g_free (newfile);
281 g_free (oldfile);1074 g_free (oldfile);
282 array = katze_array_new (KATZE_TYPE_ARRAY);1075 bookmarks = MIDORI_BOOKMARKS_DB (g_object_new (TYPE_MIDORI_BOOKMARKS_DB, NULL));
283 g_signal_connect (array, "add-item",1076 bookmarks->db = db;
284 G_CALLBACK (midori_bookmarks_add_item_cb), db);1077
285 g_signal_connect (array, "remove-item",1078 g_object_set_data (G_OBJECT (bookmarks), "db", db);
286 G_CALLBACK (midori_bookmarks_remove_item_cb), db);1079 return bookmarks;
287 g_object_set_data (G_OBJECT (array), "db", db);
288 return array;
2891080
290 init_failed:1081 init_failed:
291 g_free (newfile);1082 g_free (newfile);
@@ -297,31 +1088,384 @@
297 return NULL;1088 return NULL;
298}1089}
2991090
1091/**
1092 * midori_bookmarks_db_on_quit:
1093 * @bookmarks: the main bookmark array
1094 *
1095 * Delete the main bookmark array.
1096 *
1097 * Since: 0.5.2
1098 **/
300void1099void
301midori_bookmarks_import (const gchar* filename,1100midori_bookmarks_db_on_quit (MidoriBookmarksDb* bookmarks)
302 sqlite3* db)
303{1101{
304 KatzeArray* bookmarks;1102 g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (bookmarks));
305 GError* error = NULL;1103
3061104 g_object_unref (bookmarks);
307 bookmarks = katze_array_new (KATZE_TYPE_ARRAY);
308
309 if (!midori_array_from_file (bookmarks, filename, "xbel", &error))
310 {
311 g_warning (_("The bookmarks couldn't be saved. %s"), error->message);
312 g_error_free (error);
313 return;
314 }
315 midori_bookmarks_import_array_db (db, bookmarks, 0);
316}1105}
3171106
1107/**
1108 * midori_bookmarks_db_import_array:
1109 * @array: the main bookmark array
1110 * @array: #KatzeArray containing the items to import
1111 * @parentid: the id of folder
1112 *
1113 * Imports the items of @array as childs of the folder
1114 * identfied by @parentid.
1115 *
1116 * Since: 0.5.2
1117 **/
318void1118void
319midori_bookmarks_on_quit (KatzeArray* array)1119midori_bookmarks_db_import_array (MidoriBookmarksDb* bookmarks,
1120 KatzeArray* array,
1121 gint64 parentid)
320{1122{
1123 GList* list;
1124 KatzeItem* item;
1125
1126 g_return_if_fail (IS_MIDORI_BOOKMARKS_DB (bookmarks));
321 g_return_if_fail (KATZE_IS_ARRAY (array));1127 g_return_if_fail (KATZE_IS_ARRAY (array));
3221128
323 sqlite3* db = g_object_get_data (G_OBJECT (array), "db");1129 KATZE_ARRAY_FOREACH_ITEM_L (item, array, list)
324 g_return_if_fail (db != NULL);1130 {
325 sqlite3_close (db);1131 katze_item_set_meta_integer (item, "parentid", parentid);
326}1132 midori_bookmarks_db_add_item (bookmarks, item);
3271133 }
1134
1135 g_list_free (list);
1136}
1137
1138/**
1139 * midori_bookmarks_db_force_idle:
1140 * @array: the main bookmark array
1141 *
1142 * Internal function that checks if idle processing is pending.
1143 * If it is the case, removes it from idle time processing and
1144 * executes it immediately.
1145 **/
1146static void
1147midori_bookmarks_db_force_idle (MidoriBookmarksDb* bookmarks)
1148{
1149 if (g_idle_remove_by_data (bookmarks))
1150 midori_bookmarks_db_idle_func (bookmarks);
1151}
1152
1153/**
1154 * midori_bookmarks_db_array_from_statement:
1155 * @stmt: the sqlite returned statement
1156 * @bookmarks: the database controller
1157 *
1158 * Internal function that populate a #KatzeArray by processing the @stmt
1159 * rows identifying:
1160 * a- if the item is already in memory
1161 * in this case the item data is updated with retreived database content
1162 * and the already existing item is populated in the returned #KatzeArray
1163 * b- if the data is a folder
1164 * a new #KatzeArray item is populated in the returned #KatzeArray and
1165 * memorized for furure use.
1166 * c- if the data is a bookmark
1167 * a new #KatzeItem item is populated in the returned #KatzeArray and
1168 * memorized for furure use.
1169 *
1170 * Return value: the populated #KatzeArray
1171 **/
1172static KatzeArray*
1173midori_bookmarks_db_array_from_statement (sqlite3_stmt* stmt,
1174 MidoriBookmarksDb* bookmarks)
1175{
1176 KatzeArray *array;
1177 gint result;
1178 gint cols;
1179
1180 array = katze_array_new (KATZE_TYPE_ITEM);
1181 cols = sqlite3_column_count (stmt);
1182
1183 while ((result = sqlite3_step (stmt)) == SQLITE_ROW)
1184 {
1185 gint i;
1186 KatzeItem* item;
1187 KatzeItem* found;
1188
1189 item = katze_item_new ();
1190 for (i = 0; i < cols; i++)
1191 katze_item_set_value_from_column (stmt, i, item);
1192
1193 if (NULL != (found = g_hash_table_lookup (bookmarks->all_items, item)))
1194 {
1195 for (i = 0; i < cols; i++)
1196 katze_item_set_value_from_column (stmt, i, found);
1197
1198 g_object_unref (item);
1199
1200 item = found;
1201 }
1202 else if (KATZE_ITEM_IS_FOLDER (item))
1203 {
1204 item = KATZE_ITEM (katze_array_new (KATZE_TYPE_ITEM));
1205
1206 for (i = 0; i < cols; i++)
1207 katze_item_set_value_from_column (stmt, i, item);
1208
1209 g_object_ref (item);
1210 g_hash_table_insert (bookmarks->all_items, item, item);
1211 }
1212 else
1213 {
1214 g_object_ref (item);
1215 g_hash_table_insert (bookmarks->all_items, item, item);
1216 }
1217
1218 katze_array_add_item (array, item);
1219 }
1220
1221 sqlite3_clear_bindings (stmt);
1222 sqlite3_reset (stmt);
1223 return array;
1224}
1225
1226/**
1227 * midori_bookmarks_db_array_from_sqlite:
1228 * @array: the main bookmark array
1229 * @sqlcmd: the sqlcmd to execute
1230 *
1231 * Internal function that first forces pending idle processing to update the
1232 * database then process the requested @sqlcmd.
1233 *
1234 * Return value: a #KatzeArray on success, %NULL otherwise
1235 **/
1236static KatzeArray*
1237midori_bookmarks_db_array_from_sqlite (MidoriBookmarksDb* bookmarks,
1238 const gchar* sqlcmd)
1239{
1240 sqlite3_stmt* stmt;
1241 gint result;
1242
1243 g_return_val_if_fail (bookmarks->db != NULL, NULL);
1244
1245 midori_bookmarks_db_force_idle (bookmarks);
1246
1247 result = sqlite3_prepare_v2 (bookmarks->db, sqlcmd, -1, &stmt, NULL);
1248 if (result != SQLITE_OK)
1249 return NULL;
1250
1251 return midori_bookmarks_db_array_from_statement (stmt, bookmarks);
1252}
1253
1254/**
1255 * midori_bookmarks_db_query_recursive:
1256 * @array: the main bookmark array
1257 * @fields: comma separated list of fields
1258 * @condition: condition, like "folder = '%q'"
1259 * @value: a value to be inserted if @condition contains %q
1260 * @recursive: if %TRUE include children
1261 *
1262 * Stores the result in a #KatzeArray.
1263 *
1264 * Return value: a #KatzeArray on success, %NULL otherwise
1265 *
1266 * Since: 0.5.2
1267 **/
1268KatzeArray*
1269midori_bookmarks_db_query_recursive (MidoriBookmarksDb* bookmarks,
1270 const gchar* fields,
1271 const gchar* condition,
1272 const gchar* value,
1273 gboolean recursive)
1274{
1275 gchar* sqlcmd;
1276 char* sqlcmd_value;
1277 KatzeArray* array;
1278 KatzeItem* item;
1279 GList* list;
1280
1281 g_return_val_if_fail (IS_MIDORI_BOOKMARKS_DB (bookmarks), NULL);
1282 g_return_val_if_fail (fields, NULL);
1283 g_return_val_if_fail (condition, NULL);
1284
1285 sqlcmd = g_strdup_printf ("SELECT %s FROM bookmarks WHERE %s "
1286 "ORDER BY (uri='') ASC, title DESC", fields, condition);
1287 if (strstr (condition, "%q"))
1288 {
1289 sqlcmd_value = sqlite3_mprintf (sqlcmd, value ? value : "");
1290 array = midori_bookmarks_db_array_from_sqlite (bookmarks, sqlcmd_value);
1291 sqlite3_free (sqlcmd_value);
1292 }
1293 else
1294 array = midori_bookmarks_db_array_from_sqlite (bookmarks, sqlcmd);
1295 g_free (sqlcmd);
1296
1297 if (!recursive)
1298 return array;
1299
1300 KATZE_ARRAY_FOREACH_ITEM_L (item, array, list)
1301 {
1302 if (KATZE_ITEM_IS_FOLDER (item))
1303 {
1304 gchar* parentid = g_strdup_printf ("%" G_GINT64_FORMAT,
1305 katze_item_get_meta_integer (item, "id"));
1306 KatzeArray* subarray = midori_bookmarks_db_query_recursive (bookmarks,
1307 fields, "parentid=%q", parentid, TRUE);
1308 KatzeItem* subitem;
1309 GList* sublist;
1310
1311 KATZE_ARRAY_FOREACH_ITEM_L (subitem, subarray, sublist)
1312 {
1313 katze_array_add_item (KATZE_ARRAY (item), subitem);
1314 }
1315
1316 g_object_unref (subarray);
1317 g_free (parentid);
1318 }
1319 }
1320 g_list_free (list);
1321 return array;
1322}
1323
1324static gint64
1325midori_bookmarks_db_count_from_sqlite (sqlite3* db,
1326 const gchar* sqlcmd)
1327{
1328 gint64 count = -1;
1329 sqlite3_stmt* stmt;
1330 gint result;
1331
1332 result = sqlite3_prepare_v2 (db, sqlcmd, -1, &stmt, NULL);
1333 if (result != SQLITE_OK)
1334 return -1;
1335
1336 g_assert (sqlite3_column_count (stmt) == 1);
1337
1338 if ((result = sqlite3_step (stmt)) == SQLITE_ROW)
1339 count = sqlite3_column_int64(stmt, 0);
1340
1341 sqlite3_clear_bindings (stmt);
1342 sqlite3_reset (stmt);
1343
1344 return count;
1345}
1346
1347static gint64
1348midori_bookmarks_db_count_recursive_by_id (MidoriBookmarksDb* bookmarks,
1349 const gchar* condition,
1350 const gchar* value,
1351 gint64 id,
1352 gboolean recursive)
1353{
1354 gint64 count = -1;
1355 gchar* sqlcmd;
1356 char* sqlcmd_value;
1357 sqlite3_stmt* stmt;
1358 gint result;
1359 GList* ids;
1360 GList* iter_ids;
1361
1362 g_return_val_if_fail (condition, -1);
1363 g_return_val_if_fail (MIDORI_BOOKMARKS_DB (bookmarks), -1);
1364 g_return_val_if_fail (bookmarks->db != NULL, -1);
1365
1366 g_assert(!strstr("parentid", condition));
1367
1368 if (id > 0)
1369 sqlcmd = g_strdup_printf ("SELECT COUNT(*) FROM bookmarks "
1370 "WHERE parentid = %" G_GINT64_FORMAT " AND %s",
1371 id,
1372 condition);
1373 else
1374 sqlcmd = g_strdup_printf ("SELECT COUNT(*) FROM bookmarks "
1375 "WHERE parentid IS NULL AND %s ",
1376 condition);
1377
1378 if (strstr (condition, "%q"))
1379 {
1380 sqlcmd_value = sqlite3_mprintf (sqlcmd, value ? value : "");
1381 count = midori_bookmarks_db_count_from_sqlite (bookmarks->db, sqlcmd_value);
1382 sqlite3_free (sqlcmd_value);
1383 }
1384 else
1385 count = midori_bookmarks_db_count_from_sqlite (bookmarks->db, sqlcmd);
1386
1387 g_free (sqlcmd);
1388
1389 if (!recursive || (count < 0))
1390 return count;
1391
1392 ids = NULL;
1393
1394 if (id > 0)
1395 sqlcmd_value = sqlite3_mprintf (
1396 "SELECT id FROM bookmarks "
1397 "WHERE parentid = %" G_GINT64_FORMAT " AND uri = ''", id);
1398 else
1399 sqlcmd_value = sqlite3_mprintf (
1400 "SELECT id FROM bookmarks "
1401 "WHERE parentid IS NULL AND uri = ''");
1402
1403 if (sqlite3_prepare_v2 (bookmarks->db, sqlcmd_value, -1, &stmt, NULL) == SQLITE_OK)
1404 {
1405 g_assert (sqlite3_column_count (stmt) == 1);
1406
1407 if ((result = sqlite3_step (stmt)) == SQLITE_ROW)
1408 {
1409 gint64* pid = g_new (gint64, 1);
1410
1411 *pid = sqlite3_column_int64(stmt, 0);
1412 ids = g_list_append (ids, pid);
1413 }
1414
1415 sqlite3_clear_bindings (stmt);
1416 sqlite3_reset (stmt);
1417 }
1418
1419 sqlite3_free (sqlcmd_value);
1420
1421 iter_ids = ids;
1422 while (iter_ids)
1423 {
1424 gint64 sub_count = midori_bookmarks_db_count_recursive_by_id (bookmarks,
1425 condition,
1426 value,
1427 *(gint64*)(iter_ids->data),
1428 recursive);
1429
1430 if (sub_count < 0)
1431 {
1432 g_list_free_full (ids, g_free);
1433 return -1;
1434 }
1435
1436 count += sub_count;
1437 iter_ids = g_list_next (iter_ids);
1438 }
1439
1440 g_list_free_full (ids, g_free);
1441 return count;
1442}
1443
1444/**
1445 * midori_bookmarks_db_count_recursive:
1446 * @bookmarks: the main bookmark array
1447 * @condition: condition, like "folder = '%q'"
1448 * @value: a value to be inserted if @condition contains %q
1449 * @recursive: if %TRUE include children
1450 *
1451 * Return value: the number of elements on success, -1 otherwise
1452 *
1453 * Since: 0.5.2
1454 **/
1455gint64
1456midori_bookmarks_db_count_recursive (MidoriBookmarksDb* bookmarks,
1457 const gchar* condition,
1458 const gchar* value,
1459 KatzeItem* folder,
1460 gboolean recursive)
1461{
1462 gint64 id = -1;
1463
1464 g_return_val_if_fail (!folder || KATZE_ITEM_IS_FOLDER (folder), -1);
1465
1466 id = folder ? katze_item_get_meta_integer (folder, "id") : 0;
1467
1468 return midori_bookmarks_db_count_recursive_by_id (bookmarks, condition,
1469 value, id,
1470 recursive);
1471}
3281472
=== renamed file 'midori/midori-bookmarks.h' => 'midori/midori-bookmarks-db.h'
--- midori/midori-bookmarks.h 2012-11-25 15:37:41 +0000
+++ midori/midori-bookmarks-db.h 2013-06-11 20:53:24 +0000
@@ -10,31 +10,70 @@
10 See the file COPYING for the full license text.10 See the file COPYING for the full license text.
11*/11*/
1212
13#ifndef __MIDORI_BOOKMARKS_H__13#ifndef __MIDORI_BOOKMARKS_DB_H__
14#define __MIDORI_BOOKMARKS_H__ 114#define __MIDORI_BOOKMARKS_DB_H__ 1
1515
16#include <sqlite3.h>16#include <sqlite3.h>
17#include <katze/katze.h>17#include <katze/katze.h>
1818
19void19G_BEGIN_DECLS
20midori_bookmarks_add_item_cb (KatzeArray* array,20
21 KatzeItem* item,21#define TYPE_MIDORI_BOOKMARKS_DB \
22 sqlite3* db);22 (midori_bookmarks_db_get_type ())
2323#define MIDORI_BOOKMARKS_DB(obj) \
24void24 (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MIDORI_BOOKMARKS_DB, MidoriBookmarksDb))
25midori_bookmarks_remove_item_cb (KatzeArray* array,25#define MIDORI_BOOKMARKS_DB_CLASS(klass) \
26 KatzeItem* item,26 (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_MIDORI_BOOKMARKS_DB, MidoriBookmarksDbClass))
27 sqlite3* db);27#define IS_MIDORI_BOOKMARKS_DB(obj) \
28 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_MIDORI_BOOKMARKS_DB))
29#define IS_MIDORI_BOOKMARKS_DB_CLASS(klass) \
30 (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_MIDORI_BOOKMARKS_DB))
31#define MIDORI_BOOKMARKS_DB_GET_CLASS(obj) \
32 (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_MIDORI_BOOKMARKS_DB, MidoriBookmarksDbClass))
33
34typedef struct _MidoriBookmarksDb MidoriBookmarksDb;
35typedef struct _MidoriBookmarksDbClass MidoriBookmarksDbClass;
36
37GType
38midori_bookmarks_db_get_type (void) G_GNUC_CONST;
39
40MidoriBookmarksDb*
41midori_bookmarks_db_new (char** errmsg);
42
43void
44midori_bookmarks_db_on_quit (MidoriBookmarksDb* array);
45
46void
47midori_bookmarks_db_add_item (MidoriBookmarksDb* bookmarks, KatzeItem* item);
48
49void
50midori_bookmarks_db_update_item (MidoriBookmarksDb* bookmarks, KatzeItem* item);
51
52void
53midori_bookmarks_db_remove_item (MidoriBookmarksDb* bookmarks, KatzeItem* item);
54
55void
56midori_bookmarks_db_import_array (MidoriBookmarksDb* bookmarks,
57 KatzeArray* array,
58 gint64 parentid);
2859
29KatzeArray*60KatzeArray*
30midori_bookmarks_new (char** errmsg);61midori_bookmarks_db_query_recursive (MidoriBookmarksDb* bookmarks,
3162 const gchar* fields,
32void63 const gchar* condition,
33midori_bookmarks_on_quit (KatzeArray* array);64 const gchar* value,
3465 gboolean recursive);
35void66
36midori_bookmarks_import (const gchar* filename,67gint64
37 sqlite3* db);68midori_bookmarks_db_count_recursive (MidoriBookmarksDb* bookmarks,
3869 const gchar* condition,
39#endif /* !__MIDORI_BOOKMARKS_H__ */70 const gchar* value,
71 KatzeItem* folder,
72 gboolean recursive);
73
74void
75midori_bookmarks_db_on_quit (MidoriBookmarksDb* array);
76
77
78#endif /* !__MIDORI_BOOKMARKS_DB_H__ */
4079
4180
=== modified file 'midori/midori-browser.c'
--- midori/midori-browser.c 2013-06-02 13:30:16 +0000
+++ midori/midori-browser.c 2013-06-11 20:53:24 +0000
@@ -26,6 +26,7 @@
26#include "midori-privatedata.h"26#include "midori-privatedata.h"
27#include "midori-core.h"27#include "midori-core.h"
28#include "midori-privatedata.h"28#include "midori-privatedata.h"
29#include "midori-bookmarks-db.h"
2930
30#include "marshal.h"31#include "marshal.h"
3132
@@ -85,7 +86,7 @@
8586
86 MidoriWebSettings* settings;87 MidoriWebSettings* settings;
87 KatzeArray* proxy_array;88 KatzeArray* proxy_array;
88 KatzeArray* bookmarks;89 MidoriBookmarksDb* bookmarks;
89 KatzeArray* trash;90 KatzeArray* trash;
90 KatzeArray* search_engines;91 KatzeArray* search_engines;
91 KatzeArray* history;92 KatzeArray* history;
@@ -96,6 +97,8 @@
96 gboolean show_statusbar;97 gboolean show_statusbar;
97 guint maximum_history_age;98 guint maximum_history_age;
98 guint last_web_search;99 guint last_web_search;
100
101 gboolean bookmarkbar_populate;
99};102};
100103
101G_DEFINE_TYPE (MidoriBrowser, midori_browser, GTK_TYPE_WINDOW)104G_DEFINE_TYPE (MidoriBrowser, midori_browser, GTK_TYPE_WINDOW)
@@ -162,20 +165,13 @@
162 GParamSpec* pspec);165 GParamSpec* pspec);
163166
164void167void
165midori_bookmarks_import_array_db (sqlite3* db,
166 KatzeArray* array,
167 gint64 parentid);
168
169gboolean
170midori_bookmarks_update_item_db (sqlite3* db,
171 KatzeItem* item);
172
173void
174midori_browser_open_bookmark (MidoriBrowser* browser,168midori_browser_open_bookmark (MidoriBrowser* browser,
175 KatzeItem* item);169 KatzeItem* item);
176170
177static void171static void
178midori_bookmarkbar_populate (MidoriBrowser* browser);172midori_bookmarkbar_populate (MidoriBrowser* browser);
173static void
174midori_bookmarkbar_populate_idle (MidoriBrowser* browser);
179175
180static void176static void
181midori_bookmarkbar_clear (GtkWidget* toolbar);177midori_bookmarkbar_clear (GtkWidget* toolbar);
@@ -203,8 +199,8 @@
203 GtkToolbarStyle style);199 GtkToolbarStyle style);
204200
205static void201static void
206midori_browser_set_bookmarks (MidoriBrowser* browser,202midori_browser_set_bookmarks (MidoriBrowser* browser,
207 KatzeArray* bookmarks);203 MidoriBookmarksDb* bookmarks);
208204
209static void205static void
210midori_browser_add_speed_dial (MidoriBrowser* browser);206midori_browser_add_speed_dial (MidoriBrowser* browser);
@@ -484,6 +480,9 @@
484 inter = ZEITGEIST_ZG_DELETE_EVENT;480 inter = ZEITGEIST_ZG_DELETE_EVENT;
485 else481 else
486 g_assert_not_reached ();482 g_assert_not_reached ();
483 g_assert (KATZE_IS_ITEM (item));
484 if (KATZE_ITEM_IS_FOLDER (item))
485 return;
487 zeitgeist_log_insert_events_no_reply (zeitgeist_log_get_default (),486 zeitgeist_log_insert_events_no_reply (zeitgeist_log_get_default (),
488 zeitgeist_event_new_full (inter, ZEITGEIST_ZG_USER_ACTIVITY,487 zeitgeist_event_new_full (inter, ZEITGEIST_ZG_USER_ACTIVITY,
489 "application://midori.desktop",488 "application://midori.desktop",
@@ -817,7 +816,7 @@
817}816}
818817
819static GtkWidget*818static GtkWidget*
820midori_bookmark_folder_button_new (KatzeArray* array,819midori_bookmark_folder_button_new (MidoriBookmarksDb* array,
821 gboolean new_bookmark,820 gboolean new_bookmark,
822 gint64 selected,821 gint64 selected,
823 gint64 parentid)822 gint64 parentid)
@@ -1059,18 +1058,13 @@
1059 katze_item_set_meta_integer (bookmark, "parentid", selected);1058 katze_item_set_meta_integer (bookmark, "parentid", selected);
10601059
1061 if (new_bookmark)1060 if (new_bookmark)
1062 katze_array_add_item (browser->bookmarks, bookmark);1061 midori_bookmarks_db_add_item (browser->bookmarks, bookmark);
1063 else1062 else
1064 midori_bookmarks_update_item_db (db, bookmark);1063 midori_bookmarks_db_update_item (browser->bookmarks, bookmark);
1065 midori_browser_update_history (bookmark, "bookmark", new_bookmark ? "create" : "modify");
10661064
1067 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_toolbar)))
1068 if (!gtk_widget_get_visible (browser->bookmarkbar))
1069 _action_set_active (browser, "Bookmarkbar", TRUE);
1070 return_status = TRUE;1065 return_status = TRUE;
1071 }1066 }
1072 if (gtk_widget_get_visible (browser->bookmarkbar))1067
1073 midori_bookmarkbar_populate (browser);
1074 gtk_widget_destroy (dialog);1068 gtk_widget_destroy (dialog);
1075 return return_status;1069 return return_status;
1076}1070}
@@ -2321,7 +2315,7 @@
2321 "bookmarks",2315 "bookmarks",
2322 "Bookmarks",2316 "Bookmarks",
2323 "The bookmarks folder, containing all bookmarks",2317 "The bookmarks folder, containing all bookmarks",
2324 KATZE_TYPE_ARRAY,2318 TYPE_MIDORI_BOOKMARKS_DB,
2325 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));2319 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
23262320
2327 /**2321 /**
@@ -3096,8 +3090,8 @@
3096 else3090 else
3097 condition = "parentid = %q";3091 condition = "parentid = %q";
30983092
3099 bookmarks = midori_array_query (browser->bookmarks,3093 bookmarks = midori_bookmarks_db_query_recursive (browser->bookmarks,
3100 "id, title, parentid, uri, app, pos_panel, pos_bar", condition, id);3094 "id, title, parentid, uri, app, pos_panel, pos_bar", condition, id, FALSE);
3101 if (!bookmarks)3095 if (!bookmarks)
3102 return FALSE;3096 return FALSE;
31033097
@@ -4227,7 +4221,7 @@
4227 KatzeItem* item;4221 KatzeItem* item;
42284222
4229 item = (KatzeItem*)g_object_get_data (G_OBJECT (menuitem), "KatzeItem");4223 item = (KatzeItem*)g_object_get_data (G_OBJECT (menuitem), "KatzeItem");
4230 katze_array_remove_item (browser->bookmarks, item);4224 midori_bookmarks_db_remove_item (browser->bookmarks, item);
4231}4225}
42324226
4233static void4227static void
@@ -4242,7 +4236,7 @@
4242 menu = gtk_menu_new ();4236 menu = gtk_menu_new ();
4243 if (KATZE_ITEM_IS_FOLDER (item))4237 if (KATZE_ITEM_IS_FOLDER (item))
4244 {4238 {
4245 gint child_bookmarks_count = midori_array_count_recursive (browser->bookmarks,4239 gint child_bookmarks_count = midori_bookmarks_db_count_recursive (browser->bookmarks,
4246 "uri <> ''", NULL, item, FALSE);4240 "uri <> ''", NULL, item, FALSE);
42474241
4248 midori_browser_bookmark_popup_item (menu,4242 midori_browser_bookmark_popup_item (menu,
@@ -4497,8 +4491,7 @@
4497 if (error)4491 if (error)
4498 g_error_free (error);4492 g_error_free (error);
4499 }4493 }
4500 midori_bookmarks_import_array_db (db, bookmarks, selected);4494 midori_bookmarks_db_import_array (browser->bookmarks, bookmarks, selected);
4501 katze_array_update (browser->bookmarks);
4502 g_object_unref (bookmarks);4495 g_object_unref (bookmarks);
4503 g_free (path);4496 g_free (path);
4504 }4497 }
@@ -4552,7 +4545,7 @@
4552 return;4545 return;
45534546
4554 error = NULL;4547 error = NULL;
4555 bookmarks = midori_array_query_recursive (browser->bookmarks,4548 bookmarks = midori_bookmarks_db_query_recursive (browser->bookmarks,
4556 "*", "parentid IS NULL", NULL, TRUE);4549 "*", "parentid IS NULL", NULL, TRUE);
4557 if (!midori_array_to_file (bookmarks, path, format, &error))4550 if (!midori_array_to_file (bookmarks, path, format, &error))
4558 {4551 {
@@ -5979,6 +5972,21 @@
5979 }5972 }
5980}5973}
59815974
5975static gboolean
5976midori_browser_idle (gpointer data)
5977{
5978 MidoriBrowser* browser = MIDORI_BROWSER (data);
5979
5980 if (browser->bookmarkbar_populate)
5981 {
5982 midori_bookmarkbar_populate_idle (browser);
5983
5984 browser->bookmarkbar_populate = FALSE;
5985 }
5986
5987 return FALSE;
5988}
5989
5982static void5990static void
5983midori_browser_init (MidoriBrowser* browser)5991midori_browser_init (MidoriBrowser* browser)
5984{5992{
@@ -6459,6 +6467,8 @@
6459 katze_object_assign (browser->history, NULL);6467 katze_object_assign (browser->history, NULL);
6460 katze_object_assign (browser->dial, NULL);6468 katze_object_assign (browser->dial, NULL);
64616469
6470 g_idle_remove_by_data (browser);
6471
6462 G_OBJECT_CLASS (midori_browser_parent_class)->finalize (object);6472 G_OBJECT_CLASS (midori_browser_parent_class)->finalize (object);
6463}6473}
64646474
@@ -6973,7 +6983,7 @@
6973 KatzeItem* item)6983 KatzeItem* item)
6974{6984{
6975 MidoriBrowser* browser = midori_browser_get_for_widget (toolbar);6985 MidoriBrowser* browser = midori_browser_get_for_widget (toolbar);
6976 GtkAction* action = _action_by_name (browser, "Tools");6986 GtkAction* action = _action_by_name (browser, "Bookmarks");
6977 GtkToolItem* toolitem = katze_array_action_create_tool_item_for (6987 GtkToolItem* toolitem = katze_array_action_create_tool_item_for (
6978 KATZE_ARRAY_ACTION (action), item);6988 KATZE_ARRAY_ACTION (action), item);
6979 g_object_set_data (G_OBJECT (toolitem), "KatzeItem", item);6989 g_object_set_data (G_OBJECT (toolitem), "KatzeItem", item);
@@ -6994,6 +7004,28 @@
6994}7004}
69957005
6996static void7006static void
7007midori_bookmarkbar_add_item_cb (KatzeArray* bookmarks,
7008 KatzeItem* item,
7009 MidoriBrowser* browser)
7010{
7011 if (gtk_widget_get_visible (browser->bookmarkbar))
7012 midori_bookmarkbar_populate (browser);
7013 else if (katze_item_get_meta_boolean (item, "toolbar"))
7014 _action_set_active (browser, "Bookmarkbar", TRUE);
7015 midori_browser_update_history (item, "bookmark", "created");
7016}
7017
7018static void
7019midori_bookmarkbar_update_item_cb (KatzeArray* bookmarks,
7020 KatzeItem* item,
7021 MidoriBrowser* browser)
7022{
7023 if (gtk_widget_get_visible (browser->bookmarkbar))
7024 midori_bookmarkbar_populate (browser);
7025 midori_browser_update_history (item, "bookmark", "modify");
7026}
7027
7028static void
6997midori_bookmarkbar_remove_item_cb (KatzeArray* bookmarks,7029midori_bookmarkbar_remove_item_cb (KatzeArray* bookmarks,
6998 KatzeItem* item,7030 KatzeItem* item,
6999 MidoriBrowser* browser)7031 MidoriBrowser* browser)
@@ -7006,6 +7038,16 @@
7006static void7038static void
7007midori_bookmarkbar_populate (MidoriBrowser* browser)7039midori_bookmarkbar_populate (MidoriBrowser* browser)
7008{7040{
7041 if (browser->bookmarkbar_populate)
7042 return;
7043
7044 g_idle_add (midori_browser_idle, browser);
7045 browser->bookmarkbar_populate = TRUE;
7046}
7047
7048static void
7049midori_bookmarkbar_populate_idle (MidoriBrowser* browser)
7050{
7009 KatzeArray* array;7051 KatzeArray* array;
7010 KatzeItem* item;7052 KatzeItem* item;
70117053
@@ -7015,8 +7057,8 @@
7015 gtk_toolbar_insert (GTK_TOOLBAR (browser->bookmarkbar),7057 gtk_toolbar_insert (GTK_TOOLBAR (browser->bookmarkbar),
7016 gtk_separator_tool_item_new (), -1);7058 gtk_separator_tool_item_new (), -1);
70177059
7018 array = midori_array_query (browser->bookmarks,7060 array = midori_bookmarks_db_query_recursive (browser->bookmarks,
7019 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "toolbar = 1", NULL);7061 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "toolbar = 1", NULL, FALSE);
7020 if (!array)7062 if (!array)
7021 {7063 {
7022 _action_set_sensitive (browser, "BookmarkAdd", FALSE);7064 _action_set_sensitive (browser, "BookmarkAdd", FALSE);
@@ -7026,21 +7068,7 @@
70267068
7027 KATZE_ARRAY_FOREACH_ITEM (item, array)7069 KATZE_ARRAY_FOREACH_ITEM (item, array)
7028 {7070 {
7029 if (KATZE_ITEM_IS_BOOKMARK (item))7071 midori_bookmarkbar_insert_item (browser->bookmarkbar, item);
7030 midori_bookmarkbar_insert_item (browser->bookmarkbar, item);
7031 else
7032 {
7033 gint64 id = katze_item_get_meta_integer (item, "id");
7034 gchar* parentid = g_strdup_printf ("%" G_GINT64_FORMAT, id);
7035 KatzeArray* subfolder = midori_array_query (browser->bookmarks,
7036 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "parentid = %q AND uri != ''",
7037 parentid);
7038
7039 katze_item_set_name (KATZE_ITEM (subfolder), katze_item_get_name (item));
7040 katze_item_set_meta_integer (KATZE_ITEM (subfolder), "id", id);
7041 midori_bookmarkbar_insert_item (browser->bookmarkbar, KATZE_ITEM (subfolder));
7042 g_free (parentid);
7043 }
7044 }7072 }
7045 _action_set_sensitive (browser, "BookmarkAdd", TRUE);7073 _action_set_sensitive (browser, "BookmarkAdd", TRUE);
7046 _action_set_sensitive (browser, "BookmarkFolderAdd", TRUE);7074 _action_set_sensitive (browser, "BookmarkFolderAdd", TRUE);
@@ -7070,13 +7098,20 @@
70707098
7071static void7099static void
7072midori_browser_set_bookmarks (MidoriBrowser* browser,7100midori_browser_set_bookmarks (MidoriBrowser* browser,
7073 KatzeArray* bookmarks)7101 MidoriBookmarksDb* bookmarks)
7074{7102{
7075 MidoriWebSettings* settings;7103 MidoriWebSettings* settings;
70767104
7077 if (browser->bookmarks != NULL)7105 if (browser->bookmarks != NULL)
7106 {
7107 g_signal_handlers_disconnect_by_func (browser->bookmarks,
7108 midori_bookmarkbar_add_item_cb, browser);
7109 g_signal_handlers_disconnect_by_func (browser->bookmarks,
7110 midori_bookmarkbar_update_item_cb, browser);
7078 g_signal_handlers_disconnect_by_func (browser->bookmarks,7111 g_signal_handlers_disconnect_by_func (browser->bookmarks,
7079 midori_bookmarkbar_remove_item_cb, browser);7112 midori_bookmarkbar_remove_item_cb, browser);
7113 }
7114
7080 settings = midori_browser_get_settings (browser);7115 settings = midori_browser_get_settings (browser);
7081 g_signal_handlers_disconnect_by_func (settings,7116 g_signal_handlers_disconnect_by_func (settings,
7082 midori_browser_show_bookmarkbar_notify_value_cb, browser);7117 midori_browser_show_bookmarkbar_notify_value_cb, browser);
@@ -7105,6 +7140,10 @@
7105 g_signal_connect (settings, "notify::show-bookmarkbar",7140 g_signal_connect (settings, "notify::show-bookmarkbar",
7106 G_CALLBACK (midori_browser_show_bookmarkbar_notify_value_cb), browser);7141 G_CALLBACK (midori_browser_show_bookmarkbar_notify_value_cb), browser);
7107 g_object_notify (G_OBJECT (settings), "show-bookmarkbar");7142 g_object_notify (G_OBJECT (settings), "show-bookmarkbar");
7143 g_signal_connect_after (bookmarks, "add-item",
7144 G_CALLBACK (midori_bookmarkbar_add_item_cb), browser);
7145 g_signal_connect_after (bookmarks, "update-item",
7146 G_CALLBACK (midori_bookmarkbar_update_item_cb), browser);
7108 g_signal_connect_after (bookmarks, "remove-item",7147 g_signal_connect_after (bookmarks, "remove-item",
7109 G_CALLBACK (midori_bookmarkbar_remove_item_cb), browser);7148 G_CALLBACK (midori_bookmarkbar_remove_item_cb), browser);
7110}7149}
71117150
=== modified file 'midori/midori-frontend.c'
--- midori/midori-frontend.c 2013-05-23 22:15:27 +0000
+++ midori/midori-frontend.c 2013-06-11 20:53:24 +0000
@@ -10,7 +10,7 @@
10*/10*/
1111
12#include "midori-array.h"12#include "midori-array.h"
13#include "midori-bookmarks.h"13#include "midori-bookmarks-db.h"
14#include "midori-history.h"14#include "midori-history.h"
15#include "midori-preferences.h"15#include "midori-preferences.h"
16#include "midori-privatedata.h"16#include "midori-privatedata.h"
@@ -487,9 +487,9 @@
487 }487 }
488 g_free (uri);488 g_free (uri);
489489
490 KatzeArray* bookmarks;490 MidoriBookmarksDb* bookmarks;
491 gchar* errmsg = NULL;491 gchar* errmsg = NULL;
492 if (!(bookmarks = midori_bookmarks_new (&errmsg)))492 if (!(bookmarks = midori_bookmarks_db_new (&errmsg)))
493 {493 {
494 g_string_append_printf (error_messages,494 g_string_append_printf (error_messages,
495 _("Bookmarks couldn't be loaded: %s\n"), errmsg);495 _("Bookmarks couldn't be loaded: %s\n"), errmsg);
@@ -594,11 +594,11 @@
594midori_normal_app_on_quit (MidoriApp* app)594midori_normal_app_on_quit (MidoriApp* app)
595{595{
596 MidoriWebSettings* settings = katze_object_get_object (app, "settings");596 MidoriWebSettings* settings = katze_object_get_object (app, "settings");
597 KatzeArray* bookmarks = katze_object_get_object (app, "bookmarks");597 MidoriBookmarksDb* bookmarks = katze_object_get_object (app, "bookmarks");
598 KatzeArray* history = katze_object_get_object (app, "history");598 KatzeArray* history = katze_object_get_object (app, "history");
599599
600 g_object_notify (G_OBJECT (settings), "load-on-startup");600 g_object_notify (G_OBJECT (settings), "load-on-startup");
601 midori_bookmarks_on_quit (bookmarks);601 midori_bookmarks_db_on_quit (bookmarks);
602 midori_history_on_quit (history, settings);602 midori_history_on_quit (history, settings);
603 midori_private_data_on_quit (settings);603 midori_private_data_on_quit (settings);
604 /* Removing KatzeHttpCookies makes it save outstanding changes */604 /* Removing KatzeHttpCookies makes it save outstanding changes */
605605
=== modified file 'midori/midori.h'
--- midori/midori.h 2012-12-02 15:32:20 +0000
+++ midori/midori.h 2013-06-11 20:53:24 +0000
@@ -14,7 +14,7 @@
1414
15#include "midori-app.h"15#include "midori-app.h"
16#include "midori-array.h"16#include "midori-array.h"
17#include "midori-bookmarks.h"17#include "midori-bookmarks-db.h"
18#include "midori-browser.h"18#include "midori-browser.h"
19#include "midori-extension.h"19#include "midori-extension.h"
20#include "midori-frontend.h"20#include "midori-frontend.h"
2121
=== modified file 'panels/midori-bookmarks.c'
--- panels/midori-bookmarks.c 2013-06-04 17:28:05 +0000
+++ panels/midori-bookmarks.c 2013-06-11 20:53:24 +0000
@@ -17,6 +17,7 @@
17#include "midori-platform.h"17#include "midori-platform.h"
18#include "midori-view.h"18#include "midori-view.h"
19#include "midori-core.h"19#include "midori-core.h"
20#include "midori-bookmarks-db.h"
2021
21#include <glib/gi18n.h>22#include <glib/gi18n.h>
22#include <string.h>23#include <string.h>
@@ -25,6 +26,111 @@
2526
26#define COMPLETION_DELAY 20027#define COMPLETION_DELAY 200
2728
29G_BEGIN_DECLS
30
31#define MIDORI_BOOKMARKS_TREE_STORE_TYPE \
32 (midori_bookmarks_tree_store_get_type ())
33#define MIDORI_BOOKMARKS_TREE_STORE(obj) \
34 (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_BOOKMARKS_TREE_STORE_TYPE, MidoriBookmarksTreeStore))
35#define MIDORI_BOOKMARKS_TREE_STORE_CLASS(klass) \
36 (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_BOOKMARKS_TREE_STORE_TYPE, MidoriBookmarksTreeStoreClass))
37
38static gboolean
39midori_bookmarks_tree_store_row_drop_possible (GtkTreeDragDest *drag_dest,
40 GtkTreePath *dest_path,
41 GtkSelectionData *selection_data);
42
43typedef struct _MidoriBookmarksTreeStore MidoriBookmarksTreeStore;
44typedef struct _MidoriBookmarksTreeStoreClass MidoriBookmarksTreeStoreClass;
45
46struct _MidoriBookmarksTreeStore
47{
48 GtkTreeStore parent_instance;
49};
50
51struct _MidoriBookmarksTreeStoreClass
52{
53 GtkTreeStoreClass parent_class;
54};
55
56static GtkTreeDragDestIface *
57gtk_tree_store_gtk_tree_drag_dest_iface = NULL;
58
59static void
60midori_bookmarks_tree_store_drag_dest_init (GtkTreeDragDestIface *iface)
61{
62 gtk_tree_store_gtk_tree_drag_dest_iface = g_type_interface_peek_parent (iface);
63
64 iface->row_drop_possible = midori_bookmarks_tree_store_row_drop_possible;
65}
66
67static void
68midori_bookmarks_tree_store_init (MidoriBookmarksTreeStore* item)
69{
70}
71
72static void
73midori_bookmarks_tree_store_class_init (MidoriBookmarksTreeStoreClass *class)
74{
75}
76
77G_DEFINE_TYPE_WITH_CODE (MidoriBookmarksTreeStore,
78 midori_bookmarks_tree_store,
79 GTK_TYPE_TREE_STORE,
80 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST,
81 midori_bookmarks_tree_store_drag_dest_init));
82
83
84GtkTreeStore*
85midori_bookmarks_tree_store_new (gint n_columns, ...)
86{
87 GtkTreeStore* tree_store = GTK_TREE_STORE (g_object_new (MIDORI_BOOKMARKS_TREE_STORE_TYPE, NULL));
88 va_list ap;
89 GType* types;
90 gint n;
91
92 if (!tree_store)
93 return NULL;
94
95 types = g_new (GType, n_columns);
96
97 if (!types)
98 {
99 g_object_unref(tree_store);
100 return NULL;
101 }
102
103 va_start(ap, n_columns);
104 for (n = 0; n < n_columns; n++)
105 {
106 types[n] = va_arg(ap, GType);
107 }
108 va_end(ap);
109
110 gtk_tree_store_set_column_types (tree_store,
111 n_columns,
112 types);
113
114 g_free (types);
115 return tree_store;
116}
117
118
119GtkTreeStore*
120midori_bookmarks_tree_store_newv (gint n_columns, GType *types)
121{
122 GtkTreeStore* tree_store = GTK_TREE_STORE (g_object_new (MIDORI_BOOKMARKS_TREE_STORE_TYPE, NULL));
123
124 if (!tree_store)
125 return NULL;
126
127 gtk_tree_store_set_column_types (tree_store,
128 n_columns,
129 types);
130
131 return tree_store;
132}
133
28gboolean134gboolean
29midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser,135midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser,
30 KatzeItem* bookmark,136 KatzeItem* bookmark,
@@ -36,6 +142,12 @@
36midori_browser_open_bookmark (MidoriBrowser* browser,142midori_browser_open_bookmark (MidoriBrowser* browser,
37 KatzeItem* item);143 KatzeItem* item);
38144
145static void
146midori_bookmarks_row_changed_cb (GtkTreeModel* model,
147 GtkTreePath* path,
148 GtkTreeIter* iter,
149 MidoriBookmarks* bookmarks);
150
39struct _MidoriBookmarks151struct _MidoriBookmarks
40{152{
41 GtkVBox parent_instance;153 GtkVBox parent_instance;
@@ -44,11 +156,12 @@
44 GtkWidget* delete;156 GtkWidget* delete;
45 GtkWidget* treeview;157 GtkWidget* treeview;
46 MidoriApp* app;158 MidoriApp* app;
47 KatzeArray* array;159 MidoriBookmarksDb* bookmarks_db;
48160
49 gint filter_timeout;161 gint filter_timeout;
50 gchar* filter;162 gchar* filter;
51163
164 GList* pending_inserts;
52 KatzeItem* hovering_item;165 KatzeItem* hovering_item;
53};166};
54167
@@ -87,7 +200,12 @@
87 GParamSpec* pspec);200 GParamSpec* pspec);
88201
89static void202static void
90midori_bookmarks_statusbar_update (MidoriBookmarks *bookmarks);203midori_bookmarks_add_item_cb (KatzeArray* array,
204 KatzeItem* item,
205 MidoriBookmarks* bookmarks);
206static void
207midori_bookmarks_update_cb (KatzeArray* array,
208 MidoriBookmarks* bookmarks);
91209
92static void210static void
93midori_bookmarks_class_init (MidoriBookmarksClass* class)211midori_bookmarks_class_init (MidoriBookmarksClass* class)
@@ -124,6 +242,7 @@
124 return STOCK_BOOKMARKS;242 return STOCK_BOOKMARKS;
125}243}
126244
245#if 0
127/* TODO: Function never used */246/* TODO: Function never used */
128void247void
129midori_bookmarks_export_array_db (sqlite3* db,248midori_bookmarks_export_array_db (sqlite3* db,
@@ -137,7 +256,7 @@
137 gchar* parent_id;256 gchar* parent_id;
138257
139 parent_id = g_strdup_printf ("%" G_GINT64_FORMAT, parentid);258 parent_id = g_strdup_printf ("%" G_GINT64_FORMAT, parentid);
140 if (!(root_array = midori_array_query (array, "*", "parentid = %q", parent_id)))259 if (!(root_array = midori_bookmarks_db_query_recursive (array, "*", "parentid = %q", parent_id, FALSE)))
141 {260 {
142 g_free (parent_id);261 g_free (parent_id);
143 return;262 return;
@@ -159,27 +278,7 @@
159 g_free (parent_id);278 g_free (parent_id);
160 g_list_free (list);279 g_list_free (list);
161}280}
162281#endif
163void
164midori_bookmarks_import_array_db (sqlite3* db,
165 KatzeArray* array,
166 gint64 parentid)
167{
168 GList* list;
169 KatzeItem* item;
170 gint64 id;
171
172 if (!db)
173 return;
174
175 KATZE_ARRAY_FOREACH_ITEM_L (item, array, list)
176 {
177 id = midori_bookmarks_insert_item_db (db, item, parentid);
178 if (KATZE_IS_ARRAY (item))
179 midori_bookmarks_import_array_db (db, KATZE_ARRAY (item), id);
180 }
181 g_list_free (list);
182}
183282
184static KatzeArray*283static KatzeArray*
185midori_bookmarks_read_from_db (MidoriBookmarks* bookmarks,284midori_bookmarks_read_from_db (MidoriBookmarks* bookmarks,
@@ -189,21 +288,21 @@
189 KatzeArray* array;288 KatzeArray* array;
190289
191 if (keyword && *keyword)290 if (keyword && *keyword)
192 array = midori_array_query (bookmarks->array,291 array = midori_bookmarks_db_query_recursive (bookmarks->bookmarks_db,
193 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "title LIKE '%%%q%%'", keyword);292 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "title LIKE '%%%q%%'", keyword, FALSE);
194 else293 else
195 {294 {
196 if (parentid > 0)295 if (parentid > 0)
197 {296 {
198 gchar* parent_id = g_strdup_printf ("%" G_GINT64_FORMAT, parentid);297 gchar* parent_id = g_strdup_printf ("%" G_GINT64_FORMAT, parentid);
199 array = midori_array_query (bookmarks->array,298 array = midori_bookmarks_db_query_recursive (bookmarks->bookmarks_db,
200 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "parentid = %q", parent_id);299 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "parentid = %q", parent_id, FALSE);
201300
202 g_free (parent_id);301 g_free (parent_id);
203 }302 }
204 else303 else
205 array = midori_array_query (bookmarks->array,304 array = midori_bookmarks_db_query_recursive (bookmarks->bookmarks_db,
206 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "parentid IS NULL", NULL);305 "id, parentid, title, uri, desc, app, toolbar, pos_panel, pos_bar", "parentid IS NULL", NULL, FALSE);
207 }306 }
208 return array ? array : katze_array_new (KATZE_TYPE_ITEM);307 return array ? array : katze_array_new (KATZE_TYPE_ITEM);
209}308}
@@ -234,90 +333,133 @@
234 g_object_unref (item);333 g_object_unref (item);
235}334}
236335
237gint64336static gboolean
238midori_bookmarks_insert_item_db (sqlite3* db,337midori_bookmarks_reach_item_recurse (GtkTreeModel* model,
239 KatzeItem* item,338 GtkTreeIter* iter,
240 gint64 parentid)339 gint64 id)
241{340{
242 gchar* sqlcmd;341 do
243 char* errmsg = NULL;
244 KatzeItem* old_parent;
245 gchar* new_parentid;
246 gchar* id = NULL;
247 const gchar* uri = NULL;
248 const gchar* desc = NULL;
249 gint64 seq = 0;
250
251 /* Bookmarks must have a name, import may produce invalid items */
252 g_return_val_if_fail (katze_item_get_name (item), seq);
253
254 if (!db)
255 return seq;
256
257 if (katze_item_get_meta_integer (item, "id") > 0)
258 id = g_strdup_printf ("%" G_GINT64_FORMAT, katze_item_get_meta_integer(item, "id"));
259 else
260 id = g_strdup_printf ("NULL");
261
262 if (KATZE_ITEM_IS_BOOKMARK (item))
263 uri = katze_item_get_uri (item);
264
265 if (katze_item_get_text (item))
266 desc = katze_item_get_text (item);
267
268 /* Use folder, otherwise fallback to parent folder */
269 old_parent = katze_item_get_parent (item);
270 if (parentid > 0)
271 new_parentid = g_strdup_printf ("%" G_GINT64_FORMAT, parentid);
272 else if (old_parent && katze_item_get_meta_integer (old_parent, "id") > 0)
273 new_parentid = g_strdup_printf ("%" G_GINT64_FORMAT, katze_item_get_meta_integer (old_parent, "id"));
274 else
275 new_parentid = g_strdup_printf ("NULL");
276
277 sqlcmd = sqlite3_mprintf (
278 "INSERT INTO bookmarks (id, parentid, title, uri, desc, toolbar, app) "
279 "VALUES (%q, %q, '%q', '%q', '%q', %d, %d)",
280 id,
281 new_parentid,
282 katze_item_get_name (item),
283 katze_str_non_null (uri),
284 katze_str_non_null (desc),
285 katze_item_get_meta_boolean (item, "toolbar"),
286 katze_item_get_meta_boolean (item, "app"));
287
288 if (sqlite3_exec (db, sqlcmd, NULL, NULL, &errmsg) == SQLITE_OK)
289 {342 {
290 /* Get insert id */343 GtkTreeIter child;
291 if (g_str_equal (id, "NULL"))344 KatzeItem *item;
292 {345 gint64 itemid = -1;
293 KatzeArray* seq_array;346
294347 gtk_tree_model_get (model, iter, 0, &item, -1);
295 sqlite3_free (sqlcmd);348
296 sqlcmd = sqlite3_mprintf (349 if (!KATZE_ITEM_IS_SEPARATOR(item))
297 "SELECT seq FROM sqlite_sequence WHERE name = 'bookmarks'");350 {
298351 itemid = katze_item_get_meta_integer (item, "id");
299 seq_array = katze_array_from_sqlite (db, sqlcmd);352 g_object_unref (item);
300 if (katze_array_get_nth_item (seq_array, 0))353 }
354
355 if (id == itemid)
356 return TRUE;
357
358 if (gtk_tree_model_iter_children (model, &child, iter))
359 {
360 if (midori_bookmarks_reach_item_recurse (model, &child, id))
301 {361 {
302 KatzeItem* seq_item = katze_array_get_nth_item (seq_array, 0);362 *iter = child;
303363 return TRUE;
304 seq = katze_item_get_meta_integer (seq_item, "seq");
305 katze_item_set_meta_integer (item, "id", seq);
306 }364 }
307 g_object_unref (seq_array);
308 }365 }
309 }366 }
310 else367 while (gtk_tree_model_iter_next(model, iter));
311 {368
312 g_printerr (_("Failed to add bookmark item: %s\n"), errmsg);369 return FALSE;
313 sqlite3_free (errmsg);370}
314 }371
315372static gboolean
316 sqlite3_free (sqlcmd);373midori_bookmarks_reach_item (GtkTreeModel* model,
317 g_free (new_parentid);374 GtkTreeIter* iter,
318 g_free (id);375 gint64 id)
319376{
320 return seq;377 if (!gtk_tree_model_get_iter_first(model, iter))
378 return FALSE;
379
380 return midori_bookmarks_reach_item_recurse (model, iter, id);
381}
382
383static void
384midori_bookmarks_add_item_to_model(GtkTreeStore* model,
385 GtkTreeIter* parent,
386 KatzeItem* item)
387{
388 if (KATZE_ITEM_IS_BOOKMARK (item))
389 {
390 gchar* tooltip = g_markup_escape_text (katze_item_get_uri (item), -1);
391
392 gtk_tree_store_insert_with_values (model, NULL, parent,
393 0,
394 0, item, 1, tooltip, -1);
395 g_free (tooltip);
396 }
397 else
398 {
399 GtkTreeIter root_iter;
400
401 gtk_tree_store_insert_with_values (model, &root_iter, parent,
402 0, 0, item, -1);
403
404 /* That's an invisible dummy, so we always have an expander */
405 gtk_tree_store_insert_with_values (model, NULL, &root_iter,
406 0,
407 0, NULL, -1);
408 }
409}
410
411static void
412midori_bookmarks_update_item_in_model(MidoriBookmarks* bookmarks,
413 GtkTreeStore* model,
414 GtkTreeIter* iter,
415 KatzeItem* item)
416{
417 g_signal_handlers_block_by_func (model,
418 midori_bookmarks_row_changed_cb,
419 bookmarks);
420
421 if (KATZE_ITEM_IS_BOOKMARK (item))
422 {
423 gchar* tooltip = g_markup_escape_text (katze_item_get_uri (item), -1);
424
425 gtk_tree_store_set(model, iter,
426 0, item, 1, tooltip, -1);
427
428 g_free (tooltip);
429 }
430 else
431 {
432 gtk_tree_store_set(model, iter,
433 0, item, -1);
434 }
435
436 g_signal_handlers_unblock_by_func (model,
437 midori_bookmarks_row_changed_cb,
438 bookmarks);
439}
440
441static void
442midori_bookmarks_add_item (KatzeItem* item,
443 MidoriBookmarks* bookmarks);
444
445static gboolean
446midori_bookmarks_idle (MidoriBookmarks* bookmarks)
447{
448 GList* list_iter;
449
450 for (list_iter = bookmarks->pending_inserts; list_iter; list_iter = g_list_next (list_iter))
451 {
452 KatzeItem *item = KATZE_ITEM (list_iter->data);
453
454 midori_bookmarks_add_item (item, bookmarks);
455
456 g_object_unref (item);
457 }
458
459 g_list_free (bookmarks->pending_inserts);
460 bookmarks->pending_inserts = NULL;
461
462 return FALSE;
321}463}
322464
323static void465static void
@@ -325,11 +467,98 @@
325 KatzeItem* item,467 KatzeItem* item,
326 MidoriBookmarks* bookmarks)468 MidoriBookmarks* bookmarks)
327{469{
328 GtkTreeModel* model;470 if (!bookmarks->pending_inserts)
329 model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));471 g_idle_add ((GSourceFunc)midori_bookmarks_idle, bookmarks);
330 gtk_tree_store_clear (GTK_TREE_STORE (model));472
331 midori_bookmarks_read_from_db_to_model (bookmarks,473 g_object_ref (item);
332 GTK_TREE_STORE (model), NULL, 0, bookmarks->filter);474 bookmarks->pending_inserts = g_list_append (bookmarks->pending_inserts, item);
475}
476
477static void
478midori_bookmarks_add_item (KatzeItem* item,
479 MidoriBookmarks* bookmarks)
480{
481 gint64 id = katze_item_get_meta_integer (item, "id");
482 gint64 parentid = katze_item_get_meta_integer (item, "parentid");
483 GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));
484 GtkTreeIter iter;
485
486 if (!parentid)
487 {
488 midori_bookmarks_add_item_to_model (GTK_TREE_STORE (model), NULL, item);
489 }
490 else if (midori_bookmarks_reach_item (model, &iter, parentid))
491 {
492 GtkTreePath* path = gtk_tree_model_get_path(model, &iter);
493
494 if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (bookmarks->treeview), path))
495 {
496 midori_bookmarks_add_item_to_model (GTK_TREE_STORE (model), &iter, item);
497 }
498
499 gtk_tree_path_free (path);
500 }
501}
502
503static void
504midori_bookmarks_update_item_cb (KatzeArray* array,
505 KatzeItem* item,
506 MidoriBookmarks* bookmarks)
507{
508 gint64 id = katze_item_get_meta_integer (item, "id");
509 gint64 parentid = katze_item_get_meta_integer (item, "parentid");
510 GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));
511 GtkTreeIter iter;
512
513 if (midori_bookmarks_reach_item (model, &iter, id))
514 {
515 gint64 old_parentid = 0;
516 GtkTreeIter parent;
517
518 if (gtk_tree_model_iter_parent (model, &parent, &iter))
519 {
520 KatzeItem* old_parent;
521
522 gtk_tree_model_get (model, &parent, 0, &old_parent, -1);
523
524 old_parentid = katze_item_get_meta_integer (old_parent, "id");
525
526 g_object_unref (old_parent);
527
528 if (parentid == old_parentid)
529 {
530 midori_bookmarks_update_item_in_model (bookmarks, GTK_TREE_STORE (model), &iter, item);
531 }
532 else
533 {
534 gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
535
536 if (!gtk_tree_model_iter_has_child (model, &parent))
537 {
538 GtkTreePath* path = gtk_tree_model_get_path(model, &parent);
539
540 if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (bookmarks->treeview), path))
541 gtk_tree_view_collapse_row (GTK_TREE_VIEW (bookmarks->treeview), path);
542
543 gtk_tree_path_free (path);
544 }
545
546 midori_bookmarks_add_item (item, bookmarks);
547 }
548 }
549 else if (parentid == 0)
550 {
551 midori_bookmarks_update_item_in_model (bookmarks, GTK_TREE_STORE (model), &iter, item);
552 }
553 else
554 {
555 gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
556
557 midori_bookmarks_add_item (item, bookmarks);
558 }
559 }
560 else
561 midori_bookmarks_add_item (item, bookmarks);
333}562}
334563
335static void564static void
@@ -337,12 +566,36 @@
337 KatzeItem* item,566 KatzeItem* item,
338 MidoriBookmarks* bookmarks)567 MidoriBookmarks* bookmarks)
339{568{
569 gint64 id = katze_item_get_meta_integer (item, "id");
340 GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));570 GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));
341 gtk_tree_store_clear (GTK_TREE_STORE (model));571 GtkTreeIter iter;
342 midori_bookmarks_read_from_db_to_model (bookmarks,572
343 GTK_TREE_STORE (model), NULL, 0, bookmarks->filter);573 if (midori_bookmarks_reach_item (model, &iter, id))
574 {
575 GtkTreeIter parent;
576
577 if (gtk_tree_model_iter_parent (model, &parent, &iter))
578 {
579 gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
580
581 if (!gtk_tree_model_iter_has_child (model, &parent))
582 {
583 GtkTreePath* path = gtk_tree_model_get_path(model, &parent);
584
585 if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (bookmarks->treeview), path))
586 gtk_tree_view_collapse_row (GTK_TREE_VIEW (bookmarks->treeview), path);
587
588 gtk_tree_path_free (path);
589 }
590 }
591 else
592 {
593 gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
594 }
595 }
344}596}
345597
598
346static void599static void
347midori_bookmarks_update_cb (KatzeArray* array,600midori_bookmarks_update_cb (KatzeArray* array,
348 MidoriBookmarks* bookmarks)601 MidoriBookmarks* bookmarks)
@@ -354,6 +607,42 @@
354}607}
355608
356609
610static gboolean
611midori_bookmarks_tree_store_row_drop_possible (GtkTreeDragDest* drag_dest,
612 GtkTreePath* dest_path,
613 GtkSelectionData* selection_data)
614{
615 gboolean row_drop_possible =
616 gtk_tree_store_gtk_tree_drag_dest_iface->row_drop_possible (drag_dest,
617 dest_path,
618 selection_data);
619
620 if (!row_drop_possible)
621 return FALSE;
622
623 if ((!gtk_tree_path_get_depth(dest_path) > 1)
624 && gtk_tree_path_up(dest_path))
625 {
626 GtkTreeModel* model = GTK_TREE_MODEL(drag_dest);
627 GtkTreeIter iter;
628
629 if (gtk_tree_model_get_iter (model, &iter, dest_path))
630 {
631 KatzeItem* item;
632
633 gtk_tree_model_get (model, &iter, 0, &item, -1);
634
635 if (!KATZE_ITEM_IS_FOLDER(item))
636 row_drop_possible = FALSE;
637
638 if (item)
639 g_object_unref (item);
640 }
641 }
642
643 return row_drop_possible;
644}
645
357static void646static void
358midori_bookmarks_row_changed_cb (GtkTreeModel* model,647midori_bookmarks_row_changed_cb (GtkTreeModel* model,
359 GtkTreePath* path,648 GtkTreePath* path,
@@ -362,31 +651,37 @@
362{651{
363 KatzeItem* item;652 KatzeItem* item;
364 GtkTreeIter parent;653 GtkTreeIter parent;
365 KatzeItem* new_parent = NULL;654 gint64 parentid = 0;
366 gint64 parentid;
367
368 gtk_tree_model_get (model, iter, 0, &item, -1);
369655
370 if (gtk_tree_model_iter_parent (model, &parent, iter))656 if (gtk_tree_model_iter_parent (model, &parent, iter))
371 {657 {
658 KatzeItem* new_parent;
659
372 gtk_tree_model_get (model, &parent, 0, &new_parent, -1);660 gtk_tree_model_get (model, &parent, 0, &new_parent, -1);
373661
374 /* Bookmarks must not be moved into non-folder items */662 /* Bookmarks cannot be moved into non-folder items */
375 if (!KATZE_ITEM_IS_FOLDER (new_parent))663 g_assert (KATZE_ITEM_IS_FOLDER (new_parent));
376 parentid = 0;664
377 else665 parentid = katze_item_get_meta_integer (new_parent, "id");
378 parentid = katze_item_get_meta_integer (new_parent, "id");666
667 g_object_unref (new_parent);
379 }668 }
380 else669
381 parentid = 0;670 gtk_tree_model_get (model, iter, 0, &item, -1);
382671
383 katze_array_remove_item (bookmarks->array, item);
384 katze_item_set_meta_integer (item, "parentid", parentid);672 katze_item_set_meta_integer (item, "parentid", parentid);
385 katze_array_add_item (bookmarks->array, item);673
674 g_signal_handlers_block_by_func (bookmarks->bookmarks_db,
675 midori_bookmarks_update_item_cb,
676 bookmarks);
677
678 midori_bookmarks_db_update_item (bookmarks->bookmarks_db, item);
679
680 g_signal_handlers_unblock_by_func (bookmarks->bookmarks_db,
681 midori_bookmarks_update_item_cb,
682 bookmarks);
386683
387 g_object_unref (item);684 g_object_unref (item);
388 if (new_parent)
389 g_object_unref (new_parent);
390}685}
391686
392static void687static void
@@ -412,24 +707,15 @@
412 {707 {
413 KatzeItem* item;708 KatzeItem* item;
414 MidoriBrowser* browser;709 MidoriBrowser* browser;
415 gint64 parentid;
416710
417 gtk_tree_model_get (model, &iter, 0, &item, -1);711 gtk_tree_model_get (model, &iter, 0, &item, -1);
418712
419 g_assert (!KATZE_ITEM_IS_SEPARATOR (item));713 g_assert (!KATZE_ITEM_IS_SEPARATOR (item));
420714
421 browser = midori_browser_get_for_widget (bookmarks->treeview);715 browser = midori_browser_get_for_widget (bookmarks->treeview);
422 parentid = katze_item_get_meta_integer (item, "parentid");
423 midori_browser_edit_bookmark_dialog_new (716 midori_browser_edit_bookmark_dialog_new (
424 browser, item, FALSE, KATZE_ITEM_IS_FOLDER (item), NULL);717 browser, item, FALSE, KATZE_ITEM_IS_FOLDER (item), NULL);
425718
426 if (katze_item_get_meta_integer (item, "parentid") != parentid)
427 {
428 gtk_tree_store_clear (GTK_TREE_STORE (model));
429 midori_bookmarks_read_from_db_to_model (bookmarks, GTK_TREE_STORE (model),
430 NULL, 0, NULL);
431 }
432
433 g_object_unref (item);719 g_object_unref (item);
434 }720 }
435}721}
@@ -445,7 +731,7 @@
445 gtk_widget_set_sensitive (GTK_WIDGET (bookmarks->edit), selected);731 gtk_widget_set_sensitive (GTK_WIDGET (bookmarks->edit), selected);
446}732}
447733
448static gchar* 734static gchar*
449midori_bookmarks_statusbar_bookmarks_str (gint count)735midori_bookmarks_statusbar_bookmarks_str (gint count)
450{736{
451 if (!count)737 if (!count)
@@ -455,7 +741,7 @@
455 return g_strdup_printf (ngettext ("%d bookmark", "%d bookmarks", count), count);741 return g_strdup_printf (ngettext ("%d bookmark", "%d bookmarks", count), count);
456}742}
457743
458static gchar* 744static gchar*
459midori_bookmarks_statusbar_subfolders_str (gint count)745midori_bookmarks_statusbar_subfolders_str (gint count)
460{746{
461 if (!count)747 if (!count)
@@ -481,9 +767,9 @@
481767
482 if (KATZE_ITEM_IS_FOLDER (item))768 if (KATZE_ITEM_IS_FOLDER (item))
483 {769 {
484 gint child_folders_count = midori_array_count_recursive (bookmarks->array,770 gint child_folders_count = midori_bookmarks_db_count_recursive (bookmarks->bookmarks_db,
485 "uri = ''", NULL, item, FALSE);771 "uri = ''", NULL, item, FALSE);
486 gint child_bookmarks_count = midori_array_count_recursive (bookmarks->array,772 gint child_bookmarks_count = midori_bookmarks_db_count_recursive (bookmarks->bookmarks_db,
487 "uri <> ''", NULL, item, FALSE);773 "uri <> ''", NULL, item, FALSE);
488 gchar* child_folders_str = midori_bookmarks_statusbar_subfolders_str (child_folders_count);774 gchar* child_folders_str = midori_bookmarks_statusbar_subfolders_str (child_folders_count);
489 gchar* child_bookmarks_str = midori_bookmarks_statusbar_bookmarks_str (child_bookmarks_count);775 gchar* child_bookmarks_str = midori_bookmarks_statusbar_bookmarks_str (child_bookmarks_count);
@@ -516,13 +802,13 @@
516 }802 }
517 else803 else
518 {804 {
519 gint child_folders_count = midori_array_count_recursive (bookmarks->array,805 gint child_folders_count = midori_bookmarks_db_count_recursive (bookmarks->bookmarks_db,
520 "uri = ''", NULL, NULL, FALSE);806 "uri = ''", NULL, NULL, FALSE);
521 gint child_bookmarks_count = midori_array_count_recursive (bookmarks->array,807 gint child_bookmarks_count = midori_bookmarks_db_count_recursive (bookmarks->bookmarks_db,
522 "uri <> ''", NULL, NULL, FALSE);808 "uri <> ''", NULL, NULL, FALSE);
523 gchar* child_folders_str = midori_bookmarks_statusbar_subfolders_str (child_folders_count);809 gchar* child_folders_str = midori_bookmarks_statusbar_subfolders_str (child_folders_count);
524 gchar* child_bookmarks_str = midori_bookmarks_statusbar_bookmarks_str (child_bookmarks_count);810 gchar* child_bookmarks_str = midori_bookmarks_statusbar_bookmarks_str (child_bookmarks_count);
525 811
526 if (!child_bookmarks_count && (child_folders_count >= 1))812 if (!child_bookmarks_count && (child_folders_count >= 1))
527 /* i18n: [[n] folder(s)] and no bookmark */813 /* i18n: [[n] folder(s)] and no bookmark */
528 text = g_strdup_printf (_("%s and no bookmark"),814 text = g_strdup_printf (_("%s and no bookmark"),
@@ -533,7 +819,7 @@
533 /* i18n: [[n] bookmark(s)] and [[n] folder(s)] */819 /* i18n: [[n] bookmark(s)] and [[n] folder(s)] */
534 text = g_strdup_printf (_("%s and %s"),820 text = g_strdup_printf (_("%s and %s"),
535 child_bookmarks_str, child_folders_str);821 child_bookmarks_str, child_folders_str);
536 822
537 g_free (child_folders_str);823 g_free (child_folders_str);
538 g_free (child_bookmarks_str);824 g_free (child_bookmarks_str);
539 }825 }
@@ -541,9 +827,9 @@
541 if (text)827 if (text)
542 {828 {
543 MidoriBrowser* browser = midori_browser_get_for_widget (bookmarks->treeview);829 MidoriBrowser* browser = midori_browser_get_for_widget (bookmarks->treeview);
544 830
545 g_object_set (browser, "statusbar-text", text, NULL);831 g_object_set (browser, "statusbar-text", text, NULL);
546 832
547 g_free(text);833 g_free(text);
548 }834 }
549}835}
@@ -603,13 +889,8 @@
603889
604 gtk_tree_model_get (model, &iter, 0, &item, -1);890 gtk_tree_model_get (model, &iter, 0, &item, -1);
605891
606 /* Manually remove the iter and block clearing the treeview */892 midori_bookmarks_db_remove_item (bookmarks->bookmarks_db, item);
607 gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);893
608 g_signal_handlers_block_by_func (bookmarks->array,
609 midori_bookmarks_remove_item_cb, bookmarks);
610 katze_array_remove_item (bookmarks->array, item);
611 g_signal_handlers_unblock_by_func (bookmarks->array,
612 midori_bookmarks_remove_item_cb, bookmarks);
613 g_object_unref (item);894 g_object_unref (item);
614 }895 }
615}896}
@@ -693,9 +974,9 @@
693 GtkTreeModel* model;974 GtkTreeModel* model;
694975
695 model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));976 model = gtk_tree_view_get_model (GTK_TREE_VIEW (bookmarks->treeview));
696 if (bookmarks->array)977 if (bookmarks->bookmarks_db)
697 {978 {
698 g_object_unref (bookmarks->array);979 g_object_unref (bookmarks->bookmarks_db);
699 gtk_tree_store_clear (GTK_TREE_STORE (model));980 gtk_tree_store_clear (GTK_TREE_STORE (model));
700 }981 }
701 katze_assign (bookmarks->app, app);982 katze_assign (bookmarks->app, app);
@@ -703,17 +984,19 @@
703 return;984 return;
704985
705 g_object_ref (app);986 g_object_ref (app);
706 bookmarks->array = katze_object_get_object (app, "bookmarks");987 bookmarks->bookmarks_db = katze_object_get_object (app, "bookmarks");
707 midori_bookmarks_read_from_db_to_model (bookmarks, GTK_TREE_STORE (model), NULL, 0, NULL);988 midori_bookmarks_read_from_db_to_model (bookmarks, GTK_TREE_STORE (model), NULL, 0, NULL);
708 g_signal_connect_after (bookmarks->array, "add-item",989 g_signal_connect_after (bookmarks->bookmarks_db, "add-item",
709 G_CALLBACK (midori_bookmarks_add_item_cb), bookmarks);990 G_CALLBACK (midori_bookmarks_add_item_cb), bookmarks);
710 g_signal_connect (bookmarks->array, "remove-item",991 g_signal_connect_after (bookmarks->bookmarks_db, "update-item",
711 G_CALLBACK (midori_bookmarks_remove_item_cb), bookmarks);992 G_CALLBACK (midori_bookmarks_update_item_cb), bookmarks);
712 g_signal_connect (bookmarks->array, "update",993 g_signal_connect (bookmarks->bookmarks_db, "remove-item",
713 G_CALLBACK (midori_bookmarks_update_cb), bookmarks);994 G_CALLBACK (midori_bookmarks_remove_item_cb), bookmarks);
995 g_signal_connect (bookmarks->bookmarks_db, "update",
996 G_CALLBACK (midori_bookmarks_update_cb), bookmarks);
714 g_signal_connect_after (model, "row-changed",997 g_signal_connect_after (model, "row-changed",
715 G_CALLBACK (midori_bookmarks_row_changed_cb),998 G_CALLBACK (midori_bookmarks_row_changed_cb),
716 bookmarks);999 bookmarks);
717}1000}
7181001
719static void1002static void
@@ -943,12 +1226,12 @@
943 menu = gtk_menu_new ();1226 menu = gtk_menu_new ();
944 if (KATZE_ITEM_IS_FOLDER (item))1227 if (KATZE_ITEM_IS_FOLDER (item))
945 {1228 {
946 gint child_bookmarks_count = midori_array_count_recursive (bookmarks->array,1229 gint child_bookmarks_count = midori_bookmarks_db_count_recursive (bookmarks->bookmarks_db,
947 "uri <> ''", NULL, item, FALSE);1230 "uri <> ''", NULL, item, FALSE);
9481231
949 midori_bookmarks_popup_item (menu,1232 midori_bookmarks_popup_item (menu,
950 STOCK_TAB_NEW, _("Open all in _Tabs"), item, 1233 STOCK_TAB_NEW, _("Open all in _Tabs"), item,
951 (!child_bookmarks_count ? NULL : midori_bookmarks_open_in_tab_activate_cb), 1234 (!child_bookmarks_count ? NULL : midori_bookmarks_open_in_tab_activate_cb),
952 bookmarks);1235 bookmarks);
953 }1236 }
954 else1237 else
@@ -1080,7 +1363,7 @@
1080static KatzeItem*1363static KatzeItem*
1081midori_bookmarks_get_item_at_pos (GtkTreeView *treeview,1364midori_bookmarks_get_item_at_pos (GtkTreeView *treeview,
1082 gint x, gint y)1365 gint x, gint y)
1083{ 1366{
1084 GtkTreeModel* model = gtk_tree_view_get_model (treeview);1367 GtkTreeModel* model = gtk_tree_view_get_model (treeview);
1085 GtkTreePath* path;1368 GtkTreePath* path;
1086 GtkTreeIter iter;1369 GtkTreeIter iter;
@@ -1088,13 +1371,13 @@
10881371
1089 gtk_tree_view_get_path_at_pos (treeview, x, y,1372 gtk_tree_view_get_path_at_pos (treeview, x, y,
1090 &path, NULL, NULL, NULL);1373 &path, NULL, NULL, NULL);
1091 1374
1092 if (!path)1375 if (!path)
1093 return NULL;1376 return NULL;
1094 1377
1095 if (gtk_tree_model_get_iter (model, &iter, path))1378 if (gtk_tree_model_get_iter (model, &iter, path))
1096 gtk_tree_model_get (model, &iter, 0, &item, -1);1379 gtk_tree_model_get (model, &iter, 0, &item, -1);
1097 1380
1098 gtk_tree_path_free (path);1381 gtk_tree_path_free (path);
10991382
1100 return item;1383 return item;
@@ -1166,7 +1449,7 @@
11661449
1167 if (bookmarks->hovering_item)1450 if (bookmarks->hovering_item)
1168 g_object_unref (bookmarks->hovering_item);1451 g_object_unref (bookmarks->hovering_item);
1169 1452
1170 bookmarks->hovering_item = NULL;1453 bookmarks->hovering_item = NULL;
11711454
1172 g_object_set (browser, "statusbar-text", "", NULL);1455 g_object_set (browser, "statusbar-text", "", NULL);
@@ -1229,7 +1512,7 @@
1229 gtk_box_pack_start (GTK_BOX (bookmarks), box, FALSE, FALSE, 5);1512 gtk_box_pack_start (GTK_BOX (bookmarks), box, FALSE, FALSE, 5);
12301513
1231 /* Create the treeview */1514 /* Create the treeview */
1232 model = gtk_tree_store_new (2, KATZE_TYPE_ITEM, G_TYPE_STRING);1515 model = midori_bookmarks_tree_store_new (2, KATZE_TYPE_ITEM, G_TYPE_STRING);
1233 treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));1516 treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
1234 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);1517 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
1235 gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (treeview), 1);1518 gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (treeview), 1);
@@ -1268,7 +1551,7 @@
1268 "signal::leave-notify-event",1551 "signal::leave-notify-event",
1269 midori_bookmarks_leave_notify_event_cb, bookmarks,1552 midori_bookmarks_leave_notify_event_cb, bookmarks,
1270 NULL);1553 NULL);
1271 gtk_widget_add_events (GTK_WIDGET (treeview), 1554 gtk_widget_add_events (GTK_WIDGET (treeview),
1272 GDK_POINTER_MOTION_MASK1555 GDK_POINTER_MOTION_MASK
1273 | GDK_POINTER_MOTION_HINT_MASK);1556 | GDK_POINTER_MOTION_HINT_MASK);
12741557
@@ -1279,6 +1562,7 @@
1279 gtk_widget_show (treeview);1562 gtk_widget_show (treeview);
1280 gtk_box_pack_start (GTK_BOX (bookmarks), treeview, TRUE, TRUE, 0);1563 gtk_box_pack_start (GTK_BOX (bookmarks), treeview, TRUE, TRUE, 0);
1281 bookmarks->treeview = treeview;1564 bookmarks->treeview = treeview;
1565 bookmarks->pending_inserts = NULL;
1282 bookmarks->hovering_item = NULL;1566 bookmarks->hovering_item = NULL;
1283}1567}
12841568
12851569
=== modified file 'panels/midori-bookmarks.h'
--- panels/midori-bookmarks.h 2012-11-25 11:26:03 +0000
+++ panels/midori-bookmarks.h 2013-06-11 20:53:24 +0000
@@ -37,20 +37,6 @@
37GType37GType
38midori_bookmarks_get_type (void);38midori_bookmarks_get_type (void);
3939
40gint64
41midori_bookmarks_insert_item_db (sqlite3* db,
42 KatzeItem* item,
43 gint64 parentid);
44
45void
46midori_bookmarks_import_array_db (sqlite3* db,
47 KatzeArray* array,
48 gint64 parentid);
49
50gboolean
51midori_bookmarks_update_item_db (sqlite3* db,
52 KatzeItem* item);
53
54G_END_DECLS40G_END_DECLS
5541
56#endif /* __MIDORI_BOOKMARKS_PANEL_H__ */42#endif /* __MIDORI_BOOKMARKS_PANEL_H__ */

Subscribers

People subscribed via source and target branches

to all changes: