/* Gtk+ User Interface Builder
* Copyright (C) 1998 Damon Chaplin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* Glade only shows Bonobo controls which have a 'glade:show' attribute set
* to TRUE, e.g. with this in their .server file:
*
*
*
*/
#include
#include
#include
#include
#include
#include
#include
#include "../gb.h"
#include "../palette.h"
#include
/* Include the 21x21 icon pixmap for this widget, to be used in the palette */
#include "../graphics/gnome-control.xpm"
/*
* This is the GbWidget struct for this widget (see ../gbwidget.h).
* It is initialized in the init() function at the end of this file
*/
static GbWidget gbwidget;
/* This is the key we use to store a pointer to the bonobo widget's property
bag. */
static gchar *GladePropertyBagKey = "GladePropertyBagKey";
/* This is the Moniker property which stores the type of control. It is saved
in the XML. */
const gchar *Moniker = "BonoboWidget::moniker";
static GbWidget *control_get_gb_widget (const char *obj_id);
/****************************************************************************
* This is the dummy GbWidget we put in the palette. It only contains a
* new() function to create Bonobo controls. We create a GbWidget for each
* type of control when needed, and it is that that contains functions to
* create/get/set properties.
****************************************************************************/
/* Columns in the GtkTreeView for selecting the type of control. */
enum {
COL_OBJID,
COL_DESC,
COL_LAST
};
static GtkWidget *
control_create (GbWidgetNewData * data, char *obj_id, Bonobo_UIContainer uic)
{
GtkWidget *widget;
BonoboControlFrame *cf;
Bonobo_PropertyBag pb;
g_return_val_if_fail (obj_id != NULL, NULL);
widget = bonobo_widget_new_control (obj_id, uic);
g_return_val_if_fail (widget != NULL, NULL);
cf = bonobo_widget_get_control_frame (BONOBO_WIDGET (widget));
if (!cf) {
g_warning ("Control has no frame!");
gtk_widget_destroy (widget);
return NULL;
}
pb = bonobo_control_frame_get_control_property_bag (cf, NULL);
gtk_object_set_data (GTK_OBJECT (widget), GladePropertyBagKey, pb);
gtk_object_set_data (GTK_OBJECT (widget), Moniker, g_strdup (obj_id));
/* Make sure the GbWidget for this control is created & registered,
and set the real GbWidget for this control. */
data->widget_data->gbwidget = control_get_gb_widget (obj_id);
return widget;
}
static Bonobo_PropertyBag
control_get_pb (GtkWidget *widget)
{
return gtk_object_get_data (GTK_OBJECT (widget),
GladePropertyBagKey);
}
static Bonobo_UIContainer
widget_get_uic (GtkWidget *widget)
{
GtkWidget *top;
top = gtk_widget_get_toplevel (widget);
if (!BONOBO_IS_WINDOW (top))
return CORBA_OBJECT_NIL;
/* FIXME: Should we unref this somewhere? */
return (Bonobo_UIContainer) BONOBO_OBJREF (bonobo_window_get_ui_container (BONOBO_WINDOW (top)));
}
static void
on_control_dialog_ok (GtkWidget *widget,
GbWidgetNewData *data)
{
GtkTreeView *view;
GtkTreeModel *model;
GtkTreeIter iter;
GtkWidget *dialog;
GtkTreeSelection *selection;
char *moniker;
GtkWidget *new_widget;
dialog = gtk_widget_get_toplevel (widget);
view = g_object_get_data (G_OBJECT (dialog), "tree_view");
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
gtk_tree_selection_get_selected (selection, &model, &iter);
gtk_tree_model_get (model, &iter, COL_OBJID, &moniker, -1);
new_widget = control_create (data, moniker, widget_get_uic (data->parent));
if (new_widget)
{
gb_widget_initialize (new_widget, data);
data->callback (new_widget, data);
}
else
{
glade_util_show_message_box (_("Couldn't create the Bonobo control"),
NULL);
}
gtk_widget_destroy (dialog);
}
static void
on_control_dialog_destroy (GtkWidget *widget,
GbWidgetNewData *data)
{
gb_widget_free_new_data (data);
gtk_grab_remove (widget);
}
static GtkListStore *
do_query (void)
{
GtkListStore *store;
Bonobo_ServerInfoList *servers;
#if 0
/* This is the old query, but too many components are not generally useful
and cause problems, so we are changing to an 'opt-in' query, where
we only include components that have a 'glade:show' property set to TRUE.
*/
const char *query = "repo_ids.has('IDL:Bonobo/Control:1.0') AND NOT "
"repo_ids.has('IDL:GNOME/Vertigo/PanelAppletShell:1.0')";
#else
const char *query = "glade:show";
#endif
char *sort[] = { "description", NULL };
CORBA_Environment ev;
int i;
Bonobo_ServerInfo *serverinfo;
const char *desc;
GtkTreeIter iter;
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
CORBA_exception_init (&ev);
servers = bonobo_activation_query (query, sort, &ev);
if (BONOBO_EX (&ev)) {
g_warning ("query failed: %s\n", ev._id);
CORBA_exception_free (&ev);
return store;
}
CORBA_exception_free (&ev);
#if 0
g_print ("got %d servers.\n", servers ? servers->_length : 0);
#endif
for (i = 0; i < servers->_length; i++) {
serverinfo = &servers->_buffer[i];
desc = bonobo_server_info_prop_lookup (serverinfo, "description", NULL);
if (!desc)
desc = bonobo_server_info_prop_lookup (serverinfo, "name", NULL);
if (!desc)
desc = serverinfo->iid;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COL_OBJID, serverinfo->iid,
COL_DESC, desc,
-1);
}
CORBA_free (servers);
return store;
}
static void
on_list_selection_changed (GtkTreeSelection *selection, GtkDialog *dialog)
{
gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_OK,
gtk_tree_selection_get_selected (selection, NULL, NULL));
}
static void
show_control_dialog (GbWidgetNewData *data)
{
GtkWidget *dialog, *vbox, *label, *list, *scroll;
GtkListStore *store;
GtkCellRenderer *ren;
dialog = glade_util_create_dialog (_("New Bonobo Control"), data->parent,
GTK_SIGNAL_FUNC (on_control_dialog_ok),
data, &vbox);
g_object_set (G_OBJECT (dialog),
"resizable", TRUE,
"default-width", 400,
"default-height", 300,
NULL);
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
GTK_RESPONSE_OK, FALSE);
g_signal_connect (dialog, "destroy",
G_CALLBACK (on_control_dialog_destroy), data);
label = gtk_label_new (_("Select a Bonobo Control"));
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
scroll = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
"hadjustment", NULL,
"vadjustment", NULL,
"shadow-type", GTK_SHADOW_ETCHED_IN,
"vscrollbar-policy", GTK_POLICY_AUTOMATIC,
"hscrollbar-policy", GTK_POLICY_AUTOMATIC,
NULL);
gtk_box_pack_start (GTK_BOX (vbox), scroll, TRUE, TRUE, 0);
store = do_query ();
list = g_object_new (GTK_TYPE_TREE_VIEW,
"model", store,
"headers-visible", FALSE,
NULL);
g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (list)),
"changed",
G_CALLBACK (on_list_selection_changed), dialog);
g_object_unref (store);
ren = gtk_cell_renderer_text_new ();
#if 0
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (list),
-1, _("OAFIID"), ren,
"text", COL_OBJID,
NULL);
#endif
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (list),
-1, _("Description"), ren,
"text", COL_DESC,
NULL);
gtk_container_add (GTK_CONTAINER (scroll), list);
g_object_set_data (G_OBJECT (dialog), "tree_view", list);
gtk_widget_show_all (dialog);
gtk_grab_add (dialog);
}
static GtkWidget *
gb_bonobo_control_new (GbWidgetNewData * data)
{
GtkWidget *new_widget;
if (data->action == GB_LOADING) {
char *moniker;
moniker = load_string (data->loading_data, Moniker);
new_widget = control_create (data, moniker, widget_get_uic (data->parent));
return new_widget;
} else {
show_control_dialog (data);
return NULL;
}
}
/*
* Initializes the GbWidget structure.
*/
GbWidget *
gb_bonobo_control_init ()
{
/* Initialise the GTK type */
volatile GtkType type;
type = BONOBO_TYPE_WIDGET;
gb_widget_init_struct (&gbwidget);
gbwidget.pixmap_struct = gnome_control_xpm;
gbwidget.tooltip = _("Bonobo Control");
gbwidget.gb_widget_new = gb_bonobo_control_new;
return &gbwidget;
}
/****************************************************************************
* This is the GbWidget that will be created for each type of control.
****************************************************************************/
/* We use the moniker to ensure the property names are unique in the property
editor. */
static char *
create_prop_name (const char *moniker, const char *txt)
{
return g_strconcat (moniker, "::", txt, NULL);
}
/*
* Creates the components needed to edit the extra properties of this widget.
*/
static void
gb_bonobo_control_create_properties (GtkWidget * widget, GbWidgetCreateArgData * data)
{
Bonobo_PropertyBag pb = control_get_pb (widget);
char *moniker = gtk_object_get_data (GTK_OBJECT (widget), Moniker);
GList *key_list, *names;
g_assert (moniker);
if (!pb)
return;
key_list = bonobo_pbclient_get_keys (pb, NULL);
for (names = key_list; names; names = names->next) {
CORBA_TypeCode tc;
char *title, *doc;
char *prop = create_prop_name (moniker, names->data);
tc = bonobo_pbclient_get_type (pb, names->data, NULL);
title = bonobo_pbclient_get_doc_title (pb, names->data, NULL);
doc = bonobo_pbclient_get_doc (pb, names->data, NULL);
switch (tc->kind) {
case CORBA_tk_boolean:
property_add_bool (prop, title, doc);
break;
case CORBA_tk_string:
property_add_string (prop, title, doc);
break;
case CORBA_tk_short:
case CORBA_tk_ushort:
/* FIXME: _int_range() ? */
property_add_int (prop, title, doc);
break;
case CORBA_tk_double:
case CORBA_tk_float:
property_add_float (prop, title, doc);
break;
case CORBA_tk_ulong:
case CORBA_tk_long:
property_add_int (prop, title, doc);
break;
default:
g_warning ("Unhandled type %d", tc->kind);
break;
}
g_free (prop);
CORBA_free (title);
CORBA_free (doc);
}
bonobo_pbclient_free_keys (key_list);
}
/*
* Gets the properties of the widget. This is used for both displaying the
* properties in the property editor, and also for saving the properties.
*/
static void
gb_bonobo_control_get_properties (GtkWidget * widget, GbWidgetGetArgData * data)
{
Bonobo_PropertyBag pb = control_get_pb (widget);
char *moniker = gtk_object_get_data (GTK_OBJECT (widget), Moniker);
GList *key_list, *names;
g_assert (moniker);
if (!pb)
return;
/* We save the moniker in the XML, though we don't show it in the property
editor. */
if (data->action == GB_SAVING)
{
save_string (data, Moniker, moniker);
}
key_list = bonobo_pbclient_get_keys (pb, NULL);
for (names = key_list; names; names = names->next) {
CORBA_TypeCode tc;
char *prop = create_prop_name (moniker, names->data);
tc = bonobo_pbclient_get_type (pb, names->data, NULL);
switch (tc->kind) {
case CORBA_tk_boolean:
gb_widget_output_bool (data, prop,
bonobo_pbclient_get_boolean (pb, names->data, NULL));
break;
case CORBA_tk_string:
{
char *str = bonobo_pbclient_get_string (pb, names->data, NULL);
gb_widget_output_translatable_string (data, prop, str);
g_free (str);
break;
}
case CORBA_tk_ulong:
gb_widget_output_int (data, prop,
bonobo_pbclient_get_ulong (pb, names->data, NULL));
break;
case CORBA_tk_long:
gb_widget_output_int (data, prop,
bonobo_pbclient_get_long (pb, names->data, NULL));
break;
case CORBA_tk_short:
gb_widget_output_int (data, prop,
bonobo_pbclient_get_short (pb, names->data, NULL));
break;
case CORBA_tk_ushort:
gb_widget_output_int (data, prop,
bonobo_pbclient_get_ushort (pb, names->data, NULL));
break;
case CORBA_tk_float:
gb_widget_output_float (data, prop,
bonobo_pbclient_get_float (pb, names->data, NULL));
break;
case CORBA_tk_double:
gb_widget_output_float (data, prop,
bonobo_pbclient_get_double (pb, names->data, NULL));
break;
default:
g_warning ("Unhandled type %d", tc->kind);
break;
}
g_free (prop);
}
bonobo_pbclient_free_keys (key_list);
}
/*
* Sets the properties of the widget. This is used for both applying the
* properties changed in the property editor, and also for loading.
*/
static void
gb_bonobo_control_set_properties (GtkWidget * widget, GbWidgetSetArgData * data)
{
Bonobo_PropertyBag pb = control_get_pb (widget);
char *moniker = gtk_object_get_data (GTK_OBJECT (widget), Moniker);
GList *key_list, *names;
g_assert (moniker);
if (!pb)
return;
key_list = bonobo_pbclient_get_keys (pb, NULL);
for (names = key_list; names; names = names->next) {
CORBA_TypeCode tc;
char *prop = create_prop_name (moniker, names->data);
#if 0
g_print ("Checking property: %s\n", prop);
#endif
tc = bonobo_pbclient_get_type (pb, names->data, NULL);
switch (tc->kind) {
case CORBA_tk_boolean:
{
gboolean val;
val = gb_widget_input_bool (data, prop);
if (data->apply)
bonobo_pbclient_set_boolean (pb, names->data, val, NULL);
break;
}
case CORBA_tk_string:
{
const char *str;
str = gb_widget_input_string (data, prop);
if (data->apply)
bonobo_pbclient_set_string (pb, names->data, str, NULL);
break;
}
case CORBA_tk_float:
{
gfloat val;
val = gb_widget_input_float (data, prop);
if (data->apply)
bonobo_pbclient_set_float (pb, names->data, val, NULL);
break;
}
case CORBA_tk_double:
{
gdouble val;
val = gb_widget_input_float (data, prop);
if (data->apply)
bonobo_pbclient_set_double (pb, names->data, val, NULL);
break;
}
case CORBA_tk_long:
{
glong val;
val = gb_widget_input_int (data, prop);
if (data->apply)
bonobo_pbclient_set_long (pb, names->data, val, NULL);
break;
}
case CORBA_tk_ulong:
{
glong val;
val = gb_widget_input_int (data, prop);
if (data->apply)
bonobo_pbclient_set_ulong (pb, names->data, val, NULL);
break;
}
case CORBA_tk_short:
{
glong val;
val = gb_widget_input_int (data, prop);
if (data->apply)
bonobo_pbclient_set_short (pb, names->data, val, NULL);
break;
}
case CORBA_tk_ushort:
{
glong val;
val = gb_widget_input_int (data, prop);
if (data->apply)
bonobo_pbclient_set_ushort (pb, names->data, val, NULL);
break;
}
default:
g_warning ("Unhandled type %d", tc->kind);
break;
}
g_free (prop);
}
bonobo_pbclient_free_keys (key_list);
}
/*
* Writes the source code needed to create this widget.
* You have to output everything necessary to create the widget here, though
* there are some convenience functions to help.
*/
static void
gb_bonobo_control_write_source (GtkWidget * widget, GbWidgetWriteSourceData * data)
{
char *moniker = gtk_object_get_data (GTK_OBJECT (widget), Moniker);
BonoboControlFrame *cf;
Bonobo_PropertyBag pb;
GList *key_list, *names;
if (data->create_widget)
{
/* Currently we don't support BonoboWindow, so it will always be NIL,
but if we ever do, then it just needs to set bonobo_uic when it is
created. */
source_ensure_decl (data, " Bonobo_UIContainer bonobo_uic = CORBA_OBJECT_NIL;\n");
source_add (data,
" %s = bonobo_widget_new_control (%s, bonobo_uic);\n",
data->wname,
source_make_string (moniker, FALSE));
}
gb_widget_write_standard_source (widget, data);
cf = bonobo_widget_get_control_frame (BONOBO_WIDGET (widget));
if (!cf)
return;
pb = bonobo_control_frame_get_control_property_bag (cf, NULL);
source_ensure_decl (data, " BonoboControlFrame *bonobo_cf;\n");
source_ensure_decl (data, " Bonobo_PropertyBag bonobo_pb;\n");
source_add (data,
" bonobo_cf = bonobo_widget_get_control_frame (BONOBO_WIDGET (%s));\n",
data->wname);
source_add (data,
" bonobo_pb = bonobo_control_frame_get_control_property_bag (bonobo_cf, NULL);\n");
key_list = bonobo_pbclient_get_keys (pb, NULL);
for (names = key_list; names; names = names->next) {
CORBA_TypeCode tc;
tc = bonobo_pbclient_get_type (pb, names->data, NULL);
switch (tc->kind) {
case CORBA_tk_boolean: {
gboolean val = bonobo_pbclient_get_boolean (pb, names->data, NULL);
source_add (data,
" bonobo_pbclient_set_boolean (bonobo_pb, %s, %s, NULL);\n",
source_make_string (names->data, FALSE),
val ? "TRUE" : "FALSE");
break;
}
case CORBA_tk_string: {
char *val = bonobo_pbclient_get_string (pb, names->data, NULL);
source_add (data,
" bonobo_pbclient_set_string (bonobo_pb, %s,",
source_make_string (names->data, FALSE));
source_add (data, " %s, NULL);\n",
source_make_string (val, data->use_gettext));
g_free (val);
break;
}
case CORBA_tk_ulong: {
gulong val = bonobo_pbclient_get_ulong (pb, names->data, NULL);
source_add (data,
" bonobo_pbclient_set_ulong (bonobo_pb, %s, %lu, NULL);\n",
source_make_string (names->data, FALSE),
val);
break;
}
case CORBA_tk_long: {
glong val = bonobo_pbclient_get_long (pb, names->data, NULL);
source_add (data,
" bonobo_pbclient_set_long (bonobo_pb, %s, %li, NULL);\n",
source_make_string (names->data, FALSE),
val);
break;
}
case CORBA_tk_short: {
gshort val = bonobo_pbclient_get_short (pb, names->data, NULL);
source_add (data,
" bonobo_pbclient_set_short (bonobo_pb, %s, %i, NULL);\n",
source_make_string (names->data, FALSE),
val);
break;
}
case CORBA_tk_ushort: {
gushort val = bonobo_pbclient_get_ushort (pb, names->data, NULL);
source_add (data,
" bonobo_pbclient_set_ushort (bonobo_pb, %s, %u, NULL);\n",
source_make_string (names->data, FALSE),
val);
break;
}
case CORBA_tk_float: {
gfloat val = bonobo_pbclient_get_float (pb, names->data, NULL);
source_add (data,
" bonobo_pbclient_set_float (bonobo_pb, %s, %g, NULL);\n",
source_make_string (names->data, FALSE),
val);
break;
}
case CORBA_tk_double: {
gdouble val = bonobo_pbclient_get_double (pb, names->data, NULL);
source_add (data,
" bonobo_pbclient_set_double (bonobo_pb, %s, %g, NULL);\n",
source_make_string (names->data, FALSE),
val);
break;
}
default:
g_warning ("Unhandled type %d", tc->kind);
break;
}
}
bonobo_pbclient_free_keys (key_list);
}
static GbWidget *
control_get_gb_widget (const char *obj_id)
{
GbWidget *gbwidget;
/* Check if this GbWidget is already registered. */
gbwidget = gb_widget_lookup_class (obj_id);
/* If it isn't registered, create it and register it. */
if (!gbwidget)
{
gbwidget = g_new (GbWidget, 1);
gb_widget_init_struct (gbwidget);
/* Fill in the pixmap struct & tooltip */
gbwidget->pixmap_struct = gnome_control_xpm;
gbwidget->tooltip = NULL;
/* Fill in any functions that this Gbwidget has */
gbwidget->gb_widget_new = NULL;
gbwidget->gb_widget_create_properties = gb_bonobo_control_create_properties;
gbwidget->gb_widget_get_properties = gb_bonobo_control_get_properties;
gbwidget->gb_widget_set_properties = gb_bonobo_control_set_properties;
gbwidget->gb_widget_write_source = gb_bonobo_control_write_source;
#if 0
g_print ("Registering Bonobo control GbWidget: %s\n", obj_id);
#endif
gb_widget_register_gbwidget (obj_id, gbwidget);
}
return gbwidget;
}