mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-03-03 06:32:10 +01:00
Drop the GMenu markup functions
The parser has been moved into Gtk in a modified form and the printer was never really useful anyway (except for debugging/testing).
This commit is contained in:
parent
4e9f59bff8
commit
2a90aba068
@ -145,7 +145,6 @@ application_headers = \
|
||||
gsimpleaction.h \
|
||||
\
|
||||
gmenumodel.h \
|
||||
gmenumarkup.h \
|
||||
gmenu.h \
|
||||
gmenuexporter.h \
|
||||
gdbusmenumodel.h \
|
||||
@ -167,7 +166,6 @@ application_sources = \
|
||||
gsimpleaction.c \
|
||||
\
|
||||
gmenumodel.c \
|
||||
gmenumarkup.c \
|
||||
gmenu.c \
|
||||
gmenuexporter.c \
|
||||
gdbusmenumodel.c \
|
||||
@ -615,9 +613,6 @@ EXTRA_DIST += \
|
||||
abicheck.sh \
|
||||
gio.rc.in \
|
||||
gschema.dtd \
|
||||
menumarkup.xml \
|
||||
menumarkup2.xml \
|
||||
menumarkup.dtd \
|
||||
$(NULL)
|
||||
|
||||
BUILT_EXTRA_DIST = \
|
||||
|
@ -152,7 +152,6 @@
|
||||
#include <gio/gmenumodel.h>
|
||||
#include <gio/gmenu.h>
|
||||
#include <gio/gmenuexporter.h>
|
||||
#include <gio/gmenumarkup.h>
|
||||
#include <gio/gdbusmenumodel.h>
|
||||
|
||||
#undef __GIO_GIO_H_INSIDE__
|
||||
|
@ -1,741 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2011 Canonical Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
#include "gmenumarkup.h"
|
||||
|
||||
#include <gi18n.h>
|
||||
|
||||
/**
|
||||
* SECTION:gmenumarkup
|
||||
* @title: GMenu Markup
|
||||
* @short_description: parsing and printing GMenuModel XML
|
||||
*
|
||||
* The functions here allow to instantiate #GMenuModels by parsing
|
||||
* fragments of an XML document.
|
||||
* * The XML format for #GMenuModel consists of a toplevel
|
||||
* <tag class="starttag">menu</tag> element, which contains one or more
|
||||
* <tag class="starttag">item</tag> elements. Each <tag class="starttag">item</tag>
|
||||
* element contains <tag class="starttag">attribute</tag> and <tag class="starttag">link</tag>
|
||||
* elements with a mandatory name attribute.
|
||||
* <tag class="starttag">link</tag> elements have the same content
|
||||
* model as <tag class="starttag">menu</tag>.
|
||||
*
|
||||
* Here is the XML for <xref linkend="menu-example"/>:
|
||||
* |[<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/menumarkup2.xml"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include>]|
|
||||
*
|
||||
* The parser also understands a somewhat less verbose format, in which
|
||||
* attributes are encoded as actual XML attributes of <tag class="starttag">item</tag>
|
||||
* elements, and <tag class="starttag">link</tag> elements are replaced by
|
||||
* <tag class="starttag">section</tag> and <tag class="starttag">submenu</tag> elements.
|
||||
*
|
||||
* Here is how the example looks in this format:
|
||||
* |[<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/menumarkup.xml"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include>]|
|
||||
*
|
||||
* The parser can obtaing translations for attribute values using gettext.
|
||||
* To make use of this, the <tag class="starttag">menu</tag> element must
|
||||
* have a domain attribute which specifies the gettext domain to use, and
|
||||
* <tag class="starttag">attribute</tag> elements can be marked for translation
|
||||
* with a <literal>translatable="yes"</literal> attribute. It is also possible
|
||||
* to specify message context and translator comments, using the context
|
||||
* and comments attributes.
|
||||
*
|
||||
* The following DTD describes the XML format approximately:
|
||||
* |[<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/menumarkup.dtd"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include>]|
|
||||
*
|
||||
* To serialize a #GMenuModel into an XML fragment, use
|
||||
* g_menu_markup_print_string().
|
||||
*/
|
||||
|
||||
struct frame
|
||||
{
|
||||
GMenu *menu;
|
||||
GMenuItem *item;
|
||||
struct frame *prev;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GHashTable *objects;
|
||||
struct frame frame;
|
||||
|
||||
/* attributes */
|
||||
GQuark attribute;
|
||||
GVariantType *type;
|
||||
GString *string;
|
||||
|
||||
/* translation */
|
||||
gchar *domain;
|
||||
gchar *context;
|
||||
gboolean translatable;
|
||||
} GMenuMarkupState;
|
||||
|
||||
static void
|
||||
g_menu_markup_push_frame (GMenuMarkupState *state,
|
||||
GMenu *menu,
|
||||
GMenuItem *item)
|
||||
{
|
||||
struct frame *new;
|
||||
|
||||
new = g_slice_new (struct frame);
|
||||
*new = state->frame;
|
||||
|
||||
state->frame.menu = menu;
|
||||
state->frame.item = item;
|
||||
state->frame.prev = new;
|
||||
}
|
||||
|
||||
static void
|
||||
g_menu_markup_pop_frame (GMenuMarkupState *state)
|
||||
{
|
||||
struct frame *prev = state->frame.prev;
|
||||
|
||||
if (state->frame.item)
|
||||
{
|
||||
g_assert (prev->menu != NULL);
|
||||
g_menu_append_item (prev->menu, state->frame.item);
|
||||
g_object_unref (state->frame.item);
|
||||
}
|
||||
|
||||
state->frame = *prev;
|
||||
|
||||
g_slice_free (struct frame, prev);
|
||||
}
|
||||
|
||||
static void
|
||||
add_string_attributes (GMenuItem *item,
|
||||
const gchar **names,
|
||||
const gchar **values)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; names[i]; i++)
|
||||
{
|
||||
g_menu_item_set_attribute (item, names[i], "s", values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
find_id_attribute (const gchar **names,
|
||||
const gchar **values,
|
||||
const gchar **id)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; names[i]; i++)
|
||||
{
|
||||
if (strcmp (names[i], "id") == 0)
|
||||
{
|
||||
*id = values[i];
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
g_menu_markup_start_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
const gchar **attribute_names,
|
||||
const gchar **attribute_values,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
GMenuMarkupState *state = user_data;
|
||||
|
||||
#define COLLECT(first, ...) \
|
||||
g_markup_collect_attributes (element_name, \
|
||||
attribute_names, attribute_values, error, \
|
||||
first, __VA_ARGS__, G_MARKUP_COLLECT_INVALID)
|
||||
#define OPTIONAL G_MARKUP_COLLECT_OPTIONAL
|
||||
#define BOOLEAN G_MARKUP_COLLECT_BOOLEAN
|
||||
#define STRING G_MARKUP_COLLECT_STRING
|
||||
|
||||
if (!(state->frame.menu || state->frame.item || state->string))
|
||||
{
|
||||
/* Can only have <menu> here. */
|
||||
if (g_str_equal (element_name, "menu"))
|
||||
{
|
||||
gchar *id;
|
||||
|
||||
if (COLLECT (STRING, "id", &id))
|
||||
{
|
||||
GMenu *menu;
|
||||
|
||||
menu = g_menu_new ();
|
||||
if (state->objects)
|
||||
g_hash_table_insert (state->objects, g_strdup (id), menu);
|
||||
g_menu_markup_push_frame (state, menu, NULL);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->frame.menu)
|
||||
{
|
||||
/* Can have '<item>', '<submenu>' or '<section>' here. */
|
||||
if (g_str_equal (element_name, "item"))
|
||||
{
|
||||
GMenuItem *item;
|
||||
|
||||
item = g_menu_item_new (NULL, NULL);
|
||||
add_string_attributes (item, attribute_names, attribute_values);
|
||||
g_menu_markup_push_frame (state, NULL, item);
|
||||
return;
|
||||
}
|
||||
|
||||
else if (g_str_equal (element_name, "submenu"))
|
||||
{
|
||||
GMenuItem *item;
|
||||
GMenu *menu;
|
||||
const gchar *id;
|
||||
|
||||
menu = g_menu_new ();
|
||||
item = g_menu_item_new_submenu (NULL, G_MENU_MODEL (menu));
|
||||
add_string_attributes (item, attribute_names, attribute_values);
|
||||
g_menu_markup_push_frame (state, menu, item);
|
||||
|
||||
if (find_id_attribute (attribute_names, attribute_values, &id))
|
||||
{
|
||||
if (state->objects)
|
||||
g_hash_table_insert (state->objects, g_strdup (id), g_object_ref (menu));
|
||||
}
|
||||
g_object_unref (menu);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
else if (g_str_equal (element_name, "section"))
|
||||
{
|
||||
GMenuItem *item;
|
||||
GMenu *menu;
|
||||
const gchar *id;
|
||||
|
||||
menu = g_menu_new ();
|
||||
item = g_menu_item_new_section (NULL, G_MENU_MODEL (menu));
|
||||
add_string_attributes (item, attribute_names, attribute_values);
|
||||
g_menu_markup_push_frame (state, menu, item);
|
||||
|
||||
if (find_id_attribute (attribute_names, attribute_values, &id))
|
||||
{
|
||||
if (state->objects)
|
||||
g_hash_table_insert (state->objects, g_strdup (id), g_object_ref (menu));
|
||||
}
|
||||
g_object_unref (menu);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->frame.item)
|
||||
{
|
||||
/* Can have '<attribute>' or '<link>' here. */
|
||||
if (g_str_equal (element_name, "attribute"))
|
||||
{
|
||||
const gchar *typestr;
|
||||
const gchar *name;
|
||||
const gchar *context;
|
||||
|
||||
if (COLLECT (STRING, "name", &name,
|
||||
OPTIONAL | BOOLEAN, "translatable", &state->translatable,
|
||||
OPTIONAL | STRING, "context", &context,
|
||||
OPTIONAL | STRING, "comments", NULL, /* ignore, just for translators */
|
||||
OPTIONAL | STRING, "type", &typestr))
|
||||
{
|
||||
if (typestr && !g_variant_type_string_is_valid (typestr))
|
||||
{
|
||||
g_set_error (error, G_VARIANT_PARSE_ERROR,
|
||||
G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING,
|
||||
"Invalid GVariant type string '%s'", typestr);
|
||||
return;
|
||||
}
|
||||
|
||||
state->type = typestr ? g_variant_type_new (typestr) : g_variant_type_copy (G_VARIANT_TYPE_STRING);
|
||||
state->string = g_string_new (NULL);
|
||||
state->attribute = g_quark_from_string (name);
|
||||
state->context = g_strdup (context);
|
||||
|
||||
g_menu_markup_push_frame (state, NULL, NULL);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_str_equal (element_name, "link"))
|
||||
{
|
||||
const gchar *name;
|
||||
const gchar *id;
|
||||
|
||||
if (COLLECT (STRING, "name", &name,
|
||||
STRING | OPTIONAL, "id", &id))
|
||||
{
|
||||
GMenu *menu;
|
||||
|
||||
menu = g_menu_new ();
|
||||
g_menu_item_set_link (state->frame.item, name, G_MENU_MODEL (menu));
|
||||
g_menu_markup_push_frame (state, menu, NULL);
|
||||
|
||||
if (id != NULL && state->objects)
|
||||
g_hash_table_insert (state->objects, g_strdup (id), g_object_ref (menu));
|
||||
g_object_unref (menu);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const GSList *element_stack;
|
||||
|
||||
element_stack = g_markup_parse_context_get_element_stack (context);
|
||||
|
||||
if (element_stack->next)
|
||||
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
|
||||
_("Element <%s> not allowed inside <%s>"),
|
||||
element_name, (const gchar *) element_stack->next->data);
|
||||
|
||||
else
|
||||
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
|
||||
_("Element <%s> not allowed at toplevel"), element_name);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
g_menu_markup_end_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
GMenuMarkupState *state = user_data;
|
||||
|
||||
g_menu_markup_pop_frame (state);
|
||||
|
||||
if (state->string)
|
||||
{
|
||||
GVariant *value;
|
||||
gchar *text;
|
||||
|
||||
text = g_string_free (state->string, FALSE);
|
||||
state->string = NULL;
|
||||
|
||||
/* If error is set here, it will follow us out, ending the parse.
|
||||
* We still need to free everything, though.
|
||||
*/
|
||||
if ((value = g_variant_parse (state->type, text, NULL, NULL, error)))
|
||||
{
|
||||
/* Deal with translatable string attributes */
|
||||
if (state->domain && state->translatable &&
|
||||
g_variant_type_equal (state->type, G_VARIANT_TYPE_STRING))
|
||||
{
|
||||
const gchar *msgid;
|
||||
const gchar *msgstr;
|
||||
|
||||
msgid = g_variant_get_string (value, NULL);
|
||||
if (state->context)
|
||||
msgstr = g_dpgettext2 (state->domain, state->context, msgid);
|
||||
else
|
||||
msgstr = g_dgettext (state->domain, msgid);
|
||||
|
||||
if (msgstr != msgid)
|
||||
{
|
||||
g_variant_unref (value);
|
||||
value = g_variant_new_string (msgstr);
|
||||
g_variant_ref_sink (value);
|
||||
}
|
||||
}
|
||||
|
||||
g_menu_item_set_attribute_value (state->frame.item, g_quark_to_string (state->attribute), value);
|
||||
g_variant_unref (value);
|
||||
}
|
||||
|
||||
g_variant_type_free (state->type);
|
||||
state->type = NULL;
|
||||
|
||||
g_free (state->context);
|
||||
state->context = NULL;
|
||||
|
||||
g_free (text);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
g_menu_markup_text (GMarkupParseContext *context,
|
||||
const gchar *text,
|
||||
gsize text_len,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
GMenuMarkupState *state = user_data;
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < text_len; i++)
|
||||
if (!g_ascii_isspace (text[i]))
|
||||
{
|
||||
if (state->string)
|
||||
g_string_append_len (state->string, text, text_len);
|
||||
|
||||
else
|
||||
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
|
||||
_("text may not appear inside <%s>"),
|
||||
g_markup_parse_context_get_element (context));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
g_menu_markup_error (GMarkupParseContext *context,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
GMenuMarkupState *state = user_data;
|
||||
|
||||
while (state->frame.prev)
|
||||
{
|
||||
struct frame *prev = state->frame.prev;
|
||||
|
||||
state->frame = *prev;
|
||||
|
||||
g_slice_free (struct frame, prev);
|
||||
}
|
||||
|
||||
if (state->string)
|
||||
g_string_free (state->string, TRUE);
|
||||
|
||||
if (state->type)
|
||||
g_variant_type_free (state->type);
|
||||
|
||||
if (state->objects)
|
||||
g_hash_table_unref (state->objects);
|
||||
|
||||
g_free (state->context);
|
||||
|
||||
g_slice_free (GMenuMarkupState, state);
|
||||
}
|
||||
|
||||
static GMarkupParser g_menu_subparser =
|
||||
{
|
||||
g_menu_markup_start_element,
|
||||
g_menu_markup_end_element,
|
||||
g_menu_markup_text,
|
||||
NULL, /* passthrough */
|
||||
g_menu_markup_error
|
||||
};
|
||||
|
||||
/**
|
||||
* g_menu_markup_parser_start:
|
||||
* @context: a #GMarkupParseContext
|
||||
* @domain: (allow-none): translation domain for labels, or %NULL
|
||||
* @objects: (allow-none): a #GHashTable for the objects, or %NULL
|
||||
*
|
||||
* Begin parsing a group of menus in XML form.
|
||||
*
|
||||
* If @domain is not %NULL, it will be used to translate attributes
|
||||
* that are marked as translatable, using gettext().
|
||||
*
|
||||
* If @objects is specified then it must be a #GHashTable that was
|
||||
* created using g_hash_table_new_full() with g_str_hash(),
|
||||
* g_str_equal(), g_free() and g_object_unref().
|
||||
* Any named menus (ie: <tag class="starttag">menu</tag>,
|
||||
* <tag class="starttag">submenu</tag>,
|
||||
* <tag class="starttag">section</tag> or <tag class="starttag">link</tag>
|
||||
* elements with an id='' attribute) that are encountered while parsing
|
||||
* will be added to this table. Each toplevel menu must be named.
|
||||
*
|
||||
* If @objects is %NULL then an empty hash table will be created.
|
||||
*
|
||||
* This function should be called from the start_element function for
|
||||
* the element representing the group containing the menus. In other
|
||||
* words, the content inside of this element is expected to be a list of
|
||||
* menus.
|
||||
*
|
||||
* Since: 2.32
|
||||
*/
|
||||
void
|
||||
g_menu_markup_parser_start (GMarkupParseContext *context,
|
||||
const gchar *domain,
|
||||
GHashTable *objects)
|
||||
{
|
||||
GMenuMarkupState *state;
|
||||
|
||||
g_return_if_fail (context != NULL);
|
||||
|
||||
state = g_slice_new0 (GMenuMarkupState);
|
||||
|
||||
state->domain = g_strdup (domain);
|
||||
|
||||
if (objects != NULL)
|
||||
state->objects = g_hash_table_ref (objects);
|
||||
else
|
||||
state->objects = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
||||
|
||||
g_markup_parse_context_push (context, &g_menu_subparser, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_menu_markup_parser_end:
|
||||
* @context: a #GMarkupParseContext
|
||||
*
|
||||
* Stop the parsing of a set of menus and return the #GHashTable.
|
||||
*
|
||||
* The #GHashTable maps strings to #GObject instances. The parser only
|
||||
* adds #GMenu instances to the table, but it may contain other types if
|
||||
* a table was provided to g_menu_markup_parser_start().
|
||||
*
|
||||
* This call should be matched with g_menu_markup_parser_start().
|
||||
* See that function for more information
|
||||
*
|
||||
* Returns: (transfer full): the #GHashTable containing the objects
|
||||
*
|
||||
* Since: 2.32
|
||||
*/
|
||||
GHashTable *
|
||||
g_menu_markup_parser_end (GMarkupParseContext *context)
|
||||
{
|
||||
GMenuMarkupState *state = g_markup_parse_context_pop (context);
|
||||
GHashTable *objects;
|
||||
|
||||
objects = state->objects;
|
||||
|
||||
g_free (state->domain);
|
||||
|
||||
g_slice_free (GMenuMarkupState, state);
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_menu_markup_parser_start_menu:
|
||||
* @context: a #GMarkupParseContext
|
||||
* @domain: (allow-none): translation domain for labels, or %NULL
|
||||
* @objects: (allow-none): a #GHashTable for the objects, or %NULL
|
||||
*
|
||||
* Begin parsing the XML definition of a menu.
|
||||
*
|
||||
* This function should be called from the start_element function for
|
||||
* the element representing the menu itself. In other words, the
|
||||
* content inside of this element is expected to be a list of items.
|
||||
*
|
||||
* If @domain is not %NULL, it will be used to translate attributes
|
||||
* that are marked as translatable, using gettext().
|
||||
*
|
||||
* If @objects is specified then it must be a #GHashTable that was
|
||||
* created using g_hash_table_new_full() with g_str_hash(),
|
||||
* g_str_equal(), g_free() and g_object_unref().
|
||||
* Any named menus (ie: <tag class="starttag">submenu</tag>,
|
||||
* <tag class="starttag">section</tag> or <tag class="starttag">link</tag>
|
||||
* elements with an id='' attribute) that are encountered while parsing
|
||||
* will be added to this table.
|
||||
* Note that toplevel <tag class="starttag">menu</tag> is not added to
|
||||
* the hash table, even if it has an id attribute.
|
||||
*
|
||||
* If @objects is %NULL then named menus will not be supported.
|
||||
*
|
||||
* You should call g_menu_markup_parser_end_menu() from the
|
||||
* corresponding end_element function in order to collect the newly
|
||||
* parsed menu.
|
||||
*
|
||||
* Since: 2.32
|
||||
*/
|
||||
void
|
||||
g_menu_markup_parser_start_menu (GMarkupParseContext *context,
|
||||
const gchar *domain,
|
||||
GHashTable *objects)
|
||||
{
|
||||
GMenuMarkupState *state;
|
||||
|
||||
g_return_if_fail (context != NULL);
|
||||
|
||||
state = g_slice_new0 (GMenuMarkupState);
|
||||
|
||||
if (objects)
|
||||
state->objects = g_hash_table_ref (objects);
|
||||
|
||||
state->domain = g_strdup (domain);
|
||||
|
||||
g_markup_parse_context_push (context, &g_menu_subparser, state);
|
||||
|
||||
state->frame.menu = g_menu_new ();
|
||||
}
|
||||
|
||||
/**
|
||||
* g_menu_markup_parser_end_menu:
|
||||
* @context: a #GMarkupParseContext
|
||||
*
|
||||
* Stop the parsing of a menu and return the newly-created #GMenu.
|
||||
*
|
||||
* This call should be matched with g_menu_markup_parser_start_menu().
|
||||
* See that function for more information
|
||||
*
|
||||
* Returns: (transfer full): the newly-created #GMenu
|
||||
*
|
||||
* Since: 2.32
|
||||
*/
|
||||
GMenu *
|
||||
g_menu_markup_parser_end_menu (GMarkupParseContext *context)
|
||||
{
|
||||
GMenuMarkupState *state = g_markup_parse_context_pop (context);
|
||||
GMenu *menu;
|
||||
|
||||
menu = state->frame.menu;
|
||||
|
||||
if (state->objects)
|
||||
g_hash_table_unref (state->objects);
|
||||
g_free (state->domain);
|
||||
g_slice_free (GMenuMarkupState, state);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
static void
|
||||
indent_string (GString *string,
|
||||
gint indent)
|
||||
{
|
||||
while (indent--)
|
||||
g_string_append_c (string, ' ');
|
||||
}
|
||||
|
||||
/**
|
||||
* g_menu_markup_print_string:
|
||||
* @string: a #GString
|
||||
* @model: the #GMenuModel to print
|
||||
* @indent: the intentation level to start at
|
||||
* @tabstop: how much to indent each level
|
||||
*
|
||||
* Print the contents of @model to @string.
|
||||
* Note that you have to provide the containing
|
||||
* <tag class="starttag">menu</tag> element yourself.
|
||||
*
|
||||
* Returns: @string
|
||||
*
|
||||
* Since: 2.32
|
||||
*/
|
||||
GString *
|
||||
g_menu_markup_print_string (GString *string,
|
||||
GMenuModel *model,
|
||||
gint indent,
|
||||
gint tabstop)
|
||||
{
|
||||
gboolean need_nl = FALSE;
|
||||
gint i, n;
|
||||
|
||||
if G_UNLIKELY (string == NULL)
|
||||
string = g_string_new (NULL);
|
||||
|
||||
n = g_menu_model_get_n_items (model);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
GMenuAttributeIter *attr_iter;
|
||||
GMenuLinkIter *link_iter;
|
||||
GString *contents;
|
||||
GString *attrs;
|
||||
|
||||
attr_iter = g_menu_model_iterate_item_attributes (model, i);
|
||||
link_iter = g_menu_model_iterate_item_links (model, i);
|
||||
contents = g_string_new (NULL);
|
||||
attrs = g_string_new (NULL);
|
||||
|
||||
while (g_menu_attribute_iter_next (attr_iter))
|
||||
{
|
||||
const char *name = g_menu_attribute_iter_get_name (attr_iter);
|
||||
GVariant *value = g_menu_attribute_iter_get_value (attr_iter);
|
||||
|
||||
if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
|
||||
{
|
||||
gchar *str;
|
||||
str = g_markup_printf_escaped (" %s='%s'", name, g_variant_get_string (value, NULL));
|
||||
g_string_append (attrs, str);
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
gchar *printed;
|
||||
gchar *str;
|
||||
const gchar *type;
|
||||
|
||||
printed = g_variant_print (value, TRUE);
|
||||
type = g_variant_type_peek_string (g_variant_get_type (value));
|
||||
str = g_markup_printf_escaped ("<attribute name='%s' type='%s'>%s</attribute>\n", name, type, printed);
|
||||
indent_string (contents, indent + tabstop);
|
||||
g_string_append (contents, str);
|
||||
g_free (printed);
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
g_variant_unref (value);
|
||||
}
|
||||
g_object_unref (attr_iter);
|
||||
|
||||
while (g_menu_link_iter_next (link_iter))
|
||||
{
|
||||
const gchar *name = g_menu_link_iter_get_name (link_iter);
|
||||
GMenuModel *menu = g_menu_link_iter_get_value (link_iter);
|
||||
gchar *str;
|
||||
|
||||
if (contents->str[0])
|
||||
g_string_append_c (contents, '\n');
|
||||
|
||||
str = g_markup_printf_escaped ("<link name='%s'>\n", name);
|
||||
indent_string (contents, indent + tabstop);
|
||||
g_string_append (contents, str);
|
||||
g_free (str);
|
||||
|
||||
g_menu_markup_print_string (contents, menu, indent + 2 * tabstop, tabstop);
|
||||
|
||||
indent_string (contents, indent + tabstop);
|
||||
g_string_append (contents, "</link>\n");
|
||||
g_object_unref (menu);
|
||||
}
|
||||
g_object_unref (link_iter);
|
||||
|
||||
if (contents->str[0])
|
||||
{
|
||||
indent_string (string, indent);
|
||||
g_string_append_printf (string, "<item%s>\n", attrs->str);
|
||||
g_string_append (string, contents->str);
|
||||
indent_string (string, indent);
|
||||
g_string_append (string, "</item>\n");
|
||||
need_nl = TRUE;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (need_nl)
|
||||
g_string_append_c (string, '\n');
|
||||
|
||||
indent_string (string, indent);
|
||||
g_string_append_printf (string, "<item%s/>\n", attrs->str);
|
||||
need_nl = FALSE;
|
||||
}
|
||||
|
||||
g_string_free (contents, TRUE);
|
||||
g_string_free (attrs, TRUE);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_menu_markup_print_stderr:
|
||||
* @model: a #GMenuModel
|
||||
*
|
||||
* Print @model to stderr for debugging purposes.
|
||||
*
|
||||
* This debugging function will be removed in the future.
|
||||
*/
|
||||
void
|
||||
g_menu_markup_print_stderr (GMenuModel *model)
|
||||
{
|
||||
GString *string;
|
||||
|
||||
string = g_string_new ("<menu>\n");
|
||||
g_menu_markup_print_string (string, model, 2, 2);
|
||||
g_printerr ("%s</menu>\n", string->str);
|
||||
g_string_free (string, TRUE);
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2011 Canonical Ltd.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* licence, or (at your option) any later version.
|
||||
*
|
||||
* This 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*
|
||||
* Author: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
#ifndef __G_MENU_MARKUP_H__
|
||||
#define __G_MENU_MARKUP_H__
|
||||
|
||||
#include <gio/gmenu.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void g_menu_markup_parser_start (GMarkupParseContext *context,
|
||||
const gchar *domain,
|
||||
GHashTable *objects);
|
||||
GHashTable * g_menu_markup_parser_end (GMarkupParseContext *context);
|
||||
|
||||
void g_menu_markup_parser_start_menu (GMarkupParseContext *context,
|
||||
const gchar *domain,
|
||||
GHashTable *objects);
|
||||
GMenu * g_menu_markup_parser_end_menu (GMarkupParseContext *context);
|
||||
|
||||
void g_menu_markup_print_stderr (GMenuModel *model);
|
||||
GString * g_menu_markup_print_string (GString *string,
|
||||
GMenuModel *model,
|
||||
gint indent,
|
||||
gint tabstop);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_MENU_MARKUP_H__ */
|
@ -1,29 +0,0 @@
|
||||
<!ELEMENT menu (item|submenu|section)* >
|
||||
<!ATTLIST menu id CDATA #REQUIRED
|
||||
domain #IMPLIED >
|
||||
|
||||
<!ELEMENT item (attribute|link)* >
|
||||
<!ATTLIST item label CDATA #IMPLIED
|
||||
action CDATA #IMPLIED
|
||||
target CDATA #IMPLIED >
|
||||
|
||||
<!ELEMENT attribute (#PCDATA) >
|
||||
<!ATTLIST attribute name CDATA #REQUIRED
|
||||
type CDATA #IMPLIED
|
||||
translatable (yes|no) #IMPLIED
|
||||
context CDATA #IMPLIED
|
||||
comments CDATA #IMPLIED >
|
||||
|
||||
<!ELEMENT link (item*) >
|
||||
<!ATTLIST link name CDATA #REQUIRED
|
||||
id CDATA #IMPLIED >
|
||||
|
||||
<!ELEMENT submenu (item|submenu|section)* >
|
||||
<!ATTLIST submenu label CDATA #IMPLIED
|
||||
action CDATA #IMPLIED
|
||||
target CDATA #IMPLIED >
|
||||
|
||||
<!ELEMENT section (item|submenu|section)* >
|
||||
<!ATTLIST section label CDATA #IMPLIED
|
||||
action CDATA #IMPLIED
|
||||
target CDATA #IMPLIED >
|
@ -1,26 +0,0 @@
|
||||
<menu id='menubar'>
|
||||
<submenu label='File'></submenu>
|
||||
<submenu label='Edit'></submenu>
|
||||
<submenu label='View'>
|
||||
<section>
|
||||
<item label='Toolbar' action='toolbar'/>
|
||||
<item label='Statusbar' action='statusbar'/>
|
||||
</section>
|
||||
<section>
|
||||
<item label='Fullscreen' action='fullscreen'/>
|
||||
</section>
|
||||
<section>
|
||||
<submenu label='Highlight Mode'>
|
||||
<section label='Sources'>
|
||||
<item label='Vala' action='sources' target='vala'/>
|
||||
<item label='Python' action='sources' target='python'/>
|
||||
</section>
|
||||
<section label='Markup'>
|
||||
<item label='asciidoc' action='markup' target='asciidoc'/>
|
||||
<item label='HTML' action='markup' target='html'/>
|
||||
</section>
|
||||
</submenu>
|
||||
</section>
|
||||
</submenu>
|
||||
<submenu label='Help'></submenu>
|
||||
</menu>
|
@ -1,75 +0,0 @@
|
||||
<menu id='menubar'>
|
||||
<item>
|
||||
<attribute name='label'>File</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name='label'>Edit</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name='label'>View</attribute>
|
||||
<link name='submenu'>
|
||||
<item>
|
||||
<link name='section'>
|
||||
<item>
|
||||
<attribute name='label'>Toolbar</attribute>
|
||||
<attribute name='action'>toolbar</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name='label'>Statusbar</attribute>
|
||||
<attribute name='action'>statusbar</attribute>
|
||||
</item>
|
||||
</link>
|
||||
</item>
|
||||
<item>
|
||||
<link name='section'>
|
||||
<item>
|
||||
<attribute name='label'>Fullscreen</attribute>
|
||||
<attribute name='action'>fullscreen</attribute>
|
||||
</item>
|
||||
</link>
|
||||
</item>
|
||||
<item>
|
||||
<link name='section'>
|
||||
<item>
|
||||
<attribute name='label'>Highlight Mode</attribute>
|
||||
<link name='submenu'>
|
||||
<item>
|
||||
<attribute name='label'>Sources</attribute>
|
||||
<link name='section'>
|
||||
<item>
|
||||
<attribute name='label'>Vala</attribute>
|
||||
<attribute name='action'>sources</attribute>
|
||||
<attribute name='target'>vala</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name='label'>Python</attribute>
|
||||
<attribute name='action'>sources</attribute>
|
||||
<attribute name='target'>python</attribute>
|
||||
</item>
|
||||
</link>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name='label'>Markup</attribute>
|
||||
<link name='section'>
|
||||
<item>
|
||||
<attribute name='label'>asciidoc</attribute>
|
||||
<attribute name='action'>markup</attribute>
|
||||
<attribute name='target'>asciidoc</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name='label'>HTML</attribute>
|
||||
<attribute name='action'>markup</attribute>
|
||||
<attribute name='target'>html</attribute>
|
||||
</item>
|
||||
</link>
|
||||
</item>
|
||||
</link>
|
||||
</item>
|
||||
</link>
|
||||
</item>
|
||||
</link>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name='label'>Help</attribute>
|
||||
</item>
|
||||
</menu>
|
@ -1,5 +1,125 @@
|
||||
#include <gio/gio.h>
|
||||
|
||||
/* Markup printing {{{1 */
|
||||
|
||||
/* This used to be part of GLib, but it was removed before the stable
|
||||
* release because it wasn't generally useful. We want it here, though.
|
||||
*/
|
||||
static void
|
||||
indent_string (GString *string,
|
||||
gint indent)
|
||||
{
|
||||
while (indent--)
|
||||
g_string_append_c (string, ' ');
|
||||
}
|
||||
|
||||
static GString *
|
||||
g_menu_markup_print_string (GString *string,
|
||||
GMenuModel *model,
|
||||
gint indent,
|
||||
gint tabstop)
|
||||
{
|
||||
gboolean need_nl = FALSE;
|
||||
gint i, n;
|
||||
|
||||
if G_UNLIKELY (string == NULL)
|
||||
string = g_string_new (NULL);
|
||||
|
||||
n = g_menu_model_get_n_items (model);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
GMenuAttributeIter *attr_iter;
|
||||
GMenuLinkIter *link_iter;
|
||||
GString *contents;
|
||||
GString *attrs;
|
||||
|
||||
attr_iter = g_menu_model_iterate_item_attributes (model, i);
|
||||
link_iter = g_menu_model_iterate_item_links (model, i);
|
||||
contents = g_string_new (NULL);
|
||||
attrs = g_string_new (NULL);
|
||||
|
||||
while (g_menu_attribute_iter_next (attr_iter))
|
||||
{
|
||||
const char *name = g_menu_attribute_iter_get_name (attr_iter);
|
||||
GVariant *value = g_menu_attribute_iter_get_value (attr_iter);
|
||||
|
||||
if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
|
||||
{
|
||||
gchar *str;
|
||||
str = g_markup_printf_escaped (" %s='%s'", name, g_variant_get_string (value, NULL));
|
||||
g_string_append (attrs, str);
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
gchar *printed;
|
||||
gchar *str;
|
||||
const gchar *type;
|
||||
|
||||
printed = g_variant_print (value, TRUE);
|
||||
type = g_variant_type_peek_string (g_variant_get_type (value));
|
||||
str = g_markup_printf_escaped ("<attribute name='%s' type='%s'>%s</attribute>\n", name, type, printed);
|
||||
indent_string (contents, indent + tabstop);
|
||||
g_string_append (contents, str);
|
||||
g_free (printed);
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
g_variant_unref (value);
|
||||
}
|
||||
g_object_unref (attr_iter);
|
||||
|
||||
while (g_menu_link_iter_next (link_iter))
|
||||
{
|
||||
const gchar *name = g_menu_link_iter_get_name (link_iter);
|
||||
GMenuModel *menu = g_menu_link_iter_get_value (link_iter);
|
||||
gchar *str;
|
||||
|
||||
if (contents->str[0])
|
||||
g_string_append_c (contents, '\n');
|
||||
|
||||
str = g_markup_printf_escaped ("<link name='%s'>\n", name);
|
||||
indent_string (contents, indent + tabstop);
|
||||
g_string_append (contents, str);
|
||||
g_free (str);
|
||||
|
||||
g_menu_markup_print_string (contents, menu, indent + 2 * tabstop, tabstop);
|
||||
|
||||
indent_string (contents, indent + tabstop);
|
||||
g_string_append (contents, "</link>\n");
|
||||
g_object_unref (menu);
|
||||
}
|
||||
g_object_unref (link_iter);
|
||||
|
||||
if (contents->str[0])
|
||||
{
|
||||
indent_string (string, indent);
|
||||
g_string_append_printf (string, "<item%s>\n", attrs->str);
|
||||
g_string_append (string, contents->str);
|
||||
indent_string (string, indent);
|
||||
g_string_append (string, "</item>\n");
|
||||
need_nl = TRUE;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (need_nl)
|
||||
g_string_append_c (string, '\n');
|
||||
|
||||
indent_string (string, indent);
|
||||
g_string_append_printf (string, "<item%s/>\n", attrs->str);
|
||||
need_nl = FALSE;
|
||||
}
|
||||
|
||||
g_string_free (contents, TRUE);
|
||||
g_string_free (attrs, TRUE);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
/* TestItem {{{1 */
|
||||
|
||||
/* This utility struct is used by both the RandomMenu and MirrorMenu
|
||||
@ -789,189 +909,6 @@ test_dbus_threaded (void)
|
||||
g_object_unref (menu[i]);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GMenu *menu;
|
||||
GHashTable *objects;
|
||||
} ParserData;
|
||||
|
||||
static void
|
||||
start_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
const gchar **attribute_names,
|
||||
const gchar **attribute_values,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
ParserData *data = user_data;
|
||||
|
||||
if (g_strcmp0 (element_name, "menu") == 0)
|
||||
g_menu_markup_parser_start_menu (context, "domain", data->objects);
|
||||
}
|
||||
|
||||
static void
|
||||
end_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
ParserData *data = user_data;
|
||||
|
||||
if (g_strcmp0 (element_name, "menu") == 0)
|
||||
data->menu = g_menu_markup_parser_end_menu (context);
|
||||
}
|
||||
|
||||
static GMenuModel *
|
||||
parse_menu_string (const gchar *string, GHashTable *objects, GError **error)
|
||||
{
|
||||
const GMarkupParser parser = {
|
||||
start_element, end_element, NULL, NULL, NULL
|
||||
};
|
||||
GMarkupParseContext *context;
|
||||
ParserData data;
|
||||
|
||||
data.menu = NULL;
|
||||
data.objects = objects;
|
||||
|
||||
context = g_markup_parse_context_new (&parser, 0, &data, NULL);
|
||||
g_markup_parse_context_parse (context, string, -1, error);
|
||||
g_markup_parse_context_free (context);
|
||||
|
||||
return (GMenuModel*)data.menu;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
menu_to_string (GMenuModel *menu)
|
||||
{
|
||||
GString *s;
|
||||
|
||||
s = g_string_new ("<menu>\n");
|
||||
g_menu_markup_print_string (s, menu, 2, 2);
|
||||
g_string_append (s, "</menu>\n");
|
||||
|
||||
return g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
const gchar menu_data[] =
|
||||
"<menu id='edit-menu'>\n"
|
||||
" <section>\n"
|
||||
" <item action='undo'>\n"
|
||||
" <attribute name='label' translatable='yes' context='Stock label'>'_Undo'</attribute>\n"
|
||||
" </item>\n"
|
||||
" <item label='Redo' action='redo'/>\n"
|
||||
" </section>\n"
|
||||
" <section></section>\n"
|
||||
" <section label='Copy & Paste'>\n"
|
||||
" <item label='Cut' action='cut'/>\n"
|
||||
" <item label='Copy' action='copy'/>\n"
|
||||
" <item label='Paste' action='paste'/>\n"
|
||||
" </section>\n"
|
||||
" <item><link name='section' id='blargh'>\n"
|
||||
" <item label='Bold' action='bold'/>\n"
|
||||
" <submenu label='Language'>\n"
|
||||
" <item label='Latin' action='lang' target='latin'/>\n"
|
||||
" <item label='Greek' action='lang' target='greek'/>\n"
|
||||
" <item label='Urdu' action='lang' target='urdu'/>\n"
|
||||
" </submenu>\n"
|
||||
" <item name='test unusual attributes'>\n"
|
||||
" <attribute name='action' type='s'>'quite-some-action'</attribute>\n"
|
||||
" <attribute name='target' type='i'>36</attribute>\n"
|
||||
" <attribute name='chocolate-thunda' type='as'>['a','b']</attribute>\n"
|
||||
" <attribute name='thing1' type='g'>'s(uu)'</attribute>\n"
|
||||
" <attribute name='icon' type='s'>'small blue thing'</attribute>\n"
|
||||
" </item>\n"
|
||||
" </link></item>\n"
|
||||
"</menu>\n";
|
||||
|
||||
static void
|
||||
test_markup_roundtrip (void)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GMenuModel *a;
|
||||
GMenuModel *b;
|
||||
gchar *s;
|
||||
gchar *s2;
|
||||
|
||||
a = parse_menu_string (menu_data, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (G_IS_MENU_MODEL (a));
|
||||
|
||||
/* normalized representation */
|
||||
s = menu_to_string (a);
|
||||
|
||||
b = parse_menu_string (s, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (G_IS_MENU_MODEL (b));
|
||||
|
||||
assert_menus_equal (G_MENU_MODEL (a), G_MENU_MODEL (b));
|
||||
|
||||
s2 = menu_to_string (b);
|
||||
|
||||
g_assert_cmpstr (s, ==, s2);
|
||||
|
||||
g_object_unref (a);
|
||||
g_object_unref (b);
|
||||
g_free (s);
|
||||
g_free (s2);
|
||||
}
|
||||
|
||||
static void
|
||||
test_markup_objects (void)
|
||||
{
|
||||
GMenuModel *a, *b;
|
||||
GHashTable *objects;
|
||||
GError *error = NULL;
|
||||
|
||||
objects = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
||||
a = parse_menu_string (menu_data, objects, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (G_IS_MENU_MODEL (a));
|
||||
g_assert_cmpint (g_hash_table_size (objects), ==, 1);
|
||||
b = g_hash_table_lookup (objects, "blargh");
|
||||
g_assert (G_IS_MENU_MODEL (b));
|
||||
g_object_unref (a);
|
||||
g_hash_table_unref (objects);
|
||||
}
|
||||
|
||||
const gchar menu_data2[] =
|
||||
"<menu>"
|
||||
" <section>"
|
||||
" <item label='Redo' action='redo'/>"
|
||||
" </section>"
|
||||
" <section></section>\n"
|
||||
" <section label='Copy & Paste'>"
|
||||
" <item label='Cut' action='cut'/>"
|
||||
" </section>"
|
||||
" <section id='section1'>"
|
||||
" <item label='Bold' action='bold'/>"
|
||||
" <submenu label='Language' id='submenu1'>"
|
||||
" <section id='section2'>"
|
||||
" <item label='Urdu' action='lang' target='urdu'/>"
|
||||
" </section>"
|
||||
" </submenu>"
|
||||
" </section>"
|
||||
"</menu>";
|
||||
static void
|
||||
test_markup_ids (void)
|
||||
{
|
||||
GMenuModel *a, *b;
|
||||
GHashTable *objects;
|
||||
GError *error = NULL;
|
||||
|
||||
objects = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
||||
a = parse_menu_string (menu_data2, objects, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (G_IS_MENU_MODEL (a));
|
||||
g_assert_cmpint (g_hash_table_size (objects), ==, 3);
|
||||
b = g_hash_table_lookup (objects, "section1");
|
||||
g_assert (G_IS_MENU_MODEL (b));
|
||||
b = g_hash_table_lookup (objects, "section2");
|
||||
g_assert (G_IS_MENU_MODEL (b));
|
||||
b = g_hash_table_lookup (objects, "submenu1");
|
||||
g_assert (G_IS_MENU_MODEL (b));
|
||||
g_object_unref (a);
|
||||
g_hash_table_unref (objects);
|
||||
}
|
||||
|
||||
static void
|
||||
test_attributes (void)
|
||||
{
|
||||
@ -1078,73 +1015,7 @@ test_mutable (void)
|
||||
g_object_unref (menu);
|
||||
}
|
||||
|
||||
static void
|
||||
test_misc (void)
|
||||
{
|
||||
/* trying to use most of the GMenu api for constructing the
|
||||
* same menu two different ways
|
||||
*/
|
||||
GMenu *a, *m, *m2;
|
||||
GMenuModel *b;
|
||||
GMenuItem *item;
|
||||
const gchar *s;
|
||||
|
||||
a = g_menu_new ();
|
||||
item = g_menu_item_new ("test1", "action1::target1");
|
||||
g_menu_prepend_item (a, item);
|
||||
g_object_unref (item);
|
||||
|
||||
m = g_menu_new ();
|
||||
g_menu_prepend (m, "test2a", "action2");
|
||||
g_menu_append (m, "test2c", NULL);
|
||||
g_menu_insert (m, 1, "test2b", NULL);
|
||||
|
||||
item = g_menu_item_new_submenu ("test2", G_MENU_MODEL (m));
|
||||
g_menu_append_item (a, item);
|
||||
g_object_unref (item);
|
||||
g_object_unref (m);
|
||||
|
||||
m = g_menu_new ();
|
||||
|
||||
m2 = g_menu_new ();
|
||||
g_menu_append (m2, "x", NULL);
|
||||
g_menu_prepend_section (m, "test3a", G_MENU_MODEL (m2));
|
||||
g_object_unref (m2);
|
||||
|
||||
item = g_menu_item_new_section ("test3", G_MENU_MODEL (m));
|
||||
g_menu_insert_item (a, -1, item);
|
||||
g_object_unref (item);
|
||||
g_object_unref (m);
|
||||
|
||||
s = ""
|
||||
"<menu>"
|
||||
" <item target='target1' action='action1' label='test1'/>"
|
||||
" <item label='test2'>"
|
||||
" <link name='submenu'>"
|
||||
" <item action='action2' label='test2a'/>"
|
||||
" <item label='test2b'/>"
|
||||
" <item label='test2c'/>"
|
||||
" </link>"
|
||||
" </item>"
|
||||
" <item label='test3'>"
|
||||
" <link name='section'>"
|
||||
" <item label='test3a'>"
|
||||
" <link name='section'>"
|
||||
" <item label='x'/>"
|
||||
" </link>"
|
||||
" </item>"
|
||||
" </link>"
|
||||
" </item>"
|
||||
"</menu>";
|
||||
|
||||
b = parse_menu_string (s, NULL, NULL);
|
||||
|
||||
assert_menus_equal (G_MENU_MODEL (a), G_MENU_MODEL (b));
|
||||
g_object_unref (a);
|
||||
g_object_unref (b);
|
||||
}
|
||||
|
||||
/* Epilogue {{{1 */
|
||||
/* Epilogue {{{1 */
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@ -1157,13 +1028,9 @@ main (int argc, char **argv)
|
||||
g_test_add_func ("/gmenu/dbus/roundtrip", test_dbus_roundtrip);
|
||||
g_test_add_func ("/gmenu/dbus/subscriptions", test_dbus_subscriptions);
|
||||
g_test_add_func ("/gmenu/dbus/threaded", test_dbus_threaded);
|
||||
g_test_add_func ("/gmenu/markup/roundtrip", test_markup_roundtrip);
|
||||
g_test_add_func ("/gmenu/markup/objects", test_markup_objects);
|
||||
g_test_add_func ("/gmenu/markup/ids", test_markup_ids);
|
||||
g_test_add_func ("/gmenu/attributes", test_attributes);
|
||||
g_test_add_func ("/gmenu/links", test_links);
|
||||
g_test_add_func ("/gmenu/mutable", test_mutable);
|
||||
g_test_add_func ("/gmenu/misc", test_misc);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user