Code

OCAL. Fix for Bug #638844 (Errors printed to console if openclipart search fails).
[inkscape.git] / src / libgdl / gdl-dock-notebook.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * This file is part of the GNOME Devtools Libraries.
4  *
5  * Copyright (C) 2002 Gustavo Giráldez <gustavo.giraldez@gmx.net>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include "gdl-i18n.h"
27 #include "gdl-switcher.h"
29 #include "gdl-tools.h"
30 #include "gdl-dock-notebook.h"
31 #include "gdl-dock-tablabel.h"
34 /* Private prototypes */
36 static void  gdl_dock_notebook_class_init    (GdlDockNotebookClass *klass);
37 static void  gdl_dock_notebook_instance_init (GdlDockNotebook      *notebook);
38 static void  gdl_dock_notebook_set_property  (GObject              *object,
39                                               guint                 prop_id,
40                                               const GValue         *value,
41                                               GParamSpec           *pspec);
42 static void  gdl_dock_notebook_get_property  (GObject              *object,
43                                               guint                 prop_id,
44                                               GValue               *value,
45                                               GParamSpec           *pspec);
47 static void  gdl_dock_notebook_destroy       (GtkObject    *object);
49 static void  gdl_dock_notebook_add           (GtkContainer *container,
50                                               GtkWidget    *widget);
51 static void  gdl_dock_notebook_forall        (GtkContainer *container,
52                                               gboolean      include_internals,
53                                               GtkCallback   callback,
54                                               gpointer      callback_data);
55 static GType gdl_dock_notebook_child_type    (GtkContainer *container);
57 static void  gdl_dock_notebook_dock          (GdlDockObject    *object,
58                                               GdlDockObject    *requestor,
59                                               GdlDockPlacement  position,
60                                               GValue           *other_data);
62 static void  gdl_dock_notebook_switch_page_cb  (GtkNotebook     *nb,
63                                                 GtkNotebookPage *page,
64                                                 gint             page_num,
65                                                 gpointer         data);
67 static void  gdl_dock_notebook_set_orientation (GdlDockItem     *item,
68                                                 GtkOrientation   orientation);
69                                                
70 static gboolean gdl_dock_notebook_child_placement (GdlDockObject    *object,
71                                                    GdlDockObject    *child,
72                                                    GdlDockPlacement *placement);
74 static void     gdl_dock_notebook_present         (GdlDockObject    *object,
75                                                    GdlDockObject    *child);
77 static gboolean gdl_dock_notebook_reorder         (GdlDockObject    *object,
78                                                    GdlDockObject    *requestor,
79                                                    GdlDockPlacement  new_position,
80                                                    GValue           *other_data);
83 /* Class variables and definitions */
85 enum {
86     PROP_0,
87     PROP_PAGE
88 };
91 /* ----- Private functions ----- */
93 GDL_CLASS_BOILERPLATE (GdlDockNotebook, gdl_dock_notebook, GdlDockItem, GDL_TYPE_DOCK_ITEM) ;
95 static void
96 gdl_dock_notebook_class_init (GdlDockNotebookClass *klass)
97 {
98     static gboolean style_initialized = FALSE;
99     
100     GObjectClass       *g_object_class;
101     GtkObjectClass     *gtk_object_class;
102     GtkWidgetClass     *widget_class;
103     GtkContainerClass  *container_class;
104     GdlDockObjectClass *object_class;
105     GdlDockItemClass   *item_class;
107     g_object_class = G_OBJECT_CLASS (klass);
108     gtk_object_class = GTK_OBJECT_CLASS (klass);
109     widget_class = GTK_WIDGET_CLASS (klass);
110     container_class = GTK_CONTAINER_CLASS (klass);
111     object_class = GDL_DOCK_OBJECT_CLASS (klass);
112     item_class = GDL_DOCK_ITEM_CLASS (klass);
114     g_object_class->set_property = gdl_dock_notebook_set_property;
115     g_object_class->get_property = gdl_dock_notebook_get_property;
116     
117     gtk_object_class->destroy = gdl_dock_notebook_destroy;
119     container_class->add = gdl_dock_notebook_add;
120     container_class->forall = gdl_dock_notebook_forall;
121     container_class->child_type = gdl_dock_notebook_child_type;
122     
123     object_class->is_compound = TRUE;
124     object_class->dock = gdl_dock_notebook_dock;
125     object_class->child_placement = gdl_dock_notebook_child_placement;
126     object_class->present = gdl_dock_notebook_present;
127     object_class->reorder = gdl_dock_notebook_reorder;
128     
129     item_class->has_grip = FALSE;
130     item_class->set_orientation = gdl_dock_notebook_set_orientation;    
131     
132     g_object_class_install_property (
133         g_object_class, PROP_PAGE,
134         g_param_spec_int ("page", _("Page"),
135                           _("The index of the current page"),
136                           0, G_MAXINT,
137                           0,
138                           G_PARAM_READWRITE |
139                           GDL_DOCK_PARAM_EXPORT | GDL_DOCK_PARAM_AFTER));
141     if (!style_initialized) {
142         style_initialized = TRUE;
143         
144         gtk_rc_parse_string (
145             "style \"gdl-dock-notebook-default\" {\n"
146             "xthickness = 2\n"
147             "ythickness = 2\n"
148             "}\n"
149             "widget_class \"*.GtkNotebook.GdlDockItem\" "
150             "style : gtk \"gdl-dock-notebook-default\"\n");
151     }
154 static void 
155 gdl_dock_notebook_notify_cb (GObject    *g_object,
156                              GParamSpec *pspec,
157                              gpointer    user_data) 
159     g_return_if_fail (user_data != NULL && GDL_IS_DOCK_NOTEBOOK (user_data));
161     /* chain the notify signal */
162     g_object_notify (G_OBJECT (user_data), pspec->name);
165 static gboolean 
166 gdl_dock_notebook_button_cb (GtkWidget      *widget,
167                              GdkEventButton *event,
168                              gpointer        user_data)
170     if (event->type == GDK_BUTTON_PRESS)
171         GDL_DOCK_ITEM_SET_FLAGS (user_data, GDL_DOCK_USER_ACTION);
172     else
173         GDL_DOCK_ITEM_UNSET_FLAGS (user_data, GDL_DOCK_USER_ACTION);
175     return FALSE;
177     
178 static void
179 gdl_dock_notebook_instance_init (GdlDockNotebook *notebook)
181     GdlDockItem *item;
183     item = GDL_DOCK_ITEM (notebook);
185     /* create the container notebook */
186     item->child = gdl_switcher_new ();
187     gtk_widget_set_parent (item->child, GTK_WIDGET (notebook));
188     gtk_notebook_set_tab_pos (GTK_NOTEBOOK (item->child), GTK_POS_BOTTOM);
189     g_signal_connect (item->child, "switch-page",
190                       (GCallback) gdl_dock_notebook_switch_page_cb, (gpointer) item);
191     g_signal_connect (item->child, "notify::page",
192                       (GCallback) gdl_dock_notebook_notify_cb, (gpointer) item);
193     g_signal_connect (item->child, "button-press-event",
194                       (GCallback) gdl_dock_notebook_button_cb, (gpointer) item);
195     g_signal_connect (item->child, "button-release-event",
196                       (GCallback) gdl_dock_notebook_button_cb, (gpointer) item);
197     gtk_notebook_set_scrollable (GTK_NOTEBOOK (item->child), TRUE);
198     gtk_widget_show (item->child);
201 static void 
202 gdl_dock_notebook_set_property (GObject      *object,
203                                 guint         prop_id,
204                                 const GValue *value,
205                                 GParamSpec   *pspec)
207     GdlDockItem *item = GDL_DOCK_ITEM (object);
209     switch (prop_id) {
210         case PROP_PAGE:
211             if (item->child && GTK_IS_NOTEBOOK (item->child)) {
212                 gtk_notebook_set_current_page (GTK_NOTEBOOK (item->child),
213                                                g_value_get_int (value));
214             }
215             
216             break;
217         default:
218             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
219             break;
220     }
223 static void 
224 gdl_dock_notebook_get_property (GObject    *object,
225                                 guint       prop_id,
226                                 GValue     *value,
227                                 GParamSpec *pspec)
229     GdlDockItem *item = GDL_DOCK_ITEM (object);
231     switch (prop_id) {
232         case PROP_PAGE:
233             if (item->child && GTK_IS_NOTEBOOK (item->child)) {
234                 g_value_set_int (value, gtk_notebook_get_current_page
235                                  (GTK_NOTEBOOK (item->child)));
236             }
237             
238             break;
239         default:
240             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
241             break;
242     }
246 static void
247 gdl_dock_notebook_destroy (GtkObject *object)
249     GdlDockItem *item = GDL_DOCK_ITEM (object);
251     /* we need to call the virtual first, since in GdlDockDestroy our
252        children dock objects are detached */
253     GDL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
255     /* after that we can remove the GtkNotebook */
256     if (item->child) {
257         gtk_widget_unparent (item->child);
258         item->child = NULL;
259     };
262 static void
263 gdl_dock_notebook_switch_page_cb (GtkNotebook     *nb,
264                                   GtkNotebookPage *page,
265                                   gint             page_num,
266                                   gpointer         data)
268     GdlDockNotebook *notebook;
269     GtkWidget       *tablabel;
270     
271     notebook = GDL_DOCK_NOTEBOOK (data);
273     /* deactivate old tablabel */
274     if (nb->cur_page) {
275         tablabel = gtk_notebook_get_tab_label (
276             nb, gtk_notebook_get_nth_page (
277                 nb, gtk_notebook_get_current_page (nb)));
278         if (tablabel && GDL_IS_DOCK_TABLABEL (tablabel))
279             gdl_dock_tablabel_deactivate (GDL_DOCK_TABLABEL (tablabel));
280     };
282     /* activate new label */
283     tablabel = gtk_notebook_get_tab_label (
284         nb, gtk_notebook_get_nth_page (nb, page_num));
285     if (tablabel && GDL_IS_DOCK_TABLABEL (tablabel))
286         gdl_dock_tablabel_activate (GDL_DOCK_TABLABEL (tablabel));
288     if (GDL_DOCK_ITEM_USER_ACTION (notebook) &&
289         GDL_DOCK_OBJECT (notebook)->master)
290         g_signal_emit_by_name (GDL_DOCK_OBJECT (notebook)->master,
291                                "layout-changed");
294 static void
295 gdl_dock_notebook_add (GtkContainer *container,
296                        GtkWidget    *widget)
298     g_return_if_fail (container != NULL && widget != NULL);
299     g_return_if_fail (GDL_IS_DOCK_NOTEBOOK (container));
300     g_return_if_fail (GDL_IS_DOCK_ITEM (widget));
302     gdl_dock_object_dock (GDL_DOCK_OBJECT (container),
303                           GDL_DOCK_OBJECT (widget),
304                           GDL_DOCK_CENTER,
305                           NULL);
308 static void
309 gdl_dock_notebook_forall (GtkContainer *container,
310                           gboolean      include_internals,
311                           GtkCallback   callback,
312                           gpointer      callback_data)
314     GdlDockItem *item;
316     g_return_if_fail (container != NULL);
317     g_return_if_fail (GDL_IS_DOCK_NOTEBOOK (container));
318     g_return_if_fail (callback != NULL);
320     if (include_internals) {
321         /* use GdlDockItem's forall */
322         GDL_CALL_PARENT (GTK_CONTAINER_CLASS, forall, 
323                            (container, include_internals, callback, callback_data));
324     }
325     else {
326         item = GDL_DOCK_ITEM (container);
327         if (item->child)
328             gtk_container_foreach (GTK_CONTAINER (item->child), callback, callback_data);
329     }
332 static GType
333 gdl_dock_notebook_child_type (GtkContainer *container)
335     return GDL_TYPE_DOCK_ITEM;
337     
338 static void
339 gdl_dock_notebook_dock_child (GdlDockObject *requestor,
340                               gpointer       user_data)
342     struct {
343         GdlDockObject    *object;
344         GdlDockPlacement  position;
345         GValue           *other_data;
346     } *data = user_data;
348     gdl_dock_object_dock (data->object, requestor, data->position, data->other_data);
351 static void
352 gdl_dock_notebook_dock (GdlDockObject    *object,
353                         GdlDockObject    *requestor,
354                         GdlDockPlacement  position,
355                         GValue           *other_data)
357     g_return_if_fail (GDL_IS_DOCK_NOTEBOOK (object));
358     g_return_if_fail (GDL_IS_DOCK_ITEM (requestor));
360     /* we only add support for GDL_DOCK_CENTER docking strategy here... for the rest
361        use our parent class' method */
362     if (position == GDL_DOCK_CENTER) {
363         /* we can only dock simple (not compound) items */
364         if (gdl_dock_object_is_compound (requestor)) {
365             struct {
366                 GdlDockObject    *object;
367                 GdlDockPlacement  position;
368                 GValue           *other_data;
369             } data;
371             gdl_dock_object_freeze (requestor);
372             
373             data.object = object;
374             data.position = position;
375             data.other_data = other_data;
376              
377             gtk_container_foreach (GTK_CONTAINER (requestor),
378                                    (GtkCallback) gdl_dock_notebook_dock_child, &data);
380             gdl_dock_object_thaw (requestor);
381         }
382         else {
383             GdlDockItem *item = GDL_DOCK_ITEM (object);
384             GdlDockItem *requestor_item = GDL_DOCK_ITEM (requestor);
385             gchar       *long_name, *stock_id;
386             GdkPixbuf   *pixbuf_icon;
387             GtkWidget   *label;
388             gint         position = -1;
389             
390             g_object_get (requestor_item, "long-name", &long_name,
391                           "stock-id", &stock_id, "pixbuf-icon", &pixbuf_icon, NULL);
392             label = gdl_dock_item_get_tablabel (requestor_item);
393             if (!label) {
394                 label = gtk_label_new (long_name);
395                 gdl_dock_item_set_tablabel (requestor_item, label);
396             }
397 #if 0
398             if (GDL_IS_DOCK_TABLABEL (label)) {
399                 gdl_dock_tablabel_deactivate (GDL_DOCK_TABLABEL (label));
400                 /* hide the item grip, as we will use the tablabel's */
401                 gdl_dock_item_hide_grip (requestor_item);
402             }
403 #endif
405             if (other_data && G_VALUE_HOLDS (other_data, G_TYPE_INT))
406                 position = g_value_get_int (other_data);
407             
408             position = gdl_switcher_insert_page (GDL_SWITCHER (item->child), 
409                                                  GTK_WIDGET (requestor), label,
410                                                  long_name, long_name,
411                                                  stock_id, pixbuf_icon, position);
412             
413             GDL_DOCK_OBJECT_SET_FLAGS (requestor, GDL_DOCK_ATTACHED);
414             
415             /* Set current page to the newly docked widget. set current page
416              * really doesn't work if the page widget is not shown
417              */
418             gtk_widget_show (GTK_WIDGET (requestor));
419             gtk_notebook_set_current_page (GTK_NOTEBOOK (item->child),
420                                            position);
421             g_free (long_name);
422             g_free (stock_id);
423         }
424     }
425     else
426         GDL_CALL_PARENT (GDL_DOCK_OBJECT_CLASS, dock,
427                            (object, requestor, position, other_data));
430 static void
431 gdl_dock_notebook_set_orientation (GdlDockItem    *item,
432                                    GtkOrientation  orientation)
434     if (item->child && GTK_IS_NOTEBOOK (item->child)) {
435         if (orientation == GTK_ORIENTATION_HORIZONTAL)
436             gtk_notebook_set_tab_pos (GTK_NOTEBOOK (item->child), GTK_POS_TOP);
437         else
438             gtk_notebook_set_tab_pos (GTK_NOTEBOOK (item->child), GTK_POS_LEFT);
439     }
441     GDL_CALL_PARENT (GDL_DOCK_ITEM_CLASS, set_orientation, (item, orientation));
444 static gboolean 
445 gdl_dock_notebook_child_placement (GdlDockObject    *object,
446                                    GdlDockObject    *child,
447                                    GdlDockPlacement *placement)
449     GdlDockItem      *item = GDL_DOCK_ITEM (object);
450     GdlDockPlacement  pos = GDL_DOCK_NONE;
451     
452     if (item->child) {
453         GList *children, *l;
455         children = gtk_container_get_children (GTK_CONTAINER (item->child));
456         for (l = children; l; l = l->next) {
457             if (l->data == (gpointer) child) {
458                 pos = GDL_DOCK_CENTER;
459                 break;
460             }
461         }
462         g_list_free (children);
463     }
465     if (pos != GDL_DOCK_NONE) {
466         if (placement)
467             *placement = pos;
468         return TRUE;
469     }
470     else
471         return FALSE;
474 static void
475 gdl_dock_notebook_present (GdlDockObject *object,
476                            GdlDockObject *child)
478     GdlDockItem *item = GDL_DOCK_ITEM (object);
479     int i;
480     
481     i = gtk_notebook_page_num (GTK_NOTEBOOK (item->child),
482                                GTK_WIDGET (child));
483     if (i >= 0)
484         gtk_notebook_set_current_page (GTK_NOTEBOOK (item->child), i);
486     GDL_CALL_PARENT (GDL_DOCK_OBJECT_CLASS, present, (object, child));
489 static gboolean 
490 gdl_dock_notebook_reorder (GdlDockObject    *object,
491                            GdlDockObject    *requestor,
492                            GdlDockPlacement  new_position,
493                            GValue           *other_data)
495     GdlDockItem *item = GDL_DOCK_ITEM (object);
496     gint         current_position, new_pos = -1;
497     gboolean     handled = FALSE;
498     
499     if (item->child && new_position == GDL_DOCK_CENTER) {
500         current_position = gtk_notebook_page_num (GTK_NOTEBOOK (item->child),
501                                                   GTK_WIDGET (requestor));
502         if (current_position >= 0) {
503             handled = TRUE;
504     
505             if (other_data && G_VALUE_HOLDS (other_data, G_TYPE_INT))
506                 new_pos = g_value_get_int (other_data);
507             
508             gtk_notebook_reorder_child (GTK_NOTEBOOK (item->child), 
509                                         GTK_WIDGET (requestor),
510                                         new_pos);
511         }
512     }
513     return handled;
516 /* ----- Public interface ----- */
518 GtkWidget *
519 gdl_dock_notebook_new (void)
521     GdlDockNotebook *notebook;
523     notebook = GDL_DOCK_NOTEBOOK (g_object_new (GDL_TYPE_DOCK_NOTEBOOK, NULL));
524     GDL_DOCK_OBJECT_UNSET_FLAGS (notebook, GDL_DOCK_AUTOMATIC);
525     
526     return GTK_WIDGET (notebook);