/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* e-minicard-view-widget.c
* Copyright (C) 2000 Ximian, Inc.
* Author: Chris Lahey <clahey@ximian.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* 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 library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <config.h>
#include <gtk/gtksignal.h>
#include <gal/widgets/e-canvas-background.h>
#include <gal/widgets/e-canvas.h>
#include <libgnome/gnome-i18n.h>
#include "eab-marshal.h"
#include "e-minicard-view-widget.h"
static void e_minicard_view_widget_init (EMinicardViewWidget *widget);
static void e_minicard_view_widget_class_init (EMinicardViewWidgetClass *klass);
static void e_minicard_view_widget_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
static void e_minicard_view_widget_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
static void e_minicard_view_widget_dispose (GObject *object);
static void e_minicard_view_widget_reflow (ECanvas *canvas);
static void e_minicard_view_widget_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
static void e_minicard_view_widget_style_set (GtkWidget *widget, GtkStyle *previous_style);
static void e_minicard_view_widget_realize (GtkWidget *widget);
static gboolean e_minicard_view_widget_real_focus_in_event (GtkWidget *widget, GdkEventFocus *event);
static ECanvasClass *parent_class = NULL;
/* The arguments we take */
enum {
PROP_0,
PROP_BOOK,
PROP_QUERY,
PROP_EDITABLE,
PROP_COLUMN_WIDTH
};
enum {
SELECTION_CHANGE,
COLUMN_WIDTH_CHANGED,
RIGHT_CLICK,
LAST_SIGNAL
};
static guint signals [LAST_SIGNAL] = {0, };
GType
e_minicard_view_widget_get_type (void)
{
static GType type = 0;
if (!type) {
static const GTypeInfo info = {
sizeof (EMinicardViewWidgetClass),
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) e_minicard_view_widget_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (EMinicardViewWidget),
0, /* n_preallocs */
(GInstanceInitFunc) e_minicard_view_widget_init,
};
type = g_type_register_static (e_canvas_get_type (), "EMinicardViewWidget", &info, 0);
}
return type;
}
static void
e_minicard_view_widget_class_init (EMinicardViewWidgetClass *klass)
{
GObjectClass *object_class;
GtkWidgetClass *widget_class;
ECanvasClass *canvas_class;
object_class = (GObjectClass*) klass;
widget_class = GTK_WIDGET_CLASS (klass);
canvas_class = E_CANVAS_CLASS (klass);
parent_class = gtk_type_class (e_canvas_get_type ());
object_class->set_property = e_minicard_view_widget_set_property;
object_class->get_property = e_minicard_view_widget_get_property;
object_class->dispose = e_minicard_view_widget_dispose;
g_object_class_install_property (object_class, PROP_BOOK,
g_param_spec_object ("book",
_("Book"),
/*_( */"XXX blurb" /*)*/,
E_TYPE_BOOK,
G_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_QUERY,
g_param_spec_string ("query",
_("Query"),
/*_( */"XXX blurb" /*)*/,
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_EDITABLE,
g_param_spec_boolean ("editable",
_("Editable"),
/*_( */"XXX blurb" /*)*/,
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_COLUMN_WIDTH,
g_param_spec_double ("column_width",
_("Column Width"),
/*_( */"XXX blurb" /*)*/,
0.0, G_MAXDOUBLE, 150.0,
G_PARAM_READWRITE));
signals [SELECTION_CHANGE] =
g_signal_new ("selection_change",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EMinicardViewWidgetClass, selection_change),
NULL, NULL,
eab_marshal_NONE__NONE,
G_TYPE_NONE, 0);
signals [COLUMN_WIDTH_CHANGED] =
g_signal_new ("column_width_changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EMinicardViewWidgetClass, column_width_changed),
NULL, NULL,
eab_marshal_NONE__DOUBLE,
G_TYPE_NONE, 1, G_TYPE_DOUBLE);
signals [RIGHT_CLICK] =
g_signal_new ("right_click",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EMinicardViewWidgetClass, right_click),
NULL, NULL,
eab_marshal_INT__POINTER,
G_TYPE_INT, 1, G_TYPE_POINTER);
widget_class->style_set = e_minicard_view_widget_style_set;
widget_class->realize = e_minicard_view_widget_realize;
widget_class->size_allocate = e_minicard_view_widget_size_allocate;
widget_class->focus_in_event = e_minicard_view_widget_real_focus_in_event;
canvas_class->reflow = e_minicard_view_widget_reflow;
klass->selection_change = NULL;
klass->column_width_changed = NULL;
klass->right_click = NULL;
}
static void
e_minicard_view_widget_init (EMinicardViewWidget *view)
{
view->emv = NULL;
view->book = NULL;
view->query = NULL;
view->editable = FALSE;
view->column_width = 150;
}
GtkWidget *
e_minicard_view_widget_new (EAddressbookReflowAdapter *adapter)
{
EMinicardViewWidget *widget = E_MINICARD_VIEW_WIDGET (g_object_new (e_minicard_view_widget_get_type (), NULL));
widget->adapter = adapter;
g_object_ref (widget->adapter);
return GTK_WIDGET (widget);
}
static void
e_minicard_view_widget_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
EMinicardViewWidget *emvw;
emvw = E_MINICARD_VIEW_WIDGET (object);
switch (prop_id){
case PROP_BOOK:
if (emvw->book)
g_object_unref (emvw->book);
if (g_value_get_object (value)) {
emvw->book = E_BOOK(g_value_get_object (value));
if (emvw->book)
g_object_ref(emvw->book);
} else
emvw->book = NULL;
if (emvw->emv)
g_object_set(emvw->emv,
"book", emvw->book,
NULL);
break;
case PROP_QUERY:
emvw->query = g_strdup(g_value_get_string (value));
if (emvw->emv)
g_object_set(emvw->emv,
"query", emvw->query,
NULL);
break;
case PROP_EDITABLE:
emvw->editable = g_value_get_boolean (value);
if (emvw->emv)
g_object_set (emvw->emv,
"editable", emvw->editable,
NULL);
break;
case PROP_COLUMN_WIDTH:
emvw->column_width = g_value_get_double (value);
if (emvw->emv) {
g_object_set (emvw->emv,
"column_width", emvw->column_width,
NULL);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
e_minicard_view_widget_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
EMinicardViewWidget *emvw;
emvw = E_MINICARD_VIEW_WIDGET (object);
switch (prop_id) {
case PROP_BOOK:
g_value_set_object (value, emvw->book);
break;
case PROP_QUERY:
g_value_set_string (value, emvw->query);
break;
case PROP_EDITABLE:
g_value_set_boolean (value, emvw->editable);
break;
case PROP_COLUMN_WIDTH:
g_value_set_double (value, emvw->column_width);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
e_minicard_view_widget_dispose (GObject *object)
{
EMinicardViewWidget *view = E_MINICARD_VIEW_WIDGET(object);
if (view->book) {
g_object_unref (view->book);
view->book = NULL;
}
if (view->query) {
g_free(view->query);
view->query = NULL;
}
if (view->adapter) {
g_object_unref (view->adapter);
view->adapter = NULL;
}
if (G_OBJECT_CLASS(parent_class)->dispose)
G_OBJECT_CLASS(parent_class)->dispose (object);
}
static void
selection_change (ESelectionModel *esm, EMinicardViewWidget *widget)
{
g_signal_emit (widget,
signals [SELECTION_CHANGE], 0);
}
static void
selection_row_change (ESelectionModel *esm, int row, EMinicardViewWidget *widget)
{
gboolean selected = e_selection_model_is_row_selected (esm, row);
/* we only handle the selected case here */
if (!selected)
return;
selection_change (esm, widget);
}
static void
column_width_changed (ESelectionModel *esm, double width, EMinicardViewWidget *widget)
{
g_signal_emit (widget,
signals [COLUMN_WIDTH_CHANGED], 0, width);
}
static guint
right_click (EMinicardView *view, GdkEvent *event, EMinicardViewWidget *widget)
{
guint ret_val;
g_signal_emit (widget,
signals [RIGHT_CLICK], 0,
event, &ret_val);
return ret_val;
}
static void
e_minicard_view_widget_style_set (GtkWidget *widget, GtkStyle *previous_style)
{
EMinicardViewWidget *view = E_MINICARD_VIEW_WIDGET(widget);
if (view->background)
gnome_canvas_item_set (view->background,
"fill_color_gdk", &widget->style->base[GTK_STATE_NORMAL],
NULL );
if (GTK_WIDGET_CLASS(parent_class)->style_set)
GTK_WIDGET_CLASS(parent_class)->style_set (widget, previous_style);
}
static void
e_minicard_view_widget_realize (GtkWidget *widget)
{
EMinicardViewWidget *view = E_MINICARD_VIEW_WIDGET(widget);
GtkStyle *style = gtk_widget_get_style (widget);
view->background = gnome_canvas_item_new(gnome_canvas_root( GNOME_CANVAS(view) ),
e_canvas_background_get_type(),
"fill_color_gdk", &style->base[GTK_STATE_NORMAL],
NULL );
view->emv = gnome_canvas_item_new(
gnome_canvas_root( GNOME_CANVAS(view) ),
e_minicard_view_get_type(),
"height", (double) 100,
"minimum_width", (double) 100,
"adapter", view->adapter,
"column_width", view->column_width,
NULL );
g_signal_connect (E_REFLOW(view->emv)->selection,
"selection_changed",
G_CALLBACK (selection_change), view);
g_signal_connect (E_REFLOW(view->emv)->selection,
"selection_row_changed",
G_CALLBACK (selection_row_change), view);
g_signal_connect (view->emv,
"column_width_changed",
G_CALLBACK (column_width_changed), view);
g_signal_connect (view->emv,
"right_click",
G_CALLBACK (right_click), view);
if (GTK_WIDGET_CLASS(parent_class)->realize)
GTK_WIDGET_CLASS(parent_class)->realize (widget);
}
static void
e_minicard_view_widget_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
{
if (GTK_WIDGET_CLASS(parent_class)->size_allocate)
GTK_WIDGET_CLASS(parent_class)->size_allocate (widget, allocation);
if (GTK_WIDGET_REALIZED(widget)) {
double width;
EMinicardViewWidget *view = E_MINICARD_VIEW_WIDGET(widget);
gnome_canvas_item_set( view->emv,
"height", (double) allocation->height,
NULL );
gnome_canvas_item_set( view->emv,
"minimum_width", (double) allocation->width,
NULL );
g_object_get(view->emv,
"width", &width,
NULL);
width = MAX(width, allocation->width);
gnome_canvas_set_scroll_region (GNOME_CANVAS (view), 0, 0, width - 1, allocation->height - 1);
}
}
static void
e_minicard_view_widget_reflow(ECanvas *canvas)
{
double width;
EMinicardViewWidget *view = E_MINICARD_VIEW_WIDGET(canvas);
if (E_CANVAS_CLASS(parent_class)->reflow)
E_CANVAS_CLASS(parent_class)->reflow (canvas);
g_object_get(view->emv,
"width", &width,
NULL);
width = MAX(width, GTK_WIDGET(canvas)->allocation.width);
gnome_canvas_set_scroll_region(GNOME_CANVAS(canvas), 0, 0, width - 1, GTK_WIDGET(canvas)->allocation.height - 1);
}
ESelectionModel *
e_minicard_view_widget_get_selection_model (EMinicardViewWidget *view)
{
if (view->emv)
return E_SELECTION_MODEL (E_REFLOW (view->emv)->selection);
else
return NULL;
}
EMinicardView *
e_minicard_view_widget_get_view (EMinicardViewWidget *view)
{
if (view->emv)
return E_MINICARD_VIEW (view->emv);
else
return NULL;
}
static gboolean
e_minicard_view_widget_real_focus_in_event(GtkWidget *widget, GdkEventFocus *event)
{
GnomeCanvas *canvas;
EMinicardViewWidget *view;
canvas = GNOME_CANVAS (widget);
view = E_MINICARD_VIEW_WIDGET(widget);
if (!canvas->focused_item) {
EReflow *reflow = E_REFLOW (view->emv);
if (reflow->count) {
int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), 0);
if (unsorted != -1)
canvas->focused_item = reflow->items [unsorted];
}
}
if (GTK_WIDGET_CLASS(parent_class)->focus_in_event)
return GTK_WIDGET_CLASS(parent_class)->focus_in_event (widget, event);
return FALSE;
}