Commit b504ed88 authored by Jody Goldberg's avatar Jody Goldberg Committed by Jody Goldberg

clear the current plot. (graph_guru_select_plot) : fill in.

2001-09-29  Jody Goldberg <jgoldberg@home.com>

	* dialog-graph-guru.c (graph_guru_set_page) : clear the current plot.
	(graph_guru_select_plot) : fill in.
	(vector_state_new) : ditto.
	(vector_state_init) : ditto.
parent 5c1c69c8
2001-09-29 Jody Goldberg <jgoldberg@home.com>
* dialog-graph-guru.c (graph_guru_set_page) : clear the current plot.
(graph_guru_select_plot) : fill in.
(vector_state_new) : ditto.
(vector_state_init) : ditto.
2001-09-28 Almer S. Tigelaar <almer@gnome.org>
* dialog-cell-comment.c (dialog_cell_comment):
......
......@@ -31,22 +31,22 @@
#include "sheet-control-gui.h"
#include "sheet-object.h"
#include "dialogs.h"
#include "widgets/gnumeric-combo-text.h"
#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-i18n.h>
#include <gal/widgets/gtk-combo-text.h>
#include <gal/util/e-xml-utils.h>
typedef struct _GraphGuruState GraphGuruState;
typedef struct
{
GraphGuruState *state;
GraphGuruState *state;
xmlChar *element;
int index;
gboolean is_optional, is_shared;
GtkWidget *name_label;
GnumericExprEntry *entry;
gchar *name;
gboolean is_optional;
int index;
} VectorState;
struct _GraphGuruState
......@@ -76,9 +76,7 @@ struct _GraphGuruState
GtkWidget *selection_table;
GtkWidget *shared_separator;
struct {
GPtrArray *exprs;
} shared, unshared;
GPtrArray *shared, *unshared;
/* internal state */
int current_page, initial_page;
......@@ -106,6 +104,107 @@ graph_guru_clear_sample (GraphGuruState *state)
}
}
static void
vector_state_fill (VectorState *state, xmlNode *vector)
{
}
static void
vector_state_init (VectorState *vs, xmlNode *descriptor)
{
xmlChar *tmp;
char *name;
gboolean required;
if (vs->element != NULL)
xmlFree (vs->element);
vs->element = xmlGetProp (descriptor, "element");
required = e_xml_get_bool_prop_by_name_with_default (descriptor,
"required", FALSE);
tmp = xmlNodeGetContent (descriptor);
name = required ? g_strdup (tmp) : g_strdup_printf ("(%s)", tmp);
gtk_label_set_text (GTK_LABEL (vs->name_label), name);
xmlFree (tmp);
g_free (name);
gtk_widget_show (vs->name_label);
gtk_widget_show (GTK_WIDGET (vs->entry));
}
static gboolean
cb_graph_guru_entry_focus_in (GtkWidget *ignored0, GdkEventFocus *ignored1, VectorState *vs)
{
wbcg_set_entry (vs->state->wbcg, vs->entry);
return FALSE;
}
static VectorState *
vector_state_new (GraphGuruState *state, gboolean shared, int indx)
{
VectorState *vs;
GtkTable *table;
GtkWidget *alignment = gtk_alignment_new (1., .5, 0., 0.);
vs = g_new0 (VectorState, 1);
vs->state = state;
vs->index = indx;
vs->element = NULL;
vs->is_shared = shared;
table = GTK_TABLE (shared
? state->shared_series_details
: state->series_details);
vs->name_label = gtk_label_new ("");
gtk_container_add (GTK_CONTAINER (alignment), vs->name_label);
gtk_table_attach (table, alignment,
0, 1, indx, indx+1, GTK_FILL, 0, 5, 3);
vs->entry = GNUMERIC_EXPR_ENTRY (gnumeric_expr_entry_new (state->wbcg));
gnumeric_expr_entry_set_scg (vs->entry, state->scg);
gnumeric_expr_entry_set_flags (vs->entry,
GNUM_EE_ABS_COL|GNUM_EE_ABS_ROW, GNUM_EE_MASK);
gtk_table_attach (table, GTK_WIDGET (vs->entry),
1, 2, indx, indx+1, GTK_EXPAND|GTK_FILL, 0, 5, 3);
gnumeric_editable_enters (GTK_WINDOW (state->dialog),
GTK_EDITABLE (vs->entry));
/* FIXME : Do I really need focus-in ? is there something less draconian */
gtk_signal_connect (GTK_OBJECT (vs->entry),
"focus-in-event",
GTK_SIGNAL_FUNC (cb_graph_guru_entry_focus_in), vs);
return vs;
}
static void
vector_state_destroy (VectorState *vs, gboolean destroywidgets)
{
if (vs->element) {
xmlFree (vs->element);
vs->element = NULL;
}
if (destroywidgets) {
gtk_widget_destroy (GTK_WIDGET (vs->entry));
gtk_widget_destroy (GTK_WIDGET (vs->name_label));
}
g_free (vs);
}
static void
vector_state_array_shorten (GPtrArray *a, int len)
{
int i = a->len;
while (len < i--) {
vector_state_destroy (g_ptr_array_index (a, i), TRUE);
g_ptr_array_remove_index_fast (a, i);
}
}
static void
graph_guru_state_destroy (GraphGuruState *state)
{
......@@ -123,6 +222,22 @@ graph_guru_state_destroy (GraphGuruState *state)
state->gui = NULL;
}
if (state->shared != NULL) {
int i = state->shared->len;
while (i-- > 0)
vector_state_destroy (g_ptr_array_index (state->shared, i), FALSE);
g_ptr_array_free (state->shared, TRUE);
state->shared = NULL;
}
if (state->unshared != NULL) {
int i = state->unshared->len;
while (i-- > 0)
vector_state_destroy (g_ptr_array_index (state->unshared, i), FALSE);
g_ptr_array_free (state->unshared, TRUE);
state->unshared = NULL;
}
/* Handle window manger closing the dialog.
* This will be ignored if we are being destroyed differently.
*/
......@@ -179,7 +294,7 @@ graph_guru_select_series (GraphGuruState *s, xmlNode *xml)
name = graph_guru_series_name (s, xml);
s->updating = TRUE;
gtk_combo_text_set_text (GTK_COMBO_TEXT (s->series_selector), name);
gnm_combo_text_set_text (GNM_COMBO_TEXT (s->series_selector), name);
s->updating = FALSE;
if (s->current_series == NULL) {
......@@ -206,8 +321,9 @@ graph_guru_plot_name (GraphGuruState *s, xmlNode *plot)
static void
graph_guru_select_plot (GraphGuruState *s, xmlNode *xml)
{
xmlNode *series;
xmlNode *layout, *series;
char *name;
int shared, unshared;
if (s->updating)
return;
......@@ -216,12 +332,51 @@ graph_guru_select_plot (GraphGuruState *s, xmlNode *xml)
/* clear out the old */
if (s->current_plot != NULL) {
GtkComboText *ct = GTK_COMBO_TEXT (s->series_selector);
GnmComboText *ct = GNM_COMBO_TEXT (s->series_selector);
gtk_list_clear_items (GTK_LIST (ct->list), 0, -1);
}
s->current_plot = xml;
s->current_series = NULL;
/* Init the expr entries */
layout = e_xml_get_child_by_name (xml, "DataLayout");
g_return_if_fail (layout != NULL);
shared = unshared = 0;
for (layout = layout->xmlChildrenNode; layout; layout = layout->next) {
int indx;
gboolean is_shared;
GPtrArray *container;
VectorState *vs;
if (strcmp (layout->name, "Dimension"))
continue;
is_shared = e_xml_get_bool_prop_by_name_with_default (layout,
"shared", FALSE);
if (is_shared) {
container = s->shared;
indx = shared++;
} else {
container = s->unshared;
indx = unshared++;
}
if (indx >= (int)(container->len)) {
vs = vector_state_new (s, is_shared, indx);
g_ptr_array_add (container, vs);
} else
vs = g_ptr_array_index (container, indx);
vector_state_init (vs, layout);
}
vector_state_array_shorten (s->unshared, unshared);
vector_state_array_shorten (s->shared, shared);
if (shared > 0)
gtk_widget_show (s->shared_separator);
else
gtk_widget_hide (s->shared_separator);
/* Init lists of series */
series = e_xml_get_child_by_name (xml, "Data");
......@@ -231,7 +386,7 @@ graph_guru_select_plot (GraphGuruState *s, xmlNode *xml)
if (strcmp (series->name, "Series"))
continue;
name = graph_guru_series_name (s, series);
gtk_combo_text_add_item (GTK_COMBO_TEXT (s->series_selector),
gnm_combo_text_add_item (GNM_COMBO_TEXT (s->series_selector),
name, name);
g_free (name);
if (s->current_series == NULL)
......@@ -240,10 +395,13 @@ graph_guru_select_plot (GraphGuruState *s, xmlNode *xml)
s->updating = TRUE;
name = graph_guru_plot_name (s, xml);
gtk_combo_text_set_text (GTK_COMBO_TEXT (s->plot_selector), name);
gnm_combo_text_set_text (GNM_COMBO_TEXT (s->plot_selector), name);
g_free (name);
s->updating = FALSE;
gtk_widget_show_all (s->series_details);
gtk_widget_show_all (s->shared_series_details);
g_return_if_fail (s->current_series != NULL);
}
......@@ -271,7 +429,7 @@ graph_guru_init_data_page (GraphGuruState *s)
if (strcmp (plot->name, "Plot"))
continue;
name = graph_guru_plot_name (s, plot);
gtk_combo_text_add_item (GTK_COMBO_TEXT (s->plot_selector),
gnm_combo_text_add_item (GNM_COMBO_TEXT (s->plot_selector),
name, name);
g_free (name);
if (s->current_plot == NULL)
......@@ -295,6 +453,7 @@ graph_guru_set_page (GraphGuruState *state, int page)
case 0: name = _("Step 1 of 3: Select graph type");
prev_ok = FALSE;
graph_guru_clear_sample (state);
state->current_plot = NULL;
break;
case 1:
if (state->initial_page == 0) {
......@@ -390,8 +549,8 @@ graph_guru_selector_init (GraphGuruState *s, char const *name, int i,
GtkSignalFunc entry_activate,
GtkSignalFunc list_select)
{
GtkWidget *w = gtk_combo_text_new (TRUE);
GtkComboText *ct = GTK_COMBO_TEXT (w);
GtkWidget *w = gnm_combo_text_new (TRUE);
GnmComboText *ct = GNM_COMBO_TEXT (w);
gtk_table_attach_defaults (GTK_TABLE (s->selection_table),
w, 1, 2, i, i+1);
gtk_combo_box_set_title (GTK_COMBO_BOX (ct), _(name));
......@@ -475,6 +634,8 @@ dialog_graph_guru (WorkbookControlGUI *wbcg, GnmGraph *graph, int page)
state->control = CORBA_OBJECT_NIL;
state->xml_doc = NULL;
state->sample = NULL;
state->shared = g_ptr_array_new ();
state->unshared = g_ptr_array_new ();
state->current_page = -1;
state->current_plot = NULL;
state->current_series = NULL;
......
......@@ -151,8 +151,8 @@
<label_xalign>0</label_xalign>
<shadow_type>GTK_SHADOW_IN</shadow_type>
<child>
<padding>0</padding>
<expand>True</expand>
<padding>4</padding>
<expand>False</expand>
<fill>True</fill>
</child>
......@@ -172,7 +172,7 @@
<child>
<padding>0</padding>
<expand>False</expand>
<fill>False</fill>
<fill>True</fill>
</child>
<widget>
......@@ -324,11 +324,22 @@
</widget>
</widget>
<widget>
<class>GtkHSeparator</class>
<name>hseparator1</name>
<child>
<padding>7</padding>
<expand>False</expand>
<fill>False</fill>
</child>
</widget>
<widget>
<class>GtkTable</class>
<name>series_details</name>
<border_width>5</border_width>
<rows>1</rows>
<columns>1</columns>
<columns>2</columns>
<homogeneous>False</homogeneous>
<row_spacing>0</row_spacing>
<column_spacing>0</column_spacing>
......@@ -344,23 +355,24 @@
<name>shared_separator</name>
<child>
<padding>0</padding>
<expand>True</expand>
<fill>True</fill>
<expand>False</expand>
<fill>False</fill>
</child>
</widget>
<widget>
<class>GtkTable</class>
<name>shared_series_details</name>
<border_width>5</border_width>
<rows>1</rows>
<columns>1</columns>
<columns>2</columns>
<homogeneous>False</homogeneous>
<row_spacing>0</row_spacing>
<column_spacing>0</column_spacing>
<child>
<padding>0</padding>
<expand>True</expand>
<fill>True</fill>
<fill>False</fill>
</child>
</widget>
</widget>
......
2001-09-28 Jody Goldberg <jgoldberg@home.com>
* Makefile.am (libwidgets_a_SOURCES) : temporarily move gal's
gtk_combo_text here as gnm_combo_text. The original needs some
major work to make graph guru possible.
2001-08-20 Jody Goldberg <jgoldberg@home.com>
* Release 0.70
......
......@@ -22,4 +22,6 @@ libwidgets_a_SOURCES = \
gnumeric-dashed-canvas-line.c \
gnumeric-dashed-canvas-line.h \
gnumeric-expr-entry.c \
gnumeric-expr-entry.h
gnumeric-expr-entry.h \
gnumeric-combo-text.c \
gnumeric-combo-text.h
/*
* gtk-combo-text: A combo box for selecting from a list.
*/
#include <config.h>
#include <ctype.h>
#include <gtk/gtksignal.h>
#include <gtk/gtkentry.h>
#include <gtk/gtklist.h>
#include <gtk/gtkscrolledwindow.h>
#include "gnumeric-combo-text.h"
static GtkObjectClass *gnm_combo_text_parent_class;
static gboolean cb_pop_down (GtkWidget *w, GtkWidget *pop_down,
gpointer dummy);
static void list_unselect_cb (GtkWidget *list, GtkWidget *child,
gpointer data);
static void update_list_selection (GnmComboText *ct, const gchar *text);
static void
gnm_combo_text_destroy (GtkObject *object)
{
GnmComboText *ct = GNM_COMBO_TEXT (object);
if (ct->elements != NULL) {
g_hash_table_destroy (ct->elements);
ct->elements = NULL;
}
gtk_signal_disconnect_by_func (GTK_OBJECT (ct),
GTK_SIGNAL_FUNC (cb_pop_down), NULL);
gtk_signal_disconnect_by_func (GTK_OBJECT (ct->list),
GTK_SIGNAL_FUNC (list_unselect_cb),
(gpointer) ct);
(*gnm_combo_text_parent_class->destroy) (object);
}
static void
gnm_combo_text_class_init (GtkObjectClass *object_class)
{
object_class->destroy = &gnm_combo_text_destroy;
gnm_combo_text_parent_class = gtk_type_class (gtk_combo_box_get_type ());
}
static void
gnm_combo_text_init (GnmComboText *object)
{
}
GtkType
gnm_combo_text_get_type (void)
{
static GtkType type = 0;
if (!type){
GtkTypeInfo info = {
"GnmComboText",
sizeof (GnmComboText),
sizeof (GnmComboTextClass),
(GtkClassInitFunc) gnm_combo_text_class_init,
(GtkObjectInitFunc) gnm_combo_text_init,
NULL, /* reserved 1 */
NULL, /* reserved 2 */
(GtkClassInitFunc) NULL
};
type = gtk_type_unique (gtk_combo_box_get_type (), &info);
}
return type;
}
static gint
strcase_equal (gconstpointer v, gconstpointer v2)
{
return g_strcasecmp ((const gchar*) v, (const gchar*)v2) == 0;
}
/*
* a char* hash function from ASU
*
* This is cut/paste from gutils.c
* We've got to do this, because this widget will soon move out of the
* Gnumeric source and into a separate library.
*/
static guint
strcase_hash (gconstpointer v)
{
const unsigned char *s = (const unsigned char *)v;
const unsigned char *p;
guint h = 0, g;
for(p = s; *p != '\0'; p += 1) {
h = ( h << 4 ) + tolower (*p);
if ( ( g = h & 0xf0000000 ) ) {
h = h ^ (g >> 24);
h = h ^ g;
}
}
return h /* % M */;
}
/**
* gnm_combo_text_set_case_sensitive
* @combo_text: ComboText widget
* @val: make case sensitive if TRUE
*
* Specifies whether the text entered into the GtkEntry field and the text
* in the list items is case sensitive. Because the values are stored in a
* hash, it is not legal to change case sensitivity when the list contains
* elements.
*
* Returns: The function returns -1 if request could not be honored. On
* success, it returns 0.
*/
gint
gnm_combo_text_set_case_sensitive (GnmComboText *combo, gboolean val)
{
if (combo->elements
&& g_hash_table_size (combo->elements) > 0
&& val != combo->case_sensitive)
return -1;
else {
combo->case_sensitive = val;
if (val != combo->case_sensitive) {
GHashFunc hashfunc;
GCompareFunc comparefunc;
g_hash_table_destroy (combo->elements);
if (combo->case_sensitive) {
hashfunc = g_str_hash;
comparefunc = g_str_equal;
} else {
hashfunc = strcase_hash;
comparefunc = strcase_equal;
}
combo->elements = g_hash_table_new (hashfunc,
comparefunc);
}
return 0;
}
}
static void
entry_activate_cb (GtkWidget *entry, gpointer data)
{
GnmComboText *combo = GNM_COMBO_TEXT (data);
update_list_selection (combo,
gtk_entry_get_text (GTK_ENTRY (combo->entry)));
}
static void
list_select_cb (GtkWidget *list, GtkWidget *child, gpointer data)
{
GnmComboText *combo = GNM_COMBO_TEXT (data);
GtkEntry *entry = GTK_ENTRY (combo->entry);
gchar *value = (gchar*) gtk_object_get_data
(GTK_OBJECT (child), "value");
g_return_if_fail (entry && value);
if (combo->cached_entry == child)
combo->cached_entry = NULL;
gtk_entry_set_text (entry, value);
gtk_signal_handler_block_by_func (GTK_OBJECT (entry),
GTK_SIGNAL_FUNC (entry_activate_cb),
(gpointer) combo);
gtk_signal_emit_by_name (GTK_OBJECT (entry), "activate");
gtk_signal_handler_unblock_by_func (GTK_OBJECT (entry),
GTK_SIGNAL_FUNC (entry_activate_cb),
(gpointer) combo);
gtk_combo_box_popup_hide (GTK_COMBO_BOX (data));
}
static void
list_unselect_cb (GtkWidget *list, GtkWidget *child, gpointer data)
{
if (GTK_WIDGET_VISIBLE (list)) /* Undo interactive unselect */
gtk_list_select_child (GTK_LIST (list), child);
}
static void
cb_toggle (GtkWidget *child, gpointer data)
{
GnmComboText *ct = GNM_COMBO_TEXT (data);
gtk_list_select_child (GTK_LIST (ct->list), child);
}
void
gnm_combo_text_select_item (GnmComboText *ct, int elem)
{
gtk_list_select_item (GTK_LIST(ct->list), elem);
}
static void
update_list_selection (GnmComboText *ct, const gchar *text)
{
gpointer candidate;
GtkWidget *child;
gtk_signal_handler_block_by_func (GTK_OBJECT (ct->list),
GTK_SIGNAL_FUNC (list_select_cb),
(gpointer) ct);
gtk_signal_handler_block_by_func (GTK_OBJECT (ct->list),
GTK_SIGNAL_FUNC (list_unselect_cb),
(gpointer) ct);
gtk_list_unselect_all (GTK_LIST (ct->list));
candidate = g_hash_table_lookup (ct->elements, (gconstpointer) text);
if (candidate && GTK_IS_WIDGET (candidate)) {
child = GTK_WIDGET (candidate);
gtk_list_select_child (GTK_LIST (ct->list), child);
gtk_widget_grab_focus (child);
}
gtk_signal_handler_unblock_by_func (GTK_OBJECT (ct->list),
GTK_SIGNAL_FUNC (list_select_cb),
(gpointer) ct);
gtk_signal_handler_unblock_by_func (GTK_OBJECT (ct->list),
GTK_SIGNAL_FUNC (list_unselect_cb),
(gpointer) ct);
}
void
gnm_combo_text_set_text (GnmComboText *ct, const gchar *text)
{
gtk_entry_set_text (GTK_ENTRY (ct->entry), text);
update_list_selection (ct, text);
}
/*
* We can't just cache the old widget state on entry: If the pointer is
* dragged, we receive two enter-notify-events, and the original cached
* value would be overwritten with the GTK_STATE_ACTIVE we just set.
*
* However, we know that the gtklist only uses GTK_STATE_SELECTED and
* GTK_STATE_NORMAL. We're OK if we only cache those two.
*/
static gboolean
cb_enter (GtkWidget *w, GdkEventCrossing *event,
gpointer user)
{
GnmComboText *ct = user;
GtkStateType state = GTK_WIDGET_STATE (w);
if (state == GTK_STATE_NORMAL || state == GTK_STATE_SELECTED) {
ct->cached_entry = w;
ct->cache_mouse_state = state;
}
if (state != GTK_STATE_SELECTED)
gtk_widget_set_state (w, GTK_STATE_ACTIVE);
return TRUE;
}
static gboolean
cb_exit (GtkWidget *w, GdkEventCrossing *event,
gpointer user)
{
GnmComboText *ct = user;
if (ct->cached_entry == w)
gtk_widget_set_state (w, ct->cache_mouse_state);
return TRUE;
}
static gboolean
cb_pop_down (GtkWidget *w, GtkWidget *pop_down, gpointer dummy)
{
GnmComboText *ct = GNM_COMBO_TEXT (w);
if (ct->cached_entry)
gtk_widget_set_state (ct->cached_entry, ct->cache_mouse_state);
ct->cached_entry = NULL;
return FALSE;
}
static void
cb_remove_from_hash (GtkWidget *child, gpointer data)
{
GnmComboText *ct = GNM_COMBO_TEXT (data);
gchar *value;
if (ct->elements) {
value = gtk_object_get_data (GTK_OBJECT (child), "value");
g_hash_table_remove (ct->elements, value);
}
}
void
gnm_combo_text_add_item (GnmComboText *ct,
const gchar *item,
const gchar *value)
{
GtkWidget *listitem;
gchar *value_copy;
g_return_if_fail (item);
if (!value)
value = item;
value_copy = g_strdup (value);
listitem = gtk_list_item_new_with_label (item);
gtk_widget_show (listitem);
gtk_object_set_data_full (GTK_OBJECT (listitem), "value",
value_copy, g_free);
gtk_signal_connect (GTK_OBJECT (listitem), "enter-notify-event",
GTK_SIGNAL_FUNC (cb_enter),
(gpointer) ct);
gtk_signal_connect (GTK_OBJECT (listitem), "leave-notify-event",
GTK_SIGNAL_FUNC (cb_exit),
(gpointer) ct);
gtk_signal_connect (GTK_OBJECT (listitem), "toggle",
GTK_SIGNAL_FUNC (cb_toggle),
(gpointer) ct);
gtk_container_add (GTK_CONTAINER (ct->list),
listitem);
g_hash_table_insert (ct->elements, (gpointer)value_copy,
(gpointer) listitem);
gtk_signal_connect (GTK_OBJECT (listitem), "destroy",
GTK_SIGNAL_FUNC (cb_remove_from_hash),