Merge lp:~aauzi/midori/fix-1177553-3 into lp:midori

Proposed by André Auzi
Status: Merged
Approved by: Paweł Forysiuk
Approved revision: 6247
Merged at revision: 6290
Proposed branch: lp:~aauzi/midori/fix-1177553-3
Merge into: lp:midori
Diff against target: 876 lines (+771/-37)
3 files modified
katze/katze-cellrenderercomboboxtext.c (+518/-0)
katze/katze-cellrenderercomboboxtext.h (+58/-0)
midori/midori-browser.c (+195/-37)
To merge this branch: bzr merge lp:~aauzi/midori/fix-1177553-3
Reviewer Review Type Date Requested Status
Paweł Forysiuk Approve
Cris Dywan Approve
Review via email: mp+177272@code.launchpad.net

This proposal supersedes a proposal from 2013-07-18.

Commit message

Show folder tree when editing bookmarks

Description of the change

This last step for Bookmark folder tree reflection addresses the bookmarks edit dialog combo box.

The combo box is reworked to display a tree view of the bookmark folders.

Folder icons are added and give, in the combo box, a display of folders that aims to have consistent aspect with bookmark bar, bookmark menu and bookmark panel.

The combo box population algorithm is reworked to handle the case of sub-folders referring to a previously populated parent folder.

After this process, remaining items of the retrieved folders list are orphaned folder entries.

Opened folder are now displayed with the message 'Select [folder name]'.

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

I could live with the "duplicate" folder if need be. If it's feasible I'd consider renaming the "second" menu item to "Choose this folder", a style I've seen in a few places.
For the sizing, sokoke.c has a function, alternatively something screen width based. Hard to say which works best in this case honestly.

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

Could you provide some reasoning as to what the 2 new classes offer over standard cell renderers?

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

> Could you provide some reasoning as to what the 2 new classes offer over
> standard cell renderers?

Sure.

The combobox uses the same tree store row for the folder and the top menuitem it presents, before the separator, in the subfolder list view.

That's why we get the same name and icons in the opened folder and the top menuitem of the subfolders list.

I had to figure out a way to distinguish between the two situations:
a/ when the rendered row corresponds to the folder
b/ when the rendered row corresponds to the top of subfolders list

Since the cell renderers are executed on the same row this could not be done by information stored in the row itself.

The cell renderers I've (rapidly) written examine the containing menu to determine if they're called on a the first widget of a menu, just before a separator.

This could had been avoided for pixbufs if the combobox managed the 'expanded' property of the cell renderer, as a treeview does, but, unless I've made a big mistake, it does not seem to do it. (I couldn't make it work :/)

The two new classes are actually tied to the combobox implementation and offer the capability to render different text and pixbufs for the folder when it's listed in a menu or presented at the top of it's containees.

Note: since the detection is the same for the two classes I believe they can be implemented with about half of the code I used here.

Honestly, if combobox on tree store is not used elsewhere, I would be reluctant to keep them.

I'd only provide them if negative user feedback was given on the previous, straight forward, implementation.

Revision history for this message
Cris Dywan (kalikiana) wrote :

I'm fine with the approach, purely technically speaking.

review: Approve
Revision history for this message
Paweł Forysiuk (tuxator) wrote :

Seems to work fine. Approve

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'katze/katze-cellrenderercomboboxtext.c'
--- katze/katze-cellrenderercomboboxtext.c 1970-01-01 00:00:00 +0000
+++ katze/katze-cellrenderercomboboxtext.c 2013-07-27 21:58:26 +0000
@@ -0,0 +1,518 @@
1/*
2 Copyright (C) 2008-2013 Christian Dywan <christian@twotoasts.de>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 See the file COPYING for the full license text.
10*/
11
12#include "katze-cellrenderercomboboxtext.h"
13
14#include "marshal.h"
15
16#include <string.h>
17#include <gdk/gdk.h>
18
19#define P_(String) (String)
20#define I_(String) (String)
21#define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
22#define GTK_PARAM_WRITABLE G_PARAM_WRITABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
23#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
24
25
26static void
27katze_cell_renderer_combobox_text_finalize (GObject* object);
28
29static void
30katze_cell_renderer_combobox_text_get_property (GObject* object,
31 guint param_id,
32 GValue* value,
33 GParamSpec* pspec);
34static void
35katze_cell_renderer_combobox_text_set_property (GObject* object,
36 guint param_id,
37 const GValue* value,
38 GParamSpec* pspec);
39static void
40katze_cell_renderer_combobox_text_get_size (GtkCellRenderer* cell,
41 GtkWidget* widget,
42 GdkRectangle* cell_area,
43 gint* x_offset,
44 gint* y_offset,
45 gint* width,
46 gint* height);
47#if GTK_CHECK_VERSION(3,0,0)
48static void
49katze_cell_renderer_combobox_text_render (GtkCellRenderer *cell,
50 cairo_t* cr,
51 GtkWidget *widget,
52 GdkRectangle *background_area,
53 GdkRectangle *cell_area,
54 GtkCellRendererState flags);
55#else
56static void
57katze_cell_renderer_combobox_text_render (GtkCellRenderer *cell,
58 GdkDrawable *window,
59 GtkWidget *widget,
60 GdkRectangle *background_area,
61 GdkRectangle *cell_area,
62 GdkRectangle *expose_area,
63 GtkCellRendererState flags);
64#endif
65
66static void
67(*_cell_renderer_get_size) (GtkCellRenderer* cell,
68 GtkWidget* widget,
69 GdkRectangle* cell_area,
70 gint* x_offset,
71 gint* y_offset,
72 gint* width,
73 gint* height);
74
75#if GTK_CHECK_VERSION(3,0,0)
76static void
77(*_cell_renderer_render) (GtkCellRenderer *cell,
78 cairo_t* cr,
79 GtkWidget *widget,
80 GdkRectangle *background_area,
81 GdkRectangle *cell_area,
82 GtkCellRendererState flags) = NULL;
83#else
84static void
85(*_cell_renderer_render) (GtkCellRenderer *cell,
86 GdkDrawable *window,
87 GtkWidget *widget,
88 GdkRectangle *background_area,
89 GdkRectangle *cell_area,
90 GdkRectangle *expose_area,
91 GtkCellRendererState flags) = NULL;
92#endif
93
94enum {
95 PROP_0,
96
97 PROP_FOLDED_TEXT,
98 PROP_FOLDED_MARKUP,
99 PROP_FOLDED_ATTRIBUTES,
100 PROP_UNFOLDED_TEXT,
101 PROP_UNFOLDED_MARKUP,
102 PROP_UNFOLDED_ATTRIBUTES,
103};
104
105#define KATZE_CELL_RENDERER_COMBOBOX_TEXT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), KATZE_TYPE_CELL_RENDERER_COMBOBOX_TEXT, KatzeCellRendererComboBoxTextPrivate))
106
107typedef struct _KatzeCellRendererComboBoxTextPrivate KatzeCellRendererComboBoxTextPrivate;
108struct _KatzeCellRendererComboBoxTextPrivate
109{
110 struct _Properties {
111 PangoAttrList* extra_attrs;
112
113 gchar* text;
114
115 guint markup_set : 1;
116 } props[2];
117};
118
119G_DEFINE_TYPE (KatzeCellRendererComboBoxText, katze_cell_renderer_combobox_text, GTK_TYPE_CELL_RENDERER_TEXT)
120
121static void
122katze_cell_renderer_combobox_text_init (KatzeCellRendererComboBoxText *celltext)
123{
124 guint prop_index;
125 KatzeCellRendererComboBoxTextPrivate *priv;
126
127 priv = KATZE_CELL_RENDERER_COMBOBOX_TEXT_GET_PRIVATE (celltext);
128
129 for (prop_index = 0 ; prop_index < 2; prop_index++)
130 {
131 priv->props[prop_index].text = NULL;
132 priv->props[prop_index].extra_attrs = NULL;
133 priv->props[prop_index].markup_set = FALSE;
134 }
135}
136
137static void
138katze_cell_renderer_combobox_text_class_init (KatzeCellRendererComboBoxTextClass *class)
139{
140 GObjectClass *object_class = G_OBJECT_CLASS (class);
141 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
142
143 object_class->finalize = katze_cell_renderer_combobox_text_finalize;
144
145 _cell_renderer_get_size = cell_class->get_size;
146 _cell_renderer_render = cell_class->render;
147
148 object_class->get_property = katze_cell_renderer_combobox_text_get_property;
149 object_class->set_property = katze_cell_renderer_combobox_text_set_property;
150
151 cell_class->get_size = katze_cell_renderer_combobox_text_get_size;
152 cell_class->render = katze_cell_renderer_combobox_text_render;
153
154 g_object_class_install_property (object_class,
155 PROP_FOLDED_TEXT,
156 g_param_spec_string ("folded-text",
157 P_("Folded text"),
158 P_("Text to render if combobox_text is closed. The string [text] is replaced by default text"),
159 NULL,
160 GTK_PARAM_READWRITE));
161
162 g_object_class_install_property (object_class,
163 PROP_FOLDED_MARKUP,
164 g_param_spec_string ("folded-markup",
165 P_("Folded markup"),
166 P_("Marked up text to render if combobox_text is closed. The string [text] is replaced by default text"),
167 NULL,
168 GTK_PARAM_WRITABLE));
169
170 g_object_class_install_property (object_class,
171 PROP_FOLDED_ATTRIBUTES,
172 g_param_spec_boxed ("folded-attributes",
173 P_("Folded attributes"),
174 P_("A list of style attributes to apply to the text of the renderer if combobox_text is closed"),
175 PANGO_TYPE_ATTR_LIST,
176 GTK_PARAM_READWRITE));
177
178 g_object_class_install_property (object_class,
179 PROP_UNFOLDED_TEXT,
180 g_param_spec_string ("unfolded-text",
181 P_("Unfolded text"),
182 P_("Text to render if combobox_text is opened"),
183 NULL,
184 GTK_PARAM_READWRITE));
185
186 g_object_class_install_property (object_class,
187 PROP_UNFOLDED_MARKUP,
188 g_param_spec_string ("unfolded-markup",
189 P_("Unfolded markup"),
190 P_("Marked up text to render if combobox_text is opened"),
191 NULL,
192 GTK_PARAM_WRITABLE));
193
194 g_object_class_install_property (object_class,
195 PROP_UNFOLDED_ATTRIBUTES,
196 g_param_spec_boxed ("unfolded-attributes",
197 P_("Unfolded attributes"),
198 P_("A list of style attributes to apply to the text of the renderer if combobox_text is opened"),
199 PANGO_TYPE_ATTR_LIST,
200 GTK_PARAM_READWRITE));
201
202
203 g_type_class_add_private (object_class, sizeof (KatzeCellRendererComboBoxTextPrivate));
204}
205
206static void
207katze_cell_renderer_combobox_text_finalize (GObject *object)
208{
209 guint prop_index;
210 KatzeCellRendererComboBoxTextPrivate *priv;
211
212 priv = KATZE_CELL_RENDERER_COMBOBOX_TEXT_GET_PRIVATE (object);
213
214 for (prop_index = 0 ; prop_index < 2; prop_index++)
215 {
216 g_free (priv->props[prop_index].text);
217 if (priv->props[prop_index].extra_attrs)
218 pango_attr_list_unref (priv->props[prop_index].extra_attrs);
219 }
220
221 G_OBJECT_CLASS (katze_cell_renderer_combobox_text_parent_class)->finalize (object);
222}
223
224static void
225katze_cell_renderer_combobox_text_get_property (GObject* object,
226 guint param_id,
227 GValue* value,
228 GParamSpec* pspec)
229{
230 KatzeCellRendererComboBoxTextPrivate *priv;
231
232 priv = KATZE_CELL_RENDERER_COMBOBOX_TEXT_GET_PRIVATE (object);
233
234 switch (param_id)
235 {
236 case PROP_FOLDED_TEXT:
237 g_value_set_string (value, priv->props[0].text);
238 break;
239
240 case PROP_FOLDED_ATTRIBUTES:
241 g_value_set_boxed (value, priv->props[0].extra_attrs);
242 break;
243
244 case PROP_UNFOLDED_TEXT:
245 g_value_set_string (value, priv->props[1].text);
246 break;
247
248 case PROP_UNFOLDED_ATTRIBUTES:
249 g_value_set_boxed (value, priv->props[1].extra_attrs);
250 break;
251
252 case PROP_FOLDED_MARKUP:
253 case PROP_UNFOLDED_MARKUP:
254 default:
255 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
256 break;
257 }
258}
259
260
261static void
262katze_cell_renderer_combobox_text_set_property (GObject* object,
263 guint param_id,
264 const GValue* value,
265 GParamSpec* pspec)
266{
267 guint prop_index = 0;
268 KatzeCellRendererComboBoxTextPrivate *priv;
269
270 priv = KATZE_CELL_RENDERER_COMBOBOX_TEXT_GET_PRIVATE (object);
271
272 switch (param_id)
273 {
274 case PROP_FOLDED_TEXT:
275 prop_text:
276 g_free (priv->props[prop_index].text);
277
278 if (priv->props[prop_index].markup_set)
279 {
280 if (priv->props[prop_index].extra_attrs)
281 {
282 pango_attr_list_unref (priv->props[prop_index].extra_attrs);
283 priv->props[prop_index].extra_attrs = NULL;
284 }
285 priv->props[prop_index].markup_set = FALSE;
286 }
287
288 priv->props[prop_index].text = g_value_dup_string (value);
289 break;
290
291 case PROP_FOLDED_ATTRIBUTES:
292 prop_attributes:
293 if (priv->props[prop_index].extra_attrs)
294 pango_attr_list_unref (priv->props[prop_index].extra_attrs);
295
296 priv->props[prop_index].extra_attrs = g_value_get_boxed (value);
297 if (priv->props[prop_index].extra_attrs)
298 pango_attr_list_ref (priv->props[prop_index].extra_attrs);
299 break;
300
301 case PROP_FOLDED_MARKUP:
302 prop_markup:
303 {
304 const gchar *str;
305 gchar *text = NULL;
306 GError *error = NULL;
307 PangoAttrList *attrs = NULL;
308
309 str = g_value_get_string (value);
310 if (str && !pango_parse_markup (str,
311 -1,
312 0,
313 &attrs,
314 &text,
315 NULL,
316 &error))
317 {
318 g_warning ("Failed to set text from markup due to error parsing markup: %s",
319 error->message);
320 g_error_free (error);
321 return;
322 }
323
324 g_free (priv->props[prop_index].text);
325
326 if (priv->props[prop_index].extra_attrs)
327 pango_attr_list_unref (priv->props[prop_index].extra_attrs);
328
329 priv->props[prop_index].text = text;
330 priv->props[prop_index].extra_attrs = attrs;
331 priv->props[prop_index].markup_set = TRUE;
332 }
333 break;
334
335 case PROP_UNFOLDED_TEXT:
336 prop_index = 1;
337 goto prop_text;
338
339 case PROP_UNFOLDED_ATTRIBUTES:
340 prop_index = 1;
341 goto prop_attributes;
342
343 case PROP_UNFOLDED_MARKUP:
344 prop_index = 1;
345 goto prop_markup;
346
347 default:
348 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
349 break;
350 }
351}
352
353/**
354 * katze_cell_renderer_combobox_text_new:
355 *
356 * Creates a new #KatzeCellRendererComboBoxText. Adjust how text is drawn using
357 * object properties. Object properties can be
358 * set globally (with g_object_set()). Also, with #GtkTreeViewColumn,
359 * you can bind a property to a value in a #GtkTreeModel. For example,
360 * you can bind the "text" property on the cell renderer to a string
361 * value in the model, thus rendering a different string in each row
362 * of the #GtkTreeView
363 *
364 * Return value: the new cell renderer
365 **/
366GtkCellRenderer *
367katze_cell_renderer_combobox_text_new (void)
368{
369 return g_object_new (KATZE_TYPE_CELL_RENDERER_COMBOBOX_TEXT, NULL);
370}
371
372static void
373set_text(KatzeCellRendererComboBoxText* cell,
374 GtkWidget* widget,
375 const gchar* repl)
376{
377 const gchar *text = NULL;
378 PangoAttrList* extra_attrs = NULL;
379 GtkWidget* pwidget = gtk_widget_get_parent (widget);
380 gboolean unfolded = FALSE;
381 KatzeCellRendererComboBoxTextPrivate *priv;
382
383 priv = KATZE_CELL_RENDERER_COMBOBOX_TEXT_GET_PRIVATE (cell);
384
385 if (GTK_IS_MENU_ITEM (pwidget))
386 {
387 GtkWidget* menu = gtk_widget_get_parent (pwidget);
388 GList* items;
389
390 if (menu
391 && (GTK_IS_MENU (menu))
392 && (items = gtk_container_get_children (GTK_CONTAINER (menu)))
393 && (GTK_WIDGET (items->data) == pwidget)
394 && (g_list_length (items) > 1)
395 && (GTK_IS_SEPARATOR_MENU_ITEM (g_list_next (items)->data)))
396 {
397 unfolded = TRUE;
398 }
399 }
400
401 if (unfolded)
402 {
403 text = priv->props[1].text;
404 extra_attrs = priv->props[1].extra_attrs;
405 }
406 else
407 {
408 text = priv->props[0].text;
409 extra_attrs = priv->props[0].extra_attrs;
410 }
411
412 if (!text)
413 {
414 text = g_strdup (repl ? repl : "");
415 }
416 else
417 {
418 GString* string = g_string_new ("");
419 const gchar* src = text;
420 const guint skip = sizeof ("[text]") - 1;
421 guint len;
422
423 while (0 != (len = strlen(src)))
424 {
425 const gchar* found = strstr (src, "[text]");
426
427 if (!found)
428 {
429 g_string_append (string, src);
430 src += len;
431 }
432 else
433 {
434 g_string_append_len (string, src, found-src);
435 if (repl)
436 g_string_append (string, repl);
437 src = found + skip;
438 }
439 }
440
441 text = g_string_free (string, FALSE);
442 }
443
444 g_object_set (G_OBJECT (cell),
445 "text", text,
446 "attributes", extra_attrs,
447 NULL);
448
449 g_free ((gpointer)text);
450}
451
452static void
453katze_cell_renderer_combobox_text_get_size (GtkCellRenderer *cell,
454 GtkWidget *widget,
455 GdkRectangle *cell_area,
456 gint *x_offset,
457 gint *y_offset,
458 gint *width,
459 gint *height)
460{
461 const gchar *text = NULL;
462
463 g_object_get (G_OBJECT (cell), "text", &text, NULL);
464
465 set_text (KATZE_CELL_RENDERER_COMBOBOX_TEXT (cell), widget, text);
466
467 _cell_renderer_get_size (cell,
468 widget, cell_area,
469 x_offset, y_offset, width, height);
470
471 g_object_set (G_OBJECT (cell), "text", text, NULL);
472 g_free ((gpointer)text);
473}
474
475static void
476#if GTK_CHECK_VERSION(3,0,0)
477katze_cell_renderer_combobox_text_render (GtkCellRenderer *cell,
478 cairo_t* cr,
479 GtkWidget *widget,
480 GdkRectangle *background_area,
481 GdkRectangle *cell_area,
482 GtkCellRendererState flags)
483#else
484katze_cell_renderer_combobox_text_render (GtkCellRenderer *cell,
485 GdkDrawable *window,
486 GtkWidget *widget,
487 GdkRectangle *background_area,
488 GdkRectangle *cell_area,
489 GdkRectangle *expose_area,
490 GtkCellRendererState flags)
491#endif
492{
493 const gchar *text = NULL;
494
495 g_object_get (G_OBJECT (cell), "text", &text, NULL);
496
497 set_text (KATZE_CELL_RENDERER_COMBOBOX_TEXT (cell), widget, text);
498
499#if GTK_CHECK_VERSION(3,0,0)
500 _cell_renderer_render (cell,
501 cr,
502 widget,
503 background_area,
504 cell_area,
505 flags);
506#else
507 _cell_renderer_render (cell,
508 window,
509 widget,
510 background_area,
511 cell_area,
512 expose_area,
513 flags);
514#endif
515
516 g_object_set (G_OBJECT (cell), "text", text, NULL);
517 g_free ((gpointer)text);
518}
0519
=== added file 'katze/katze-cellrenderercomboboxtext.h'
--- katze/katze-cellrenderercomboboxtext.h 1970-01-01 00:00:00 +0000
+++ katze/katze-cellrenderercomboboxtext.h 2013-07-27 21:58:26 +0000
@@ -0,0 +1,58 @@
1/*
2 Copyright (C) 2008-2013 Christian Dywan <christian@twotoasts.de>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 See the file COPYING for the full license text.
10*/
11
12#ifndef __KATZE_CELL_RENDERER_COMBOBOX_TEXT_H__
13#define __KATZE_CELL_RENDERER_COMBOBOX_TEXT_H__
14
15
16#include <gtk/gtk.h>
17
18#ifndef GSEAL
19#define GSEAL(String) String
20#endif
21
22G_BEGIN_DECLS
23
24
25#define KATZE_TYPE_CELL_RENDERER_COMBOBOX_TEXT (katze_cell_renderer_combobox_text_get_type ())
26#define KATZE_CELL_RENDERER_COMBOBOX_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), KATZE_TYPE_CELL_RENDERER_COMBOBOX_TEXT, KatzeCellRendererComboBoxText))
27#define KATZE_CELL_RENDERER_COMBOBOX_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), KATZE_TYPE_CELL_RENDERER_COMBOBOX_TEXT, KatzeCellRendererComboBoxTextClass))
28#define KATZE_IS_CELL_RENDERER_COMBOBOX_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), KATZE_TYPE_CELL_RENDERER_COMBOBOX_TEXT))
29#define KATZE_IS_CELL_RENDERER_COMBOBOX_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), KATZE_TYPE_CELL_RENDERER_COMBOBOX_TEXT))
30#define KATZE_CELL_RENDERER_COMBOBOX_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), KATZE_TYPE_CELL_RENDERER_COMBOBOX_TEXT, KatzeCellRendererComboBoxTextClass))
31
32typedef struct _KatzeCellRendererComboBoxText KatzeCellRendererComboBoxText;
33typedef struct _KatzeCellRendererComboBoxTextClass KatzeCellRendererComboBoxTextClass;
34
35struct _KatzeCellRendererComboBoxText
36{
37 GtkCellRendererText parent;
38
39 /*< private >*/
40};
41
42struct _KatzeCellRendererComboBoxTextClass
43{
44 GtkCellRendererTextClass parent_class;
45
46 /* Padding for future expansion */
47 void (*_gtk_reserved1) (void);
48 void (*_gtk_reserved2) (void);
49 void (*_gtk_reserved3) (void);
50 void (*_gtk_reserved4) (void);
51};
52
53GType katze_cell_renderer_combobox_text_get_type (void) G_GNUC_CONST;
54GtkCellRenderer *katze_cell_renderer_combobox_text_new (void);
55
56G_END_DECLS
57
58#endif /* __KATZE_CELL_RENDERER_COMBOBOX_TEXT_H__ */
059
=== modified file 'midori/midori-browser.c'
--- midori/midori-browser.c 2013-07-15 23:01:23 +0000
+++ midori/midori-browser.c 2013-07-27 21:58:26 +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 "katze-cellrenderercomboboxtext.h"
2930
30#include "marshal.h"31#include "marshal.h"
3132
@@ -828,52 +829,217 @@
828 }829 }
829}830}
830831
832static gboolean
833midori_bookmark_folder_button_reach_parent (GtkTreeModel* model, GtkTreeIter *iter, gint64 parentid)
834{
835 do
836 {
837 gint64 id;
838
839 gtk_tree_model_get (model, iter, 1, &id, -1);
840
841 if (parentid == id)
842 return TRUE;
843
844 if (gtk_tree_model_iter_has_child (model, iter))
845 {
846 GtkTreeIter child;
847 gtk_tree_model_iter_children (model, &child, iter);
848 if (midori_bookmark_folder_button_reach_parent (model, &child, parentid))
849 {
850 *iter = child;
851 return TRUE;
852 }
853 }
854 }
855 while (gtk_tree_model_iter_next (model, iter));
856
857 return FALSE;
858}
859
860typedef struct _FolderEntry
861{
862 const gchar *title;
863 gint64 id;
864 gint64 parentid;
865} FolderEntry;
866
867static void
868midori_bookmark_folder_free_folder_entry (FolderEntry* folder)
869{
870 g_free ((gpointer)folder->title);
871}
872
831static GtkWidget*873static GtkWidget*
832midori_bookmark_folder_button_new (KatzeArray* array,874midori_bookmark_folder_button_new (KatzeArray* array,
833 gint64 selected,875 gint64 selected_parentid)
834 gint64 parentid)
835{876{
836 GtkListStore* model;877 GtkTreeStore* model;
837 GtkWidget* combo;878 GtkWidget* combo;
838 GtkCellRenderer* renderer;879 GtkCellRenderer* renderer;
839 guint n;880 guint n;
840 sqlite3* db;881 sqlite3* db;
841 sqlite3_stmt* statement;882 sqlite3_stmt* statement;
842 gint result;883 gint result;
843 const gchar* sqlcmd = "SELECT title, id FROM bookmarks WHERE uri='' ORDER BY title ASC";884 const gchar* sqlcmd = "SELECT title, id, parentid FROM bookmarks WHERE uri='' ORDER BY parentid, title ASC";
844885 gint64 current_parentid;
845 model = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT64);886 GtkTreeIter tree_iter;
846 combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (model));887 GtkTreeIter stock_parent_iter;
847 renderer = gtk_cell_renderer_text_new ();888 GtkTreeIter* parent_iter;
848 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);889 GList *folders = NULL;
849 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), renderer, "text", 0);
850 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), renderer, "ellipsize", 1);
851 gtk_list_store_insert_with_values (model, NULL, G_MAXINT,
852 0, _("Bookmarks"), 1, PANGO_ELLIPSIZE_END, 2, (gint64)0, -1);
853 gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
854890
855 db = g_object_get_data (G_OBJECT (array), "db");891 db = g_object_get_data (G_OBJECT (array), "db");
856 g_return_val_if_fail (db != NULL, NULL);892 g_return_val_if_fail (db != NULL, NULL);
893
894 /* folder combo box model content:
895 ** 0: title
896 ** 1: id
897 */
898 model = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT64);
899 combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (model));
900
901 /* setup combo layout
902 ** 0: a folder icon
903 ** 1: the folder name
904 */
905
906 gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo));
907
908 renderer = gtk_cell_renderer_pixbuf_new ();
909 g_object_set (G_OBJECT (renderer),
910 "stock-id", GTK_STOCK_DIRECTORY,
911 "stock-size", GTK_ICON_SIZE_MENU,
912 NULL);
913 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, FALSE);
914
915 renderer = katze_cell_renderer_combobox_text_new ();
916 g_object_set (G_OBJECT (renderer),
917 "width-chars", 40, /* FIXME: figure out a way to define an acceptable string length */
918 "ellipsize", PANGO_ELLIPSIZE_END,
919 "unfolded-text", _("Select [text]"),
920 NULL);
921 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
922 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), renderer, "text", 0);
923
924 /* read the folders list from the database */
925 /* FIXME: this should be a service of midori/midori-bookmarks-db */
926
927 if ((result = sqlite3_prepare_v2 (db, sqlcmd, -1, &statement, NULL)) == SQLITE_OK)
928 {
929 while ((result = sqlite3_step (statement)) == SQLITE_ROW)
930 {
931 FolderEntry* folder = g_new (FolderEntry, 1);
932
933 folder->title = g_strdup ((const gchar*)sqlite3_column_text (statement, 0));
934 folder->id = sqlite3_column_int64 (statement, 1);
935 folder->parentid = sqlite3_column_int64 (statement, 2);
936
937 folders = g_list_append (folders, folder);
938 }
939
940 sqlite3_clear_bindings (statement);
941 sqlite3_reset (statement);
942 }
943
944 /* populate the combo box */
945 /* FIXME: here we should have the root bookmark array's name and id, not hard encoded values */
946
947 gtk_tree_store_insert_with_values (model, &tree_iter, NULL, G_MAXINT,
948 0, _("Bookmarks"), 1, (gint64)0, -1);
949 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &tree_iter);
950
951 current_parentid = 0;
952 parent_iter = NULL;
857 n = 1;953 n = 1;
858 if ((result = sqlite3_prepare_v2 (db, sqlcmd, -1, &statement, NULL)) == SQLITE_OK)954 while (g_list_first (folders))
859 while ((result = sqlite3_step (statement)) == SQLITE_ROW)
860 {955 {
861 const unsigned char* name = sqlite3_column_text (statement, 0);956 gboolean something_done = FALSE;
862 gint64 id = sqlite3_column_int64 (statement, 1);957 GList* list_iter = g_list_first (folders);
863958
864 /* do not show the folder itself */959 do
865 if (id != selected)
866 {960 {
867 gtk_list_store_insert_with_values (model, NULL, G_MAXINT,961 FolderEntry* folder = list_iter->data;
868 0, name, 1, PANGO_ELLIPSIZE_END, 2, id, -1);962 const gchar* title = folder->title;
869963 gint64 id = folder->id;
870 if (id == parentid)964 gint64 parentid = folder->parentid;
871 gtk_combo_box_set_active (GTK_COMBO_BOX (combo), n);965
966 if (parentid != current_parentid) /* optimize case of sub-folders of the same parent */
967 {
968 if (!parentid)
969 {
970 /* folder's parent is the stree store root */
971
972 current_parentid = 0;
973 parent_iter = NULL;
974 }
975 else if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &tree_iter))
976 {
977 if (midori_bookmark_folder_button_reach_parent (
978 GTK_TREE_MODEL (model), &tree_iter, parentid))
979 {
980 /* folder's parent found in the tree store */
981
982 current_parentid = parentid;
983 stock_parent_iter = tree_iter;
984 parent_iter = &stock_parent_iter;
985 }
986 else
987 {
988 /* folder's parent not found, skip it */
989
990 list_iter = g_list_next (list_iter);
991 continue;
992 }
993 }
994 else
995 g_assert_not_reached ();
996 }
997
998 /* insert folder in the tree store and remove it from the folders list */
999
1000 gtk_tree_store_insert_with_values (model, &tree_iter, parent_iter, G_MAXINT,
1001 0, title, 1, id, -1);
1002
1003 if (id == selected_parentid)
1004 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &tree_iter);
1005
872 n++;1006 n++;
873 }1007
874 }1008 something_done = TRUE;
1009
1010 g_free ((gpointer)title);
1011 folders = g_list_delete_link (folders, list_iter);
1012
1013 list_iter = g_list_first (folders);
1014 }
1015 while (list_iter);
1016
1017 if (!something_done) /* avoid infinite loop in case of orphan folders */
1018 break;
1019 }
1020
1021 if (g_list_first (folders))
1022 {
1023 GList* iter;
1024 g_printerr ("midori_bookmark_folder_button_new: orphan folder(s) detected in bookmarks db\n");
1025
1026 for (iter = g_list_first (folders) ; iter ; iter = g_list_next (iter))
1027 {
1028 FolderEntry* folder = iter->data;
1029 const gchar* title = folder->title;
1030 gint64 id = folder->id;
1031 gint64 parentid = folder->parentid;
1032
1033 g_printerr (" id=%" G_GINT64_FORMAT ", parentid=%" G_GINT64_FORMAT ", title=%s\n",
1034 id, parentid, title);
1035 }
1036
1037 g_list_free_full (folders, (GDestroyNotify)midori_bookmark_folder_free_folder_entry);
1038 }
1039
875 if (n < 2)1040 if (n < 2)
876 gtk_widget_set_sensitive (combo, FALSE);1041 gtk_widget_set_sensitive (combo, FALSE);
1042
877 return combo;1043 return combo;
878}1044}
8791045
@@ -887,14 +1053,8 @@
8871053
888 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter))1054 if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter))
889 {1055 {
890 gchar* selected = NULL;
891 GtkTreeModel* model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));1056 GtkTreeModel* model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
892 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &selected, 2, &id, -1);1057 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 1, &id, -1);
893
894 if (g_str_equal (selected, _("Bookmarks")))
895 id = 0;
896
897 g_free (selected);
898 }1058 }
8991059
900 return id;1060 return id;
@@ -1021,7 +1181,6 @@
1021 }1181 }
10221182
1023 combo_folder = midori_bookmark_folder_button_new (browser->bookmarks,1183 combo_folder = midori_bookmark_folder_button_new (browser->bookmarks,
1024 katze_item_get_meta_integer (bookmark, "id"),
1025 katze_item_get_meta_integer (bookmark, "parentid"));1184 katze_item_get_meta_integer (bookmark, "parentid"));
1026 gtk_box_pack_start (GTK_BOX (vbox), combo_folder, FALSE, FALSE, 0);1185 gtk_box_pack_start (GTK_BOX (vbox), combo_folder, FALSE, FALSE, 0);
10271186
@@ -4460,8 +4619,7 @@
4460 gtk_container_add (GTK_CONTAINER (content_area), hbox);4619 gtk_container_add (GTK_CONTAINER (content_area), hbox);
4461 gtk_widget_show_all (hbox);4620 gtk_widget_show_all (hbox);
44624621
4463 combobox_folder = midori_bookmark_folder_button_new (browser->bookmarks,4622 combobox_folder = midori_bookmark_folder_button_new (browser->bookmarks, 0);
4464 0, 0);
4465 gtk_container_add (GTK_CONTAINER (content_area), combobox_folder);4623 gtk_container_add (GTK_CONTAINER (content_area), combobox_folder);
44664624
4467 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);4625 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);

Subscribers

People subscribed via source and target branches

to all changes: