Logo Search packages:      
Sourcecode: galeon version File versions

galeon-sidebar.c

/*
 *  Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
 *
 *  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.
 */

#include "galeon-sidebar.h"
#include "galeon-dialog.h"
#include "galeon-marshal.h"
#include "gul-state.h"

#include <string.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkframe.h>
#include <gtk/gtkarrow.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkbutton.h>
#include <gtk/gtkimage.h>
#include <gtk/gtkmenuitem.h>
#include <gtk/gtkpaned.h>
#include <gtk/gtkstock.h>
#include <libgnomeui/gnome-uidefs.h>

/* State paths */
#define STATE_SIDEBAR_PAGE   "Sidebar/current_page"

static void
galeon_sidebar_class_init (GaleonSidebarClass *klass);
static void
galeon_sidebar_init (GaleonSidebar *window);
static void
galeon_sidebar_finalize (GObject *object);

typedef struct
{
      char *id;
      char *title;
      gboolean can_remove;
      GtkWidget *item;
} GaleonSidebarPage;

#define GALEON_SIDEBAR_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
                               GALEON_TYPE_SIDEBAR, GaleonSidebarPrivate))


struct GaleonSidebarPrivate
{
      GtkWidget *content_frame;
      GtkWidget *title_frame;
      GtkWidget *title_menu;
      GtkWidget *title_button;
      GtkWidget *title_label;
      GtkWidget *title_hbox;
      GtkWidget *remove_button;
      GObject *content;
      GList *pages;
      GaleonSidebarPage *current;
};

enum
{
      PAGE_CHANGED,
      CLOSE_REQUESTED,
      REMOVE_REQUESTED,
      LAST_SIGNAL
};

static GObjectClass *parent_class = NULL;

static guint sidebar_signals[LAST_SIGNAL] = { 0 };

GType 
galeon_sidebar_get_type (void)
{
        static GType galeon_sidebar_type = 0;

        if (galeon_sidebar_type == 0)
        {
                static const GTypeInfo our_info =
                {
                        sizeof (GaleonSidebarClass),
                        NULL, /* base_init */
                        NULL, /* base_finalize */
                        (GClassInitFunc) galeon_sidebar_class_init,
                        NULL,
                        NULL, /* class_data */
                        sizeof (GaleonSidebar),
                        0, /* n_preallocs */
                        (GInstanceInitFunc) galeon_sidebar_init
                };

                galeon_sidebar_type = g_type_register_static (GTK_TYPE_VBOX,
                                                             "GaleonSidebar",
                                                             &our_info, 0);
        }

        return galeon_sidebar_type;
}

static void
galeon_sidebar_show (GtkWidget *widget)
{
      GaleonSidebar *sidebar = GALEON_SIDEBAR(widget);

      if (!sidebar->priv->current)
      {
            /* The setting of the initial page is in the sidebar as if 
             * you create a gtkmozembed object without ever 'realize'ing
             * it, when it is destoryed it will crash the program :(
             */
            char * page = gul_state_get_string (STATE_SIDEBAR_PAGE, NULL);
            if (page)
            {
                  galeon_sidebar_select_page (sidebar, page);
                  g_free (page);
            }
            else if (sidebar->priv->pages)
            {
                  galeon_sidebar_select_page (sidebar, 
                       ((GaleonSidebarPage *)sidebar->priv->pages->data)->id);
            }
      }

      GTK_WIDGET_CLASS (parent_class)->show (widget); 
}

static void
galeon_sidebar_size_allocate (GtkWidget *widget,
                              GtkAllocation *allocation)
{
      int width;
      GtkAllocation child_allocation;
      GaleonSidebar *sidebar = GALEON_SIDEBAR(widget);
      GtkWidget *frame = sidebar->priv->title_frame;
      GtkWidget *hbox = sidebar->priv->title_hbox;
      GtkRequisition child_requisition;
      
      GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
      
      gtk_widget_get_child_requisition (hbox, &child_requisition);
      width = child_requisition.width;
      
      child_allocation = frame->allocation;
      child_allocation.width = MAX (width, frame->allocation.width);
      
      gtk_widget_size_allocate (frame, &child_allocation);
}

static void
galeon_sidebar_class_init (GaleonSidebarClass *klass)
{
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
      GtkWidgetClass *widget_class;
      
      parent_class = g_type_class_peek_parent (klass);
      widget_class = (GtkWidgetClass*) klass;
      
        object_class->finalize = galeon_sidebar_finalize;
      
      widget_class->size_allocate = galeon_sidebar_size_allocate;
      widget_class->show = galeon_sidebar_show;
      
      sidebar_signals[PAGE_CHANGED] =
                g_signal_new ("page_changed",
                              G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_FIRST,
                              G_STRUCT_OFFSET (GaleonSidebarClass, page_changed),
                              NULL, NULL,
                              g_cclosure_marshal_VOID__STRING,
                              G_TYPE_NONE,
                              1,
                        G_TYPE_STRING);
      sidebar_signals[CLOSE_REQUESTED] =
                g_signal_new ("close_requested",
                              G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_FIRST,
                              G_STRUCT_OFFSET (GaleonSidebarClass, close_requested),
                              NULL, NULL,
                              g_cclosure_marshal_VOID__VOID,
                              G_TYPE_NONE,
                              0);
      sidebar_signals[REMOVE_REQUESTED] =
                g_signal_new ("remove_requested",
                              G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_FIRST,
                              G_STRUCT_OFFSET (GaleonSidebarClass, remove_requested),
                              NULL, NULL,
                              g_cclosure_marshal_VOID__STRING,
                              G_TYPE_NONE,
                              1,
                        G_TYPE_STRING);

      g_type_class_add_private (klass, sizeof (GaleonSidebarPrivate));
}

static void
popup_position_func (GtkMenu *menu,
                    int *x, 
                    int *y,
                    gboolean *push_in,
                    gpointer user_data)
{
       GtkWidget *button;

       button = GTK_WIDGET (user_data);
       
       gdk_window_get_origin (button->parent->window, x, y);
       *x += button->allocation.x;
       *y += button->allocation.y + button->allocation.height;

       *push_in = FALSE;
}


static int
title_button_press_cb (GtkWidget *item, GdkEventButton *event, gpointer data)
{
       GaleonSidebar *sidebar;
       
       sidebar = GALEON_SIDEBAR (data);

       gtk_menu_popup (GTK_MENU (sidebar->priv->title_menu),
                       NULL, NULL,
                       popup_position_func, sidebar->priv->title_button, 
                       event->button, event->time);

       return TRUE;
}

static void
close_clicked_cb (GtkWidget *button, GaleonSidebar *sidebar)
{
      g_signal_emit (G_OBJECT (sidebar), sidebar_signals[CLOSE_REQUESTED], 0);
}

static void
remove_clicked_cb (GtkWidget *button, GaleonSidebar *sidebar)
{
      g_return_if_fail (sidebar->priv->current != NULL);
      
      g_signal_emit (G_OBJECT (sidebar), sidebar_signals[REMOVE_REQUESTED], 0,
                   sidebar->priv->current->id);
}

static void
galeon_sidebar_init (GaleonSidebar *sidebar)
{
      GtkWidget *frame;
      GtkWidget *frame_hbox;
      GtkWidget *button_hbox;
      GtkWidget *close_button;
      GtkWidget *close_image;
      GtkWidget *remove_image;
      GtkWidget *remove_button;
      GtkWidget *arrow;
      
        sidebar->priv = GALEON_SIDEBAR_GET_PRIVATE (sidebar);
      sidebar->priv->content = NULL;
      sidebar->priv->pages = NULL;
      sidebar->priv->current = NULL;
            
      frame_hbox = gtk_hbox_new (FALSE, 0);
      
        sidebar->priv->title_button = gtk_button_new ();
        gtk_button_set_relief (GTK_BUTTON (sidebar->priv->title_button),
                               GTK_RELIEF_NONE);

      g_signal_connect (sidebar->priv->title_button, "button_press_event",
                          G_CALLBACK (title_button_press_cb),
                          sidebar);
       
        button_hbox = gtk_hbox_new (FALSE, 0);
        gtk_container_set_border_width (GTK_CONTAINER (button_hbox), 0);
       
        sidebar->priv->title_label = gtk_label_new ("");
       
        /* FIXME: Temp */
        gtk_widget_show (sidebar->priv->title_label);

        gtk_box_pack_start (GTK_BOX (button_hbox), 
                            sidebar->priv->title_label,
                            FALSE, FALSE, 0);
       
        arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_ETCHED_IN);
        gtk_widget_show (arrow);
        gtk_box_pack_end (GTK_BOX (button_hbox), arrow, FALSE, FALSE, 0);
       
        gtk_widget_show (button_hbox);
       
        gtk_container_add (GTK_CONTAINER (sidebar->priv->title_button),
                           button_hbox);

        sidebar->priv->title_menu = gtk_menu_new ();
        g_object_ref (sidebar->priv->title_menu);
        gtk_object_sink (GTK_OBJECT (sidebar->priv->title_menu));
        gtk_widget_show (sidebar->priv->title_button);
        gtk_widget_show (sidebar->priv->title_menu);

        gtk_box_pack_start (GTK_BOX (frame_hbox), 
                            sidebar->priv->title_button,
                            FALSE, FALSE, 0);

      /* Remove sidebar button */
      remove_image = gtk_image_new_from_stock (GTK_STOCK_DELETE, 
                                                 GTK_ICON_SIZE_SMALL_TOOLBAR);
        gtk_widget_show (remove_image);

      remove_button = gtk_button_new ();

      gtk_button_set_relief (GTK_BUTTON (remove_button), GTK_RELIEF_NONE);
      gtk_container_add (GTK_CONTAINER (remove_button), remove_image);

      g_signal_connect (remove_button, "clicked",
                          G_CALLBACK (remove_clicked_cb), 
                          sidebar);

        gtk_widget_show (remove_button);

      sidebar->priv->remove_button = remove_button;
      
      /* Close button */
        close_image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, 
                                                GTK_ICON_SIZE_SMALL_TOOLBAR);
        gtk_widget_show (close_image);

      close_button = gtk_button_new ();

      gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
      gtk_container_add (GTK_CONTAINER (close_button), close_image);

      g_signal_connect (close_button, "clicked",
                          G_CALLBACK (close_clicked_cb), 
                          sidebar);

        gtk_widget_show (close_button); 
       
        gtk_box_pack_end (GTK_BOX (frame_hbox), close_button,
                          FALSE, FALSE, 0);
      gtk_box_pack_end (GTK_BOX (frame_hbox), remove_button,
                          FALSE, FALSE, 0);
      sidebar->priv->title_hbox = frame_hbox;

        frame = gtk_frame_new (NULL);
        gtk_frame_set_shadow_type (GTK_FRAME (frame), 
                           GTK_SHADOW_ETCHED_IN);
        gtk_widget_show (frame);
      sidebar->priv->title_frame = frame;
 
        gtk_container_add (GTK_CONTAINER (frame), 
                     frame_hbox);

        gtk_widget_show (frame_hbox);

      gtk_box_pack_start (GTK_BOX (sidebar), frame,
                            FALSE, FALSE, 2);

        sidebar->priv->content_frame = gtk_vbox_new (FALSE, 0);
      gtk_widget_show (sidebar->priv->content_frame);
            
        gtk_box_pack_start (GTK_BOX (sidebar), sidebar->priv->content_frame,
                            TRUE, TRUE, 0);
}

static void
galeon_sidebar_finalize (GObject *object)
{
        GaleonSidebar *sidebar;

        g_return_if_fail (object != NULL);
        g_return_if_fail (GALEON_IS_SIDEBAR (object));

        sidebar = GALEON_SIDEBAR (object);

        g_return_if_fail (sidebar->priv != NULL);

        g_object_unref (sidebar->priv->title_menu);

      /* FIXME free pages list */


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

GtkWidget *
galeon_sidebar_new (void)
{
      return GTK_WIDGET (g_object_new (GALEON_TYPE_SIDEBAR, NULL));
}

static void
select_page (GaleonSidebar *sidebar, GaleonSidebarPage *page)
{
      sidebar->priv->current = page;

      gtk_label_set_text (GTK_LABEL (sidebar->priv->title_label),
                            page->title);
      gtk_widget_set_sensitive (GTK_WIDGET(sidebar->priv->remove_button),
                          page->can_remove);
      
      gul_state_set_string (STATE_SIDEBAR_PAGE, page->id);

      g_signal_emit (G_OBJECT (sidebar), sidebar_signals[PAGE_CHANGED], 0, 
                   page->id);
}

static void
title_menu_item_activated_cb (GtkWidget *item, GaleonSidebar *sidebar)
{
      GaleonSidebarPage *page;

      page = (GaleonSidebarPage *) g_object_get_data (G_OBJECT(item), "page");

      select_page (sidebar, page);
}

void
galeon_sidebar_add_page (GaleonSidebar *sidebar,
                   const char *title,
                   const char *page_id,
                   gboolean can_remove)
{
      GtkWidget *item;
      GaleonSidebarPage *page;

      page = g_new0 (GaleonSidebarPage, 1);     
      page->id = g_strdup (page_id);
      page->title = g_strdup (title);
      page->can_remove = can_remove;
      
        item = gtk_menu_item_new_with_label (title); 
      g_object_set_data (G_OBJECT(item), "page", (gpointer)page);
      g_signal_connect (G_OBJECT(item), "activate",
                    G_CALLBACK (title_menu_item_activated_cb),
                    sidebar); 
      gtk_menu_shell_append (GTK_MENU_SHELL(sidebar->priv->title_menu),
                               item);
        gtk_widget_show (item);

      page->item = item;
      
      sidebar->priv->pages = g_list_append (sidebar->priv->pages,
                                          (gpointer)page);
}

static gint 
page_compare_func (gconstpointer  a,
                   gconstpointer  b)
{
      GaleonSidebarPage *page = (GaleonSidebarPage *)a;

      return strcmp (page->id, (char*) b);
}

static GaleonSidebarPage *
galeon_sidebar_find_page_by_id (GaleonSidebar *sidebar,
                        const char *page_id)
{
      GList *l;
      
      l = g_list_find_custom (sidebar->priv->pages, page_id,
                        page_compare_func);
      if (!l) return NULL;
      
      return (GaleonSidebarPage *)l->data;
}

gboolean 
galeon_sidebar_remove_page (GaleonSidebar *sidebar,
                      const char *page_id)
{
      GaleonSidebarPage *page, *new_page;
      GList *l;

      page = galeon_sidebar_find_page_by_id (sidebar, page_id);
      g_return_val_if_fail (page != NULL, FALSE);

      sidebar->priv->pages = g_list_remove (sidebar->priv->pages,
                                          (gpointer)page);
      
      l = sidebar->priv->pages;
      new_page = (GaleonSidebarPage *)l->data ?
                 (GaleonSidebarPage *)l->data : NULL;

      if (page)
      {
            galeon_sidebar_select_page (sidebar, new_page->id);
      }

      gtk_widget_destroy (page->item);
      
      return TRUE;
}

gboolean 
galeon_sidebar_select_page (GaleonSidebar *sidebar,
                      const char *page_id)
{
      GaleonSidebarPage *page;

      page = galeon_sidebar_find_page_by_id (sidebar, page_id);
      g_return_val_if_fail (page != NULL, FALSE);
      
      select_page (sidebar, page);
      
      return FALSE;
}

void 
galeon_sidebar_set_content (GaleonSidebar *sidebar,
                      GObject *content)
{
      if (content == sidebar->priv->content)
      {
            return;
      }

      if (GTK_IS_WIDGET(sidebar->priv->content))
      {
            gtk_container_remove(GTK_CONTAINER(sidebar->priv->content_frame),
                             GTK_WIDGET(sidebar->priv->content));
      }
      else if (GALEON_IS_DIALOG(sidebar->priv->content))
      {
            galeon_dialog_remove_embedded (GALEON_DIALOG(sidebar->priv->content));
      }

      sidebar->priv->content = content;

      if (GTK_IS_WIDGET(content))
      {
            gtk_container_add (GTK_CONTAINER(sidebar->priv->content_frame),
                           GTK_WIDGET(content));
      }
      else if (GALEON_IS_DIALOG(content))
      {
            galeon_dialog_show_embedded (GALEON_DIALOG(content),
                                   sidebar->priv->content_frame);
      }
}

Generated by  Doxygen 1.6.0   Back to index