Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/vcl/unx/gtk3/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 20 kB image not shown  

Quelle  glomenu.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */


#include <o3tl/safeint.hxx>

#include <unx/gtk/glomenu.h>

struct GLOMenu
{
    GMenuModel const  parent_instance;

    GArray      *items;
};

typedef GMenuModelClass GLOMenuClass;

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#if defined __clang__
#if __has_warning("-Wdeprecated-volatile")
#pragma clang diagnostic ignored "-Wdeprecated-volatile"
#endif
#endif
#endif
G_DEFINE_TYPE (GLOMenu, g_lo_menu, G_TYPE_MENU_MODEL);
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

namespace {

struct item
{
    GHashTable*     attributes;     // Item attributes.
    GHashTable*     links;          // Item links.
};

}

static void
g_lo_menu_struct_item_init (struct item *menu_item)
{
    menu_item->attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, reinterpret_cast<GDestroyNotify>(g_variant_unref));
    menu_item->links = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
}

/* We treat attribute names the same as GSettings keys:
 * - only lowercase ascii, digits and '-'
 * - must start with lowercase
 * - must not end with '-'
 * - no consecutive '-'
 * - not longer than 1024 chars
 */

static bool
valid_attribute_name (const gchar *name)
{
    gint i;

    if (!g_ascii_islower (name[0]))
        return false;

    for (i = 1; name[i]; i++)
    {
        if (name[i] != '-' &&
                !g_ascii_islower (name[i]) &&
                !g_ascii_isdigit (name[i]))
            return false;

        if (name[i] == '-' && name[i + 1] == '-')
            return false;
    }

    if (name[i - 1] == '-')
        return false;

    if (i > 1024)
        return false;

    return true;
}

/*
 * GLOMenu
 */


static gboolean
g_lo_menu_is_mutable (GMenuModel*)
{
    // Menu is always mutable.
    return true;
}

static gint
g_lo_menu_get_n_items (GMenuModel *model)
{
    g_return_val_if_fail (model != nullptr, 0);
    GLOMenu *menu = G_LO_MENU (model);
    g_return_val_if_fail (menu->items != nullptr, 0);

    return menu->items->len;
}

gint
g_lo_menu_get_n_items_from_section (GLOMenu *menu,
                                    gint     section)
{
    g_return_val_if_fail (0 <= section && o3tl::make_unsigned(section) < menu->items->len, 0);

    GLOMenu *model = g_lo_menu_get_section (menu, section);

    g_return_val_if_fail (model != nullptr, 0);

    gint length = model->items->len;

    g_object_unref (model);

    return length;
}

static void
g_lo_menu_get_item_attributes (GMenuModel  *model,
                               gint         position,
                               GHashTable **table)
{
    GLOMenu *menu = G_LO_MENU (model);
    *table = g_hash_table_ref (g_array_index (menu->items, struct item, position).attributes);
}

static void
g_lo_menu_get_item_links (GMenuModel  *model,
                          gint         position,
                          GHashTable **table)
{
    GLOMenu *menu = G_LO_MENU (model);
    *table = g_hash_table_ref (g_array_index (menu->items, struct item, position).links);
}

void
g_lo_menu_insert (GLOMenu     *menu,
                  gint         position,
                  const gchar *label)
{
    g_lo_menu_insert_section (menu, position, label, nullptr);
}

void
g_lo_menu_insert_in_section (GLOMenu     *menu,
                             gint         section,
                             gint         position,
                             const gchar *label)
{
    g_return_if_fail (G_IS_LO_MENU (menu));
    g_return_if_fail (0 <= section && o3tl::make_unsigned(section) < menu->items->len);

    GLOMenu *model = g_lo_menu_get_section (menu, section);

    g_return_if_fail (model != nullptr);

    g_lo_menu_insert (model, position, label);

    g_object_unref (model);
}

GLOMenu *
g_lo_menu_new()
{
    return G_LO_MENU( g_object_new (G_TYPE_LO_MENU, nullptr) );
}

static void
g_lo_menu_set_attribute_value (GLOMenu     *menu,
                               gint         position,
                               const gchar *attribute,
                               GVariant    *value)
{
    g_return_if_fail (G_IS_LO_MENU (menu));
    g_return_if_fail (attribute != nullptr);
    g_return_if_fail (valid_attribute_name (attribute));

    if (position >= static_cast<gint>(menu->items->len))
        return;

    struct item menu_item = g_array_index (menu->items, struct item, position);

    if (value != nullptr)
        g_hash_table_insert (menu_item.attributes, g_strdup (attribute), g_variant_ref_sink (value));
    else
        g_hash_table_remove (menu_item.attributes, attribute);
}

static GVariant*
g_lo_menu_get_attribute_value_from_item_in_section (GLOMenu            *menu,
                                                    gint                section,
                                                    gint                position,
                                                    const gchar        *attribute,
                                                    const GVariantType *type)
{
    GMenuModel *model = G_MENU_MODEL (g_lo_menu_get_section (menu, section));

    g_return_val_if_fail (model != nullptr, nullptr);

    GVariant *value = g_menu_model_get_item_attribute_value (model,
                                                             position,
                                                             attribute,
                                                             type);

    g_object_unref (model);

    return value;
}

void
g_lo_menu_set_label (GLOMenu     *menu,
                     gint         position,
                     const gchar *label)
{
    g_return_if_fail (G_IS_LO_MENU (menu));

    GVariant *value;

    if (label != nullptr)
        value = g_variant_new_string (label);
    else
        value = nullptr;

    g_lo_menu_set_attribute_value (menu, position, G_MENU_ATTRIBUTE_LABEL, value);
}

void
g_lo_menu_set_icon (GLOMenu     *menu,
                    gint         position,
                    const GIcon *icon)
{
    g_return_if_fail (G_IS_LO_MENU (menu));

    GVariant *value;

    if (icon != nullptr)
    {
#if GLIB_CHECK_VERSION(2,38,0)
        value = g_icon_serialize (const_cast<GIcon*>(icon));
#else
        value = nullptr;
#endif
    }
    else
        value = nullptr;

#ifndef G_MENU_ATTRIBUTE_ICON
#    define G_MENU_ATTRIBUTE_ICON "icon"
#endif

    g_lo_menu_set_attribute_value (menu, position, G_MENU_ATTRIBUTE_ICON, value);
    if (value)
      g_variant_unref (value);
}

void
g_lo_menu_set_label_to_item_in_section (GLOMenu     *menu,
                                        gint         section,
                                        gint         position,
                                        const gchar *label)
{
    g_return_if_fail (G_IS_LO_MENU (menu));

    GLOMenu *model = g_lo_menu_get_section (menu, section);

    g_return_if_fail (model != nullptr);

    g_lo_menu_set_label (model, position, label);

    // Notify the update.
    g_menu_model_items_changed (G_MENU_MODEL (model), position, 1, 1);

    g_object_unref (model);
}

void
g_lo_menu_set_icon_to_item_in_section (GLOMenu     *menu,
                                       gint         section,
                                       gint         position,
                                       const GIcon *icon)
{
    g_return_if_fail (G_IS_LO_MENU (menu));

    GLOMenu *model = g_lo_menu_get_section (menu, section);

    g_return_if_fail (model != nullptr);

    g_lo_menu_set_icon (model, position, icon);

    // Notify the update.
    g_menu_model_items_changed (G_MENU_MODEL (model), position, 1, 1);

    g_object_unref (model);
}

gchar *
g_lo_menu_get_label_from_item_in_section (GLOMenu *menu,
                                          gint     section,
                                          gint     position)
{
    g_return_val_if_fail (G_IS_LO_MENU (menu), nullptr);

    GVariant *label_value = g_lo_menu_get_attribute_value_from_item_in_section (menu,
                                                                                section,
                                                                                position,
                                                                                G_MENU_ATTRIBUTE_LABEL,
                                                                                G_VARIANT_TYPE_STRING);

    gchar *label = nullptr;

    if (label_value)
    {
        label = g_variant_dup_string (label_value, nullptr);
        g_variant_unref (label_value);
    }

    return label;
}

void
g_lo_menu_set_action_and_target_value (GLOMenu     *menu,
                                       gint         position,
                                       const gchar *action,
                                       GVariant    *target_value)
{
    g_return_if_fail (G_IS_LO_MENU (menu));

    GVariant *action_value;

    if (action != nullptr)
    {
        action_value = g_variant_new_string (action);
    }
    else
    {
        action_value = nullptr;
        target_value = nullptr;
    }

    g_lo_menu_set_attribute_value (menu, position, G_MENU_ATTRIBUTE_ACTION, action_value);
    g_lo_menu_set_attribute_value (menu, position, G_MENU_ATTRIBUTE_TARGET, target_value);
    g_lo_menu_set_attribute_value (menu, position, G_LO_MENU_ATTRIBUTE_SUBMENU_ACTION, nullptr);

    g_menu_model_items_changed (G_MENU_MODEL (menu), position, 1, 1);
}

void
g_lo_menu_set_action_and_target_value_to_item_in_section (GLOMenu     *menu,
                                                          gint         section,
                                                          gint         position,
                                                          const gchar *command,
                                                          GVariant    *target_value)
{
    g_return_if_fail (G_IS_LO_MENU (menu));

    GLOMenu *model = g_lo_menu_get_section (menu, section);

    g_return_if_fail (model != nullptr);

    g_lo_menu_set_action_and_target_value (model, position, command, target_value);

    g_object_unref (model);
}

void
g_lo_menu_set_accelerator_to_item_in_section (GLOMenu     *menu,
                                              gint         section,
                                              gint         position,
                                              const gchar *accelerator)
{
    g_return_if_fail (G_IS_LO_MENU (menu));

    GLOMenu *model = g_lo_menu_get_section (menu, section);

    g_return_if_fail (model != nullptr);

    GVariant *value;

    if (accelerator != nullptr)
        value = g_variant_new_string (accelerator);
    else
        value = nullptr;

    g_lo_menu_set_attribute_value (model, position, G_LO_MENU_ATTRIBUTE_ACCELERATOR, value);

    // Notify the update.
    g_menu_model_items_changed (G_MENU_MODEL (model), position, 1, 1);

    g_object_unref (model);
}

gchar *
g_lo_menu_get_accelerator_from_item_in_section (GLOMenu *menu,
                                                gint     section,
                                                gint     position)
{
    g_return_val_if_fail (G_IS_LO_MENU (menu), nullptr);

    GVariant *accel_value = g_lo_menu_get_attribute_value_from_item_in_section (menu,
                                                                                section,
                                                                                position,
                                                                                G_LO_MENU_ATTRIBUTE_ACCELERATOR,
                                                                                G_VARIANT_TYPE_STRING);

    gchar *accel = nullptr;

    if (accel_value != nullptr)
    {
        accel = g_variant_dup_string (accel_value, nullptr);
        g_variant_unref (accel_value);
    }

    return accel;
}

void
g_lo_menu_set_command_to_item_in_section (GLOMenu     *menu,
                                          gint         section,
                                          gint         position,
                                          const gchar *command)
{
    g_return_if_fail (G_IS_LO_MENU (menu));

    GLOMenu *model = g_lo_menu_get_section (menu, section);

    g_return_if_fail (model != nullptr);

    GVariant *value;

    if (command != nullptr)
        value = g_variant_new_string (command);
    else
        value = nullptr;

    g_lo_menu_set_attribute_value (model, position, G_LO_MENU_ATTRIBUTE_COMMAND, value);

    // Notify the update.
    g_menu_model_items_changed (G_MENU_MODEL (model), position, 1, 1);

    g_object_unref (model);
}

gchar *
g_lo_menu_get_command_from_item_in_section (GLOMenu *menu,
                                            gint     section,
                                            gint     position)
{
    g_return_val_if_fail (G_IS_LO_MENU (menu), nullptr);

    GVariant *command_value = g_lo_menu_get_attribute_value_from_item_in_section (menu,
                                                                                  section,
                                                                                  position,
                                                                                  G_LO_MENU_ATTRIBUTE_COMMAND,
                                                                                  G_VARIANT_TYPE_STRING);

    gchar *command = nullptr;

    if (command_value != nullptr)
    {
        command = g_variant_dup_string (command_value, nullptr);
        g_variant_unref (command_value);
    }

    return command;
}

static void
g_lo_menu_set_link (GLOMenu     *menu,
                    gint         position,
                    const gchar *link,
                    GMenuModel  *model)
{
    g_return_if_fail (G_IS_LO_MENU (menu));
    g_return_if_fail (link != nullptr);
    g_return_if_fail (valid_attribute_name (link));

    if (position < 0 || o3tl::make_unsigned(position) >= menu->items->len)
        position = menu->items->len - 1;

    struct item menu_item = g_array_index (menu->items, struct item, position);

    if (model != nullptr)
        g_hash_table_insert (menu_item.links, g_strdup (link), g_object_ref (model));
    else
        g_hash_table_remove (menu_item.links, link);
}

void
g_lo_menu_insert_section (GLOMenu     *menu,
                          gint         position,
                          const gchar *label,
                          GMenuModel  *section)
{
    g_return_if_fail (G_IS_LO_MENU (menu));

    if (position < 0 || o3tl::make_unsigned(position) > menu->items->len)
        position = menu->items->len;

    struct item menu_item;

    g_lo_menu_struct_item_init(&menu_item);

    g_array_insert_val (menu->items, position, menu_item);

    g_lo_menu_set_label (menu, position, label);
    g_lo_menu_set_link (menu, position, G_MENU_LINK_SECTION, section);

    g_menu_model_items_changed (G_MENU_MODEL (menu), position, 0, 1);
}

void
g_lo_menu_new_section (GLOMenu     *menu,
                       gint         position,
                       const gchar *label)
{
    GMenuModel *section = G_MENU_MODEL (g_lo_menu_new());

    g_lo_menu_insert_section (menu, position, label, section);

    g_object_unref (section);
}

GLOMenu *
g_lo_menu_get_section (GLOMenu *menu,
                       gint section)
{
    g_return_val_if_fail (G_IS_LO_MENU (menu), nullptr);

    return G_LO_MENU (G_MENU_MODEL_CLASS (g_lo_menu_parent_class)
                      ->get_item_link (G_MENU_MODEL (menu), section, G_MENU_LINK_SECTION));
}

void
g_lo_menu_new_submenu_in_item_in_section (GLOMenu *menu,
                                          gint     section,
                                          gint     position)
{
    g_return_if_fail (G_IS_LO_MENU (menu));
    g_return_if_fail (0 <= section && o3tl::make_unsigned(section) < menu->items->len);

    GLOMenu* model = g_lo_menu_get_section (menu, section);

    g_return_if_fail (model != nullptr);

    if (0 <= position && o3tl::make_unsigned(position) < model->items->len) {
        GMenuModel* submenu = G_MENU_MODEL (g_lo_menu_new());

        g_lo_menu_set_link (model, position, G_MENU_LINK_SUBMENU, submenu);

        g_object_unref (submenu);

        g_menu_model_items_changed (G_MENU_MODEL (model), position, 1, 1);

    }
    g_object_unref (model);
}

GLOMenu *
g_lo_menu_get_submenu_from_item_in_section (GLOMenu *menu,
                                            gint     section,
                                            gint     position)
{
    g_return_val_if_fail (G_IS_LO_MENU (menu), nullptr);
    g_return_val_if_fail (0 <= section && o3tl::make_unsigned(section) < menu->items->len, nullptr);

    GLOMenu *model = g_lo_menu_get_section (menu, section);

    g_return_val_if_fail (model != nullptr, nullptr);

    GLOMenu *submenu = nullptr;

    if (0 <= position && o3tl::make_unsigned(position) < model->items->len)
        submenu = G_LO_MENU (G_MENU_MODEL_CLASS (g_lo_menu_parent_class)
                ->get_item_link (G_MENU_MODEL (model), position, G_MENU_LINK_SUBMENU));
        //submenu = g_menu_model_get_item_link (G_MENU_MODEL (model), position, G_MENU_LINK_SUBMENU);

    g_object_unref (model);

    return submenu;
}

void
g_lo_menu_set_submenu_action_to_item_in_section (GLOMenu     *menu,
                                                 gint         section,
                                                 gint         position,
                                                 const gchar *action)
{
    g_return_if_fail (G_IS_LO_MENU (menu));

    GMenuModel *model = G_MENU_MODEL (g_lo_menu_get_section (menu, section));

    g_return_if_fail (model != nullptr);

    GVariant *value;

    if (action != nullptr)
        value = g_variant_new_string (action);
    else
        value = nullptr;

    g_lo_menu_set_attribute_value (G_LO_MENU (model), position, G_LO_MENU_ATTRIBUTE_SUBMENU_ACTION, value);

    // Notify the update.
    g_menu_model_items_changed (model, position, 1, 1);

    g_object_unref (model);
}

static void
g_lo_menu_clear_item (struct item *menu_item)
{
    if (menu_item->attributes != nullptr)
        g_hash_table_unref (menu_item->attributes);
    if (menu_item->links != nullptr)
        g_hash_table_unref (menu_item->links);
}

void
g_lo_menu_remove (GLOMenu *menu,
                  gint     position)
{
    g_return_if_fail (G_IS_LO_MENU (menu));
    g_return_if_fail (0 <= position && o3tl::make_unsigned(position) < menu->items->len);

    g_lo_menu_clear_item (&g_array_index (menu->items, struct item, position));
    g_array_remove_index (menu->items, position);
    g_menu_model_items_changed (G_MENU_MODEL (menu), position, 1, 0);
}

void
g_lo_menu_remove_from_section (GLOMenu *menu,
                               gint     section,
                               gint     position)
{
    g_return_if_fail (G_IS_LO_MENU (menu));
    g_return_if_fail (0 <= section && o3tl::make_unsigned(section) < menu->items->len);

    GLOMenu *model = g_lo_menu_get_section (menu, section);

    g_return_if_fail (model != nullptr);

    g_lo_menu_remove (model, position);

    g_object_unref (model);
}

static void
g_lo_menu_finalize (GObject *object)
{
    GLOMenu *menu = G_LO_MENU (object);
    struct item *items;
    gint n_items;
    gint i;

    n_items = menu->items->len;
    items = reinterpret_cast<struct item *>(g_array_free (menu->items, FALSE));
    for (i = 0; i < n_items; i++)
        g_lo_menu_clear_item (&items[i]);
    g_free (items);

    G_OBJECT_CLASS (g_lo_menu_parent_class)
            ->finalize (object);
}

static void
g_lo_menu_init (GLOMenu *menu)
{
    menu->items = g_array_new (FALSEFALSEsizeof (struct item));
}

static void
g_lo_menu_class_init (GLOMenuClass *klass)
{
    GMenuModelClass *model_class = G_MENU_MODEL_CLASS (klass);
    GObjectClass *object_class = G_OBJECT_CLASS (klass);

    object_class->finalize = g_lo_menu_finalize;

    model_class->is_mutable = g_lo_menu_is_mutable;
    model_class->get_n_items = g_lo_menu_get_n_items;
    model_class->get_item_attributes = g_lo_menu_get_item_attributes;
    model_class->get_item_links = g_lo_menu_get_item_links;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=91 H=95 G=92

¤ Dauer der Verarbeitung: 0.9 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.