Logo Search packages:      
Sourcecode: galeon version File versions

galeon-css-menu.c

/*
 *  Copyright (C) 2002  Ricardo Fernández Pascual
 *  Copyright (C) 2004  Crispin Flowerday
 *
 *  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, 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.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <glib/gi18n.h>

#include <gtk/gtkuimanager.h>
#include <gtk/gtkactiongroup.h>
#include <gtk/gtkradioaction.h>

#include "galeon-window.h"
#include "galeon-tab.h"
#include "galeon-embed-utils.h"
#include "galeon-css-menu.h"

#include "galeon-marshal.h"
#include "galeon-debug.h"
#include "gul-string.h"
#include "gul-gui.h"

/**
 * Private data
 */
#define GALEON_CSS_MENU_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
                               GALEON_TYPE_CSS_MENU, GaleonCssMenuPrivate))


struct _GaleonCssMenuPrivate
{
      GaleonWindow *window;
      GtkUIManager *merge;
      GaleonEmbed *embed;

      GtkActionGroup *item_action_group;
      guint merge_id;

      GtkActionGroup *menu_action_group;
      guint menu_merge_id;

      guint rebuild_timeout;
      gboolean block_signals;
};

enum
{
      PROP_0,
      PROP_WINDOW
};


G_DEFINE_TYPE (GaleonCssMenu, galeon_css_menu, G_TYPE_OBJECT);

static void galeon_css_menu_rebuild (GaleonCssMenu *menu);

#define CSS_MENU_PLACEHOLDER_PATH       "/menubar/View/ViewStylesMenuPlaceholder"
#define STYLESHEET_KEY                  "galeon-stylesheet"
#define USERSTYLE_KEY               "galeon-user-style"
#define REBUILD_TIMEOUT 700

#define MENU_ITEM_MAX_LENGTH 40

static void
activate_stylesheet_cb (GtkAction *action, GaleonCssMenu *menu)
{
      GaleonCssMenuPrivate *p = menu->priv;
      EmbedStyleSheet *style;

      if (menu->priv->block_signals) return;

      g_return_if_fail (GALEON_IS_EMBED (p->embed));

      style = g_object_get_data (G_OBJECT (action), STYLESHEET_KEY);

      if (style->type == STYLESHEET_USER)
      {
            EmbedStyleSheet *overrideStyle =
                  g_object_get_data(G_OBJECT(p->embed), USERSTYLE_KEY);
            if (overrideStyle)
            {
                  galeon_embed_remove_user_stylesheet(p->embed,
                                              overrideStyle);
            }
            galeon_embed_apply_user_stylesheet(p->embed, style->name,
                                       &overrideStyle);
            g_object_set_data_full(G_OBJECT(p->embed), USERSTYLE_KEY,
                                   overrideStyle,
                               (GDestroyNotify)galeon_embed_stylesheet_free);
      }
      else if (style->type == STYLESHEET_USER_NONE)
      {
            EmbedStyleSheet *overrideStyle =
                  g_object_get_data(G_OBJECT(p->embed), USERSTYLE_KEY);
            if (overrideStyle)
            {
                  galeon_embed_remove_user_stylesheet(p->embed,
                                              overrideStyle);
                  g_object_set_data(G_OBJECT(p->embed), USERSTYLE_KEY,
                                NULL);
            }
      }
      else
      {
            galeon_embed_set_stylesheet (p->embed, style);
      }
}

static GtkAction *
create_stylesheet_action (GaleonCssMenu *menu, EmbedStyleSheet *style, int num)
{
      GtkAction  *action;
      gchar *tooltip, *label, *shortened;
      gchar name[40];

      g_snprintf (name, sizeof (name), "GaleonCSS%dAction", num);

      shortened = gul_string_shorten (style->name, MENU_ITEM_MAX_LENGTH);
      label = gul_string_double_underscores (shortened);

      switch (style->type)
      {
      case STYLESHEET_NONE:
            tooltip = g_strdup (_("Render the page without using a style"));
            break;
      case STYLESHEET_BASIC:
            tooltip = g_strdup (_("Render the page using the default style"));
            break;
      case STYLESHEET_USER_NONE:
            tooltip = g_strdup (_("Do not apply a user style to the page"));
            break;
      case STYLESHEET_USER:
            tooltip = g_strdup_printf (_("Apply the user style from \"%s\" to the page"),
                            style->name);
            break;
      default:
            tooltip = g_strdup_printf (_("Render the page using the \"%s\" style"), 
                                 style->name);
            break;
      }

      action = g_object_new (GTK_TYPE_RADIO_ACTION,
                         "name", name,
                         "label", label,
                         "tooltip", tooltip,
                         NULL);

      g_object_set_data_full (G_OBJECT(action), STYLESHEET_KEY, style,
                        (GDestroyNotify)galeon_embed_stylesheet_free);

      g_signal_connect_object (action, "activate",
                         G_CALLBACK (activate_stylesheet_cb),
                         menu, 0);

      gtk_action_group_add_action (menu->priv->item_action_group, action);
      g_object_unref (action);

      g_free (label);
      g_free (tooltip);
      return action;
}

static void
galeon_css_menu_rebuild (GaleonCssMenu *menu)
{
      GaleonCssMenuPrivate *p = menu->priv;
      GList *stylesheets = NULL, *user_styles = NULL, *l;
      GtkAction *action;
      EmbedStyleSheet *current = NULL, *user_current = NULL;
      GSList *radio_group = NULL, *user_group = NULL;
      int count = 0;

      if (p->merge_id > 0)
      {
            gtk_ui_manager_remove_ui (p->merge, p->merge_id);
            gtk_ui_manager_ensure_update (p->merge);
            p->merge_id = 0;
      }

      if (p->item_action_group)
      {
            gtk_ui_manager_remove_action_group (p->merge, p->item_action_group);
            g_object_unref (p->item_action_group);
            p->item_action_group = NULL;
      }

      LOG ("Rebuilding stylesheet menu");

      stylesheets = galeon_embed_get_stylesheets (p->embed);

      current = galeon_embed_get_selected_stylesheet (p->embed);

      user_styles = galeon_embed_utils_get_user_stylesheets();

      user_current = g_object_get_data(G_OBJECT(p->embed), USERSTYLE_KEY);

      p->block_signals = TRUE;

      /* Create the new action group */
      p->item_action_group = 
            gtk_action_group_new ("StylesheetMenuDynamicActions");
      gtk_action_group_set_translation_domain (p->item_action_group, NULL);
      gtk_ui_manager_insert_action_group (p->merge, p->item_action_group, 0);

      p->merge_id = gtk_ui_manager_new_merge_id (p->merge);

      action = gtk_action_group_get_action (p->menu_action_group,
                                    "StyleMenuAction");
      g_object_set (G_OBJECT (action), "sensitive",
                    (stylesheets != NULL || user_styles != NULL), NULL);
      
      for (l = stylesheets; l ; l = l->next)
      {
            EmbedStyleSheet *style = (EmbedStyleSheet*) (l->data);
            action = create_stylesheet_action (menu, style, count++);

            gtk_ui_manager_add_ui (p->merge, p->merge_id,
                               CSS_MENU_PLACEHOLDER_PATH "/StyleMenu",
                               gtk_action_get_name (action),
                               gtk_action_get_name (action),
                               GTK_UI_MANAGER_MENUITEM, FALSE);

            /* Make sure all widgets are in the same radio_group */
            gtk_radio_action_set_group (GTK_RADIO_ACTION (action), radio_group);
            radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (action));

            gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), 
                                    galeon_embed_stylesheet_compare (style, current));
      }

      if (stylesheets && user_styles)
      {
            gtk_ui_manager_add_ui(p->merge, p->merge_id,
                              CSS_MENU_PLACEHOLDER_PATH "/StyleMenu",
                              "usersep", NULL,
                              GTK_UI_MANAGER_SEPARATOR, FALSE);
      }

      for (l = user_styles; l ; l = l->next)
      {
            EmbedStyleSheet *style = (EmbedStyleSheet*)(l->data);
            action = create_stylesheet_action(menu, style, count++);

            gtk_ui_manager_add_ui(p->merge, p->merge_id,
                              CSS_MENU_PLACEHOLDER_PATH "/StyleMenu",
                              gtk_action_get_name(action),
                              gtk_action_get_name(action),
                              GTK_UI_MANAGER_MENUITEM, FALSE);

            /* Make sure all widgets are in the same radio_gruop */
            gtk_radio_action_set_group(GTK_RADIO_ACTION(action), user_group);
            user_group = gtk_radio_action_get_group(GTK_RADIO_ACTION (action));

            gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), 
                                   galeon_embed_stylesheet_compare(style,
                                                           user_current));
      }

      /* Don't need to free the contents, they are held as weak ref's
       * against their action */
      g_list_free (stylesheets);
      galeon_embed_stylesheet_free (current);
      g_list_free(user_styles);

      p->block_signals = FALSE;

      gtk_ui_manager_ensure_update (p->merge);
}

static gboolean
galeon_css_menu_rebuild_timeout_cb (gpointer data)
{
      GaleonCssMenu *gm = data;
      GaleonCssMenuPrivate *p = gm->priv;
      LOG ("GaleonCssMenu rebuild timeout");

      p->rebuild_timeout = 0;

      galeon_css_menu_rebuild (data);
      return FALSE;
}

static void 
galeon_css_menu_rebuild_with_timeout (GaleonCssMenu *gm) 
{
      GaleonCssMenuPrivate *p = gm->priv;

      LOG ("galeon_css_menu_rebuild_with_timeout");

      if (p->rebuild_timeout)
      {
            g_source_remove (p->rebuild_timeout);
      }
      
      p->rebuild_timeout = g_timeout_add (REBUILD_TIMEOUT, 
                                  galeon_css_menu_rebuild_timeout_cb, gm);
}

static void
galeon_css_menu_rebuild_for_reload(GaleonCssMenu *gm)
{
      GaleonCssMenuPrivate *p = gm->priv;

      g_object_set_data(G_OBJECT(p->embed), USERSTYLE_KEY, NULL);

      galeon_css_menu_rebuild_with_timeout(gm);
}

static void
galeon_css_menu_set_embed (GaleonCssMenu *menu, GaleonEmbed *embed)
{
      GaleonCssMenuPrivate *p = menu->priv;

      if (p->embed)
      {
            g_signal_handlers_disconnect_matched (p->embed, G_SIGNAL_MATCH_DATA, 
                                          0, 0, NULL, NULL, menu);
            g_object_unref (p->embed);
      }

      p->embed = embed;
      if (p->embed)
      {
            g_object_ref (p->embed);
            g_signal_connect_object (p->embed, "ge_net_stop",
                               G_CALLBACK (galeon_css_menu_rebuild_for_reload),
                               menu, G_CONNECT_SWAPPED);
      }

      galeon_css_menu_rebuild_with_timeout (menu);
}


static void
embed_changed_cb (GaleonWindow *window, GaleonEmbed *old_embed, 
              GaleonEmbed *new_embed, GaleonCssMenu *menu)
{
      galeon_css_menu_set_embed (menu, new_embed);
}


static GtkActionEntry entries[] = {
      { "StyleMenuAction", NULL, N_("St_yles"), NULL,
        N_("Select a different style for this page"), NULL }
};
static guint n_entries = G_N_ELEMENTS(entries);

static void
galeon_css_menu_set_window (GaleonCssMenu *menu, GaleonWindow *window)
{
      GaleonCssMenuPrivate *p = menu->priv;
      GaleonEmbed *embed;
      GtkAction *action;

      p->window = window;
      
      /* Create the Action Group */
      p->merge = g_object_ref (GTK_UI_MANAGER (window->merge));
      menu->priv->menu_action_group = gtk_action_group_new ("CssMenuActions");
      gtk_action_group_set_translation_domain (menu->priv->menu_action_group, NULL);
      gtk_ui_manager_insert_action_group(p->merge, p->menu_action_group, 0);
      gtk_action_group_add_actions (p->menu_action_group, entries,
                              n_entries, window);

      action = gtk_action_group_get_action (p->menu_action_group, "StyleMenuAction");
      g_object_set (G_OBJECT (action), "hide_if_empty", FALSE, NULL);

      p->menu_merge_id = gtk_ui_manager_new_merge_id (p->merge);

      gtk_ui_manager_add_ui (p->merge, p->menu_merge_id,
                         CSS_MENU_PLACEHOLDER_PATH,
                         "StyleMenu",
                         "StyleMenuAction",
                         GTK_UI_MANAGER_MENU, FALSE);

      /* Attach the signals to the window */
      g_signal_connect_object (window, "active-embed-changed",
                         G_CALLBACK (embed_changed_cb),
                         menu, 0);
      embed = galeon_window_get_active_embed (window);

      galeon_css_menu_set_embed (menu, embed);
}


static void
galeon_css_menu_set_property (GObject *object,
                        guint prop_id,
                        const GValue *value,
                        GParamSpec *pspec)
{
      GaleonCssMenu *m = GALEON_CSS_MENU (object);

      switch (prop_id)
      {
      case PROP_WINDOW:
            {
                  galeon_css_menu_set_window 
                        (m, GALEON_WINDOW (g_value_get_object (value)));
            }
            break;
      default: 
            break;
      }
}

static void
galeon_css_menu_get_property (GObject *object,
                        guint prop_id,
                        GValue *value,
                        GParamSpec *pspec)
{
      GaleonCssMenu *m = GALEON_CSS_MENU (object);
      
      switch (prop_id)
      {
      case PROP_WINDOW:
            g_value_set_object (value, m->priv->window);
            break;
      default: 
            break;
      }
}


static void
galeon_css_menu_finalize_impl(GObject *o)
{
      GaleonCssMenu *gm = GALEON_CSS_MENU(o);
      GaleonCssMenuPrivate *p = gm->priv;

      LOG ("galeon_css_menu_finalize_impl");

      if (p->merge_id > 0)
      {
            gtk_ui_manager_remove_ui (p->merge, p->merge_id);
      }

      if (p->menu_merge_id > 0)
      {
            gtk_ui_manager_remove_ui (p->merge, p->menu_merge_id);
      }

      if (p->menu_action_group)
      {
            gtk_ui_manager_remove_action_group
                  (p->merge, p->menu_action_group);
            g_object_unref (p->menu_action_group);
      }

      if (p->item_action_group)
      {
            gtk_ui_manager_remove_action_group
                  (p->merge, p->item_action_group);
            g_object_unref (p->item_action_group);
      }

      if (p->rebuild_timeout)
      {
            g_source_remove (p->rebuild_timeout);
      }

      if (p->embed)
      {
            g_object_unref (p->embed);
      }

      gtk_ui_manager_ensure_update (p->merge);
      g_object_unref (p->merge);

      G_OBJECT_CLASS(galeon_css_menu_parent_class)->finalize (o);
}

static void 
galeon_css_menu_init(GaleonCssMenu *m)
{
      GaleonCssMenuPrivate *p = GALEON_CSS_MENU_GET_PRIVATE (m);
      m->priv = p;
}

static void
galeon_css_menu_class_init(GaleonCssMenuClass *klass)
{
      GObjectClass *object_class = G_OBJECT_CLASS (klass);

      object_class->set_property = galeon_css_menu_set_property;
      object_class->get_property = galeon_css_menu_get_property;
      object_class->finalize = galeon_css_menu_finalize_impl;

      g_object_class_install_property (object_class,
                                         PROP_WINDOW,
                                         g_param_spec_object ("GaleonWindow",
                                                              "GaleonWindow",
                                                              "Parent window",
                                                              GALEON_TYPE_WINDOW,
                                                              G_PARAM_READWRITE |
                                                G_PARAM_CONSTRUCT_ONLY));

      g_type_class_add_private (klass, sizeof (GaleonCssMenuPrivate));
}


GaleonCssMenu *
galeon_css_menu_new (GaleonWindow *window)
{
      GaleonCssMenu *ret = g_object_new (GALEON_TYPE_CSS_MENU, 
                                 "GaleonWindow", window, NULL);
      return ret;
}

Generated by  Doxygen 1.6.0   Back to index