/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* gul-bonobo-extensions.c - implementation of new functions that conceptually
belong in bonobo. Perhaps some of these will be
actually rolled into bonobo someday.
This file is based on nautilus-bonobo-extensions.c from
libnautilus-private.
Copyright (C) 2000, 2001 Eazel, Inc.
The Gnome Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The Gnome Library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the Gnome Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Authors: John Sullivan <sullivan@eazel.com>
Darin Adler <darin@bentspoon.com>
*/
#include <config.h>
#include "ephy-bonobo-extensions.h"
#include "ephy-string.h"
#include <string.h>
#include <bonobo/bonobo-ui-util.h>
#include <gtk/gtkmain.h>
#include <libgnomevfs/gnome-vfs-utils.h>
#include <bonobo/bonobo-control.h>
typedef enum {
NUMBERED_MENU_ITEM_PLAIN,
NUMBERED_MENU_ITEM_TOGGLE,
NUMBERED_MENU_ITEM_RADIO
} NumberedMenuItemType;
void
ephy_bonobo_set_accelerator (BonoboUIComponent *ui,
const char *path,
const char *accelerator)
{
if (bonobo_ui_component_get_container (ui)) /* should not do this here... */
{
bonobo_ui_component_set_prop (ui, path, "accel", accelerator, NULL);
}
}
void
ephy_bonobo_set_label (BonoboUIComponent *ui,
const char *path,
const char *label)
{
if (bonobo_ui_component_get_container (ui)) /* should not do this here... */
{
bonobo_ui_component_set_prop (ui, path, "label", label, NULL);
}
}
void
ephy_bonobo_set_tip (BonoboUIComponent *ui,
const char *path,
const char *tip)
{
if (bonobo_ui_component_get_container (ui)) /* should not do this here... */
{
bonobo_ui_component_set_prop (ui, path, "tip", tip, NULL);
}
}
void
ephy_bonobo_set_sensitive (BonoboUIComponent *ui,
const char *path,
gboolean sensitive)
{
if (bonobo_ui_component_get_container (ui)) /* should not do this here... */
{
bonobo_ui_component_set_prop (ui, path, "sensitive", sensitive ? "1" : "0", NULL);
}
}
void
ephy_bonobo_set_toggle_state (BonoboUIComponent *ui,
const char *path,
gboolean state)
{
if (bonobo_ui_component_get_container (ui)) /* should not do this here... */
{
bonobo_ui_component_set_prop (ui, path, "state", state ? "1" : "0", NULL);
}
}
void
ephy_bonobo_set_hidden (BonoboUIComponent *ui,
const char *path,
gboolean hidden)
{
if (bonobo_ui_component_get_container (ui)) /* should not do this here... */
{
bonobo_ui_component_set_prop (ui, path, "hidden", hidden ? "1" : "0", NULL);
}
}
char *
ephy_bonobo_get_label (BonoboUIComponent *ui,
const char *path)
{
if (bonobo_ui_component_get_container (ui)) /* should not do this here... */
{
return bonobo_ui_component_get_prop (ui, path, "label", NULL);
}
else
{
return NULL;
}
}
gboolean
ephy_bonobo_get_hidden (BonoboUIComponent *ui,
const char *path)
{
char *value;
gboolean hidden;
CORBA_Environment ev;
g_return_val_if_fail (BONOBO_IS_UI_COMPONENT (ui), FALSE);
g_return_val_if_fail (path != NULL, FALSE);
CORBA_exception_init (&ev);
value = bonobo_ui_component_get_prop (ui, path, "hidden", &ev);
CORBA_exception_free (&ev);
if (value == NULL) {
/* No hidden attribute means not hidden. */
hidden = FALSE;
} else {
/* Anything other than "0" counts as TRUE */
hidden = strcmp (value, "0") != 0;
g_free (value);
}
return hidden;
}
static char *
get_numbered_menu_item_name (guint index)
{
return g_strdup_printf ("%u", index);
}
char *
ephy_bonobo_get_numbered_menu_item_path (BonoboUIComponent *ui,
const char *container_path,
guint index)
{
char *item_name;
char *item_path;
g_return_val_if_fail (BONOBO_IS_UI_COMPONENT (ui), NULL);
g_return_val_if_fail (container_path != NULL, NULL);
item_name = get_numbered_menu_item_name (index);
item_path = g_strconcat (container_path, "/", item_name, NULL);
g_free (item_name);
return item_path;
}
char *
ephy_bonobo_get_numbered_menu_item_command (BonoboUIComponent *ui,
const char *container_path,
guint index)
{
char *command_name;
char *path;
g_return_val_if_fail (BONOBO_IS_UI_COMPONENT (ui), NULL);
g_return_val_if_fail (container_path != NULL, NULL);
path = ephy_bonobo_get_numbered_menu_item_path (ui, container_path, index);
command_name = gnome_vfs_escape_string (path);
g_free (path);
return command_name;
}
guint
ephy_bonobo_get_numbered_menu_item_index_from_command (const char *command)
{
char *path;
char *index_string;
int index;
gboolean got_index;
path = gnome_vfs_unescape_string (command, NULL);
index_string = strrchr (path, '/');
if (index_string == NULL) {
got_index = FALSE;
} else {
got_index = ephy_str_to_int (index_string + 1, &index);
}
g_free (path);
g_return_val_if_fail (got_index, 0);
return index;
}
char *
ephy_bonobo_get_numbered_menu_item_container_path_from_command (const char *command)
{
char *path;
char *index_string;
char *container_path;
path = gnome_vfs_unescape_string (command, NULL);
index_string = strrchr (path, '/');
container_path = index_string == NULL
? NULL
: g_strndup (path, index_string - path);
g_free (path);
return container_path;
}
static char *
ephy_bonobo_add_numbered_menu_item_internal (BonoboUIComponent *ui,
const char *container_path,
guint index,
const char *label,
NumberedMenuItemType type,
GdkPixbuf *pixbuf,
const char *radio_group_name)
{
char *xml_item, *xml_command;
char *command_name;
char *item_name, *pixbuf_data;
char *path;
g_assert (BONOBO_IS_UI_COMPONENT (ui));
g_assert (container_path != NULL);
g_assert (label != NULL);
g_assert (type == NUMBERED_MENU_ITEM_PLAIN || pixbuf == NULL);
g_assert (type == NUMBERED_MENU_ITEM_RADIO || radio_group_name == NULL);
g_assert (type != NUMBERED_MENU_ITEM_RADIO || radio_group_name != NULL);
item_name = get_numbered_menu_item_name (index);
command_name = ephy_bonobo_get_numbered_menu_item_command
(ui, container_path, index);
switch (type) {
case NUMBERED_MENU_ITEM_TOGGLE:
xml_item = g_strdup_printf ("<menuitem name=\"%s\" id=\"%s\" type=\"toggle\"/>\n",
item_name, command_name);
break;
case NUMBERED_MENU_ITEM_RADIO:
xml_item = g_strdup_printf ("<menuitem name=\"%s\" id=\"%s\" "
"type=\"radio\" group=\"%s\"/>\n",
item_name, command_name, radio_group_name);
break;
case NUMBERED_MENU_ITEM_PLAIN:
if (pixbuf != NULL) {
pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf);
xml_item = g_strdup_printf ("<menuitem name=\"%s\" verb=\"%s\" "
"pixtype=\"pixbuf\" pixname=\"%s\"/>\n",
item_name, command_name, pixbuf_data);
g_free (pixbuf_data);
} else {
xml_item = g_strdup_printf ("<menuitem name=\"%s\" verb=\"%s\"/>\n",
item_name, command_name);
}
break;
default:
g_assert_not_reached ();
xml_item = NULL; /* keep compiler happy */
}
g_free (item_name);
bonobo_ui_component_set (ui, container_path, xml_item, NULL);
g_free (xml_item);
path = ephy_bonobo_get_numbered_menu_item_path (ui, container_path, index);
ephy_bonobo_set_label (ui, path, label);
g_free (path);
/* Make the command node here too, so callers can immediately set
* properties on it (otherwise it doesn't get created until some
* time later).
*/
xml_command = g_strdup_printf ("<cmd name=\"%s\"/>\n", command_name);
bonobo_ui_component_set (ui, "/commands", xml_command, NULL);
g_free (xml_command);
g_free (command_name);
return item_name;
}
/* Add a menu item specified by number into a given path. Used for
* dynamically creating a related series of menu items. Each index
* must be unique (normal use is to call this in a loop, and
* increment the index for each item).
*/
void
ephy_bonobo_add_numbered_menu_item (BonoboUIComponent *ui,
const char *container_path,
guint index,
const char *label,
GdkPixbuf *pixbuf)
{
g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
g_return_if_fail (container_path != NULL);
g_return_if_fail (label != NULL);
ephy_bonobo_add_numbered_menu_item_internal (ui, container_path, index, label,
NUMBERED_MENU_ITEM_PLAIN, pixbuf, NULL);
}
/* Add a menu item specified by number into a given path. Used for
* dynamically creating a related series of toggle menu items. Each index
* must be unique (normal use is to call this in a loop, and
* increment the index for each item).
*/
void
ephy_bonobo_add_numbered_toggle_menu_item (BonoboUIComponent *ui,
const char *container_path,
guint index,
const char *label)
{
g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
g_return_if_fail (container_path != NULL);
g_return_if_fail (label != NULL);
ephy_bonobo_add_numbered_menu_item_internal (ui, container_path, index, label,
NUMBERED_MENU_ITEM_TOGGLE, NULL, NULL);
}
/* Add a menu item specified by number into a given path. Used for
* dynamically creating a related series of radio menu items. Each index
* must be unique (normal use is to call this in a loop, and
* increment the index for each item).
*/
void
ephy_bonobo_add_numbered_radio_menu_item (BonoboUIComponent *ui,
const char *container_path,
guint index,
const char *label,
const char *radio_group_name)
{
g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
g_return_if_fail (container_path != NULL);
g_return_if_fail (label != NULL);
ephy_bonobo_add_numbered_menu_item_internal (ui, container_path, index, label,
NUMBERED_MENU_ITEM_RADIO, NULL, radio_group_name);
}
void
ephy_bonobo_add_numbered_submenu (BonoboUIComponent *ui,
const char *container_path,
guint index,
const char *label,
GdkPixbuf *pixbuf)
{
char *xml_string, *item_name, *pixbuf_data, *submenu_path, *command_name;
g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
g_return_if_fail (container_path != NULL);
g_return_if_fail (label != NULL);
g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
item_name = get_numbered_menu_item_name (index);
command_name = ephy_bonobo_get_numbered_menu_item_command (ui, container_path, index);
if (pixbuf != NULL) {
pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf);
xml_string = g_strdup_printf ("<submenu name=\"%s\" pixtype=\"pixbuf\" pixname=\"%s\" "
"verb=\"%s\"/>\n",
item_name, pixbuf_data, command_name);
g_free (pixbuf_data);
} else {
xml_string = g_strdup_printf ("<submenu name=\"%s\" verb=\"%s\"/>\n", item_name,
command_name);
}
bonobo_ui_component_set (ui, container_path, xml_string, NULL);
g_free (xml_string);
submenu_path = ephy_bonobo_get_numbered_menu_item_path (ui, container_path, index);
ephy_bonobo_set_label (ui, submenu_path, label);
g_free (submenu_path);
g_free (item_name);
g_free (command_name);
}
void
ephy_bonobo_add_numbered_submenu_no_verb (BonoboUIComponent *ui,
const char *container_path,
guint index,
const char *label,
GdkPixbuf *pixbuf)
{
char *xml_string, *item_name, *pixbuf_data, *submenu_path;
g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
g_return_if_fail (container_path != NULL);
g_return_if_fail (label != NULL);
g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
item_name = get_numbered_menu_item_name (index);
if (pixbuf != NULL) {
pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf);
xml_string = g_strdup_printf ("<submenu name=\"%s\" pixtype=\"pixbuf\" pixname=\"%s\" "
"/>\n",
item_name, pixbuf_data);
g_free (pixbuf_data);
} else {
xml_string = g_strdup_printf ("<submenu name=\"%s\"/>\n", item_name);
}
bonobo_ui_component_set (ui, container_path, xml_string, NULL);
g_free (xml_string);
submenu_path = ephy_bonobo_get_numbered_menu_item_path (ui, container_path, index);
ephy_bonobo_set_label (ui, submenu_path, label);
g_free (submenu_path);
g_free (item_name);
}
void
ephy_bonobo_add_submenu (BonoboUIComponent *ui,
const char *path,
const char *label,
GdkPixbuf *pixbuf)
{
char *xml_string, *name, *pixbuf_data, *submenu_path;
g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
g_return_if_fail (path != NULL);
g_return_if_fail (label != NULL);
g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
/* Labels may contain characters that are illegal in names. So
* we create the name by URI-encoding the label.
*/
name = gnome_vfs_escape_string (label);
if (pixbuf != NULL) {
pixbuf_data = bonobo_ui_util_pixbuf_to_xml (pixbuf);
xml_string = g_strdup_printf ("<submenu name=\"%s\" pixtype=\"pixbuf\" pixname=\"%s\"/>\n",
name, pixbuf_data);
g_free (pixbuf_data);
} else {
xml_string = g_strdup_printf ("<submenu name=\"%s\"/>\n", name);
}
bonobo_ui_component_set (ui, path, xml_string, NULL);
g_free (xml_string);
submenu_path = g_strconcat (path, "/", name, NULL);
ephy_bonobo_set_label (ui, submenu_path, label);
g_free (submenu_path);
g_free (name);
}
void
ephy_bonobo_add_menu_separator (BonoboUIComponent *ui, const char *path)
{
static gint hack = 0;
gchar *xml;
g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
g_return_if_fail (path != NULL);
xml = g_strdup_printf ("<separator name=\"sep%d\"/>", ++hack);
bonobo_ui_component_set (ui, path, xml, NULL);
g_free (xml);
}
static void
remove_commands (BonoboUIComponent *ui, const char *container_path)
{
BonoboUINode *path_node;
BonoboUINode *child_node;
char *verb_name;
char *id_name;
path_node = bonobo_ui_component_get_tree (ui, container_path, TRUE, NULL);
if (path_node == NULL) {
return;
}
bonobo_ui_component_freeze (ui, NULL);
for (child_node = bonobo_ui_node_children (path_node);
child_node != NULL;
child_node = bonobo_ui_node_next (child_node)) {
verb_name = bonobo_ui_node_get_attr (child_node, "verb");
if (verb_name != NULL) {
bonobo_ui_component_remove_verb (ui, verb_name);
bonobo_ui_node_free_string (verb_name);
} else {
/* Only look for an id if there's no verb */
id_name = bonobo_ui_node_get_attr (child_node, "id");
if (id_name != NULL) {
bonobo_ui_component_remove_listener (ui, id_name);
bonobo_ui_node_free_string (id_name);
}
}
}
bonobo_ui_component_thaw (ui, NULL);
bonobo_ui_node_free (path_node);
}
/**
* ephy_bonobo_remove_menu_items_and_verbs
*
* Removes all menu items contained in a menu or placeholder, and
* their verbs.
*
* @uih: The BonoboUIHandler for this menu item.
* @container_path: The standard bonobo-style path specifier for this placeholder or submenu.
*/
void
ephy_bonobo_remove_menu_items_and_commands (BonoboUIComponent *ui,
const char *container_path)
{
char *remove_wildcard;
g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
g_return_if_fail (container_path != NULL);
remove_commands (ui, container_path);
/* For speed, remove menu items themselves all in one fell swoop,
* though we removed the verbs one-by-one.
*/
remove_wildcard = g_strdup_printf ("%s/*", container_path);
bonobo_ui_component_rm (ui, remove_wildcard, NULL);
g_free (remove_wildcard);
}
/* Call to set the user-visible label of a menu item to a string
* containing an underscore accelerator. The underscore is stripped
* off before setting the label of the command, because pop-up menu
* and toolbar button labels shouldn't have the underscore.
*/
void
ephy_bonobo_set_label_for_menu_item_and_command (BonoboUIComponent *ui,
const char *menu_item_path,
const char *command_path,
const char *label_with_underscore)
{
char *label_no_underscore;
g_return_if_fail (BONOBO_IS_UI_COMPONENT (ui));
g_return_if_fail (menu_item_path != NULL);
g_return_if_fail (command_path != NULL);
g_return_if_fail (label_with_underscore != NULL);
label_no_underscore = ephy_str_strip_chr (label_with_underscore, '_');
ephy_bonobo_set_label (ui,
menu_item_path,
label_with_underscore);
ephy_bonobo_set_label (ui,
command_path,
label_no_underscore);
g_free (label_no_underscore);
}
gchar *
ephy_bonobo_add_dockitem (BonoboUIComponent *uic,
const char *name,
int band_num)
{
gchar *xml;
gchar *sname;
gchar *path;
sname = gnome_vfs_escape_string (name);
xml = g_strdup_printf ("<dockitem name=\"%s\" band_num=\"%d\" "
"config=\"0\" behavior=\"exclusive\"/>",
sname, band_num);
path = g_strdup_printf ("/%s", sname);
bonobo_ui_component_set (uic, "", xml, NULL);
g_free (sname);
g_free (xml);
return path;
}
BonoboControl *
ephy_bonobo_add_numbered_control (BonoboUIComponent *uic, GtkWidget *w,
guint index, const char *container_path)
{
BonoboControl *control;
char *xml_string, *item_name, *control_path;
g_return_val_if_fail (BONOBO_IS_UI_COMPONENT (uic), NULL);
g_return_val_if_fail (container_path != NULL, NULL);
item_name = get_numbered_menu_item_name (index);
xml_string = g_strdup_printf ("<control name=\"%s\"/>", item_name);
bonobo_ui_component_set (uic, container_path, xml_string, NULL);
g_free (xml_string);
control_path = ephy_bonobo_get_numbered_menu_item_path (uic, container_path, index);
control = bonobo_control_new (w);
bonobo_ui_component_object_set (uic, control_path, BONOBO_OBJREF (control), NULL);
bonobo_object_unref (control);
g_free (control_path);
g_free (item_name);
return control;
}
void
ephy_bonobo_replace_path (BonoboUIComponent *uic, const gchar *path_src,
const char *path_dst)
{
BonoboUINode *node;
const char *name;
char *path_dst_folder;
name = strrchr (path_dst, '/');
g_return_if_fail (name != NULL);
path_dst_folder = g_strndup (path_dst, name - path_dst);
name++;
node = bonobo_ui_component_get_tree (uic, path_src, TRUE, NULL);
bonobo_ui_node_set_attr (node, "name", name);
ephy_bonobo_clear_path (uic, path_dst);
bonobo_ui_component_set_tree (uic, path_dst_folder, node, NULL);
g_free (path_dst_folder);
bonobo_ui_node_free (node);
}
void
ephy_bonobo_clear_path (BonoboUIComponent *uic,
const gchar *path)
{
if (bonobo_ui_component_path_exists (uic, path, NULL))
{
char *remove_wildcard = g_strdup_printf ("%s/*", path);
bonobo_ui_component_rm (uic, remove_wildcard, NULL);
g_free (remove_wildcard);
}
}
void
ephy_bonobo_add_numbered_widget (BonoboUIComponent *uic, GtkWidget *w,
guint index, const char *container_path)
{
gchar *path = ephy_bonobo_get_numbered_menu_item_path (uic, container_path, index);
gchar *item_name = get_numbered_menu_item_name (index);
gchar *xml_string = g_strdup_printf ("<control name=\"%s\"/>", item_name);
bonobo_ui_component_set (uic, container_path, xml_string, NULL);
bonobo_ui_component_widget_set (uic, path, w, NULL);
g_free (path);
g_free (item_name);
g_free (xml_string);
}