[Gnucash-changes] Forgot directory, files.

Joshua Sled jsled at cvs.gnucash.org
Thu Feb 10 20:33:16 EST 2005


Log Message:
-----------
Forgot directory, files.

Tags:
----
g2-gog-integ

Added Files:
-----------
    gnucash/lib/goffice/split/widgets:
        Makefile.am
        widget-font-selector.h
        widget-format-selector.c
        widget-format-selector.h

Revision Data
-------------
--- /dev/null
+++ lib/goffice/split/widgets/widget-format-selector.c
@@ -0,0 +1,1199 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/**
+ * widget-number-format-selector.c:  Implements a widget to select number format.
+ *
+ * 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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ **/
+
+#include <config.h>
+#include "widget-format-selector.h"
+
+#include <glib/gi18n.h>
+
+#include <format.h>
+#include <mstyle.h>
+#include <style-color.h>
+//#include <sheet.h>
+#include <value.h>
+
+#include <goffice/gui-utils/go-combo-text.h>
+
+#include <gtk/gtksizegroup.h>
+#include <gtk/gtktreeview.h>
+#include <gtk/gtktreeselection.h>
+#include <gtk/gtkspinbutton.h>
+#include <gtk/gtktogglebutton.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtkliststore.h>
+#include <gtk/gtkhbox.h>
+#include <gsf/gsf-impl-utils.h>
+
+#include <string.h>
+#include <locale.h>
+
+/* The maximum number of chars in the formatting sample */
+#define FORMAT_PREVIEW_MAX 25
+
+#define SETUP_LOCALE_SWITCH char *oldlocale = NULL
+
+#define START_LOCALE_SWITCH						\
+  do {									\
+	if (nfs->locale) {						\
+		currency_date_format_shutdown ();			\
+		oldlocale = g_strdup (setlocale (LC_ALL, NULL));	\
+		gnm_setlocale (LC_ALL, nfs->locale);		\
+		currency_date_format_init ();				\
+	}								\
+  } while (0)
+
+#define END_LOCALE_SWITCH						\
+  do {									\
+	if (oldlocale) {						\
+		currency_date_format_shutdown ();			\
+		gnm_setlocale (LC_ALL, oldlocale);			\
+		g_free (oldlocale);					\
+		currency_date_format_init ();				\
+	}								\
+  } while (0)
+
+#define FMT_CUSTOM ((FormatFamily)(FMT_SPECIAL + 1))
+
+/*Format Categories*/
+static char const *const format_category_names[] = {
+	N_("General"),
+	N_("Number"),
+	N_("Currency"),
+	N_("Accounting"),
+	N_("Date"),
+	N_("Time"),
+	N_("Percentage"),
+	N_("Fraction"),
+	N_("Scientific"),
+	N_("Text"),
+	N_("Special"),
+	N_("Custom"),
+	NULL
+};
+
+/* The available format widgets */
+typedef enum {
+	F_GENERAL_EXPLANATION,
+	F_NUMBER_EXPLANATION,
+	F_CURRENCY_EXPLANATION,
+	F_ACCOUNTING_EXPLANATION,
+	F_DATE_EXPLANATION,
+	F_TIME_EXPLANATION,
+	F_PERCENTAGE_EXPLANATION,
+	F_FRACTION_EXPLANATION,
+	F_SCIENTIFIC_EXPLANATION,
+	F_TEXT_EXPLANATION,
+	F_SPECIAL_EXPLANATION,
+	F_CUSTOM_EXPLANATION,
+
+	F_SEPARATOR,
+	F_SYMBOL_LABEL,		F_SYMBOL,
+	F_ENTRY,
+	F_LIST_LABEL,		F_LIST_SCROLL,		F_LIST,
+	F_DECIMAL_SPIN,	
+	F_NEGATIVE_LABEL,	F_NEGATIVE_SCROLL,	F_NEGATIVE,
+	F_DECIMAL_LABEL,	F_CODE_LABEL,	F_SYMBOL_BOX,
+	F_DECIMAL_BOX,	F_CODE_BOX,	F_MAX_WIDGET
+} FormatWidget;
+
+struct  _NumberFormatSelector {
+	GtkHBox   box;
+	GladeXML *gui;
+
+	GnmValue *value;
+	char	 *locale;
+
+	gboolean  enable_edit;
+
+	GnmDateConventions const *date_conv;
+
+	struct {
+		GtkTextView	*preview;
+		GtkWidget	*preview_box;
+		GtkTextBuffer	*preview_buffer;
+
+		GtkWidget	*widget[F_MAX_WIDGET];
+		GtkWidget	*menu;
+		GtkTreeModel	*menu_model;
+		GtkSizeGroup    *size_group;
+
+		struct {
+			GtkTreeView 		*view;
+			GtkListStore		*model;
+			GtkTreeSelection 	*selection;
+		} negative_types;
+
+		struct {
+			GtkTreeView	 *view;
+			GtkListStore	 *model;
+			GtkTreeSelection *selection;
+		} formats;
+
+		gulong          entry_changed_id;
+		GnmFormat	*spec;
+		gint		current_type;
+		int		num_decimals;
+		int		negative_format;
+		int		currency_index;
+		gboolean	use_separator;
+	} format;
+};
+
+typedef struct {
+	GtkHBoxClass parent_class;
+
+	gboolean (*number_format_changed) (NumberFormatSelector *nfs, const char *fmt);
+} NumberFormatSelectorClass;
+
+static GtkHBoxClass *nfs_parent_class;
+
+/* Signals we emit */
+enum {
+	NUMBER_FORMAT_CHANGED,
+	LAST_SIGNAL
+};
+
+static guint nfs_signals[LAST_SIGNAL] = { 0 };
+
+static void format_entry_set_text (NumberFormatSelector *nfs, gchar *text);
+
+static void
+generate_format (NumberFormatSelector *nfs)
+{
+	FormatFamily const page = nfs->format.current_type;
+	GnmFormat *new_format;
+
+	/* 
+	 * It is a strange idea not to reuse FormatCharacteristics
+	 * in this file, so build one.
+	 */
+	FormatCharacteristics format = nfs->format.spec->family_info;
+	format.thousands_sep = nfs->format.use_separator;
+	format.num_decimals = nfs->format.num_decimals;
+	format.negative_fmt = nfs->format.negative_format;
+	format.currency_symbol_index = nfs->format.currency_index;
+
+	new_format = style_format_build (page, &format);
+	if (new_format) {
+		char *tmp = style_format_as_XL (new_format, TRUE);
+		format_entry_set_text (nfs, tmp);
+		g_free (tmp);
+	}
+
+	style_format_unref (new_format);
+}
+
+static void
+draw_format_preview (NumberFormatSelector *nfs, gboolean regen_format)
+{
+	gchar		*preview;
+	GnmFormat	*sf = NULL;
+	GnmColor	*c = NULL;
+
+	if (regen_format)
+		generate_format (nfs);
+
+	/* Nothing to sample. */
+	if (nfs->value == NULL)
+		return;
+
+	sf = nfs->format.spec;
+
+	if (sf == NULL || nfs->value == NULL)
+		return;
+
+	if (style_format_is_general (sf) &&
+	    VALUE_FMT (nfs->value) != NULL)
+		sf = VALUE_FMT (nfs->value);
+
+	preview = format_value (sf, nfs->value, &c, -1, nfs->date_conv);
+	if (strlen (preview) > FORMAT_PREVIEW_MAX)
+		strcpy (&preview[FORMAT_PREVIEW_MAX - 5], " ...");
+
+	gtk_text_buffer_set_text (nfs->format.preview_buffer, preview, -1);
+	if (c != NULL) {
+		gtk_widget_modify_text (GTK_WIDGET(nfs->format.preview), 
+					GTK_STATE_NORMAL, &(c->color));
+		style_color_unref (c);
+	} else {
+		GdkColor color;
+		gdk_color_parse ("black", &color);
+		gtk_widget_modify_text (GTK_WIDGET(nfs->format.preview), 
+					GTK_STATE_NORMAL, &color);	
+	}
+
+	g_free (preview);
+}
+
+static void
+fillin_negative_samples (NumberFormatSelector *nfs)
+{
+	static char const *const decimals = "098765432109876543210987654321";
+	static char const *const formats[4] = {
+		"-%s%s3%s210%s%s%s%s",
+		"%s%s3%s210%s%s%s%s",
+		"(%s%s3%s210%s%s%s%s)",
+		"(%s%s3%s210%s%s%s%s)"
+	};
+	int const n = 30 - nfs->format.num_decimals;
+
+	FormatFamily const page = nfs->format.current_type;
+	char const *space_b = "", *currency_b;
+	char const *space_a = "", *currency_a;
+	const char *decimal;
+	const char *thousand_sep;
+	int i;
+	GtkTreeIter  iter;
+	GtkTreePath *path;
+	gboolean more;
+	SETUP_LOCALE_SWITCH;
+
+	g_return_if_fail (page == FMT_NUMBER || page == FMT_CURRENCY);
+	g_return_if_fail (nfs->format.num_decimals <= 30);
+
+	START_LOCALE_SWITCH;
+		
+	if (nfs->format.use_separator)
+		thousand_sep = format_get_thousand ()->str;
+	else
+		thousand_sep = "";
+	if (nfs->format.num_decimals > 0)
+		decimal = format_get_decimal ()->str;
+	else
+		decimal = "";
+
+	if (page == FMT_CURRENCY) {
+		currency_b = (const gchar *)currency_symbols[nfs->format.currency_index].symbol;
+		/*
+		 * FIXME : This should be better hidden.
+		 * Ideally the render would do this for us.
+		 */
+		if (currency_b[0] == '[' && currency_b[1] == '$') {
+			char const *end = strchr (currency_b+2, '-');
+			if (end == NULL)
+				end = strchr (currency_b+2, ']');
+			currency_b = g_strndup (currency_b+2, end-currency_b-2);
+		} else
+			currency_b = g_strdup (currency_b);
+
+		if (currency_symbols[nfs->format.currency_index].has_space)
+			space_b = " ";
+
+		if (!currency_symbols[nfs->format.currency_index].precedes) {
+			currency_a = currency_b;
+			currency_b = "";
+			space_a = space_b;
+			space_b = "";
+		} else {
+			currency_a = "";
+		}
+	} else
+		currency_a = currency_b = "";
+
+	more = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (nfs->format.negative_types.model), &iter);
+	for (i = 0 ; i < 4; i++) {
+		char *buf = g_strdup_printf (formats[i],
+					     currency_b, space_b, thousand_sep, decimal,
+					     decimals + n, space_a, currency_a);
+		if (!more)
+			gtk_list_store_append (nfs->format.negative_types.model, &iter);
+		gtk_list_store_set (nfs->format.negative_types.model, &iter,
+				    0, i,
+				    1, buf,
+				    2, (i % 2) ? "red" : NULL,
+				    -1);
+		if (more)
+			more = gtk_tree_model_iter_next (GTK_TREE_MODEL (nfs->format.negative_types.model),
+							 &iter);
+
+		g_free (buf);
+	}
+
+	/* If non empty then free the string */
+	if (*currency_a)
+		g_free ((char*)currency_a);
+	if (*currency_b)
+		g_free ((char*)currency_b);
+
+	path = gtk_tree_path_new ();
+	gtk_tree_path_append_index (path, nfs->format.negative_format);
+	gtk_tree_selection_select_path (nfs->format.negative_types.selection, path);
+	gtk_tree_path_free (path);
+
+	END_LOCALE_SWITCH;
+}
+
+static void
+cb_decimals_changed (GtkSpinButton *spin, NumberFormatSelector *nfs)
+{
+	FormatFamily const page = nfs->format.current_type;
+
+	nfs->format.num_decimals = gtk_spin_button_get_value_as_int (spin);
+
+	if (page == FMT_NUMBER || page == FMT_CURRENCY)
+		fillin_negative_samples (nfs);
+
+	draw_format_preview (nfs, TRUE);
+}
+
+static void
+cb_separator_toggle (GtkObject *obj, NumberFormatSelector *nfs)
+{
+	nfs->format.use_separator =
+		gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (obj));
+	fillin_negative_samples (nfs);
+
+	draw_format_preview (nfs, TRUE);
+}
+
+static void
+fmt_dialog_init_fmt_list (NumberFormatSelector *nfs, char const *const *formats,
+			  GtkTreeIter *select)
+{
+	GtkTreeIter iter;
+	char *fmt;
+	char const *cur_fmt = nfs->format.spec->format;
+
+	for (; *formats; formats++) {
+		gtk_list_store_append (nfs->format.formats.model, &iter);
+		fmt = style_format_str_as_XL (*formats, TRUE);
+		gtk_list_store_set (nfs->format.formats.model, &iter,
+			0, fmt, -1);
+		g_free (fmt);
+
+		if (!strcmp (*formats, cur_fmt))
+			*select = iter;
+	}
+}
+
+static void
+fmt_dialog_enable_widgets (NumberFormatSelector *nfs, int page)
+{
+	SETUP_LOCALE_SWITCH;
+	static FormatWidget const contents[][12] = {
+		/* General */
+		{
+			F_GENERAL_EXPLANATION,
+			F_MAX_WIDGET
+		},
+		/* Number */
+		{
+			F_NUMBER_EXPLANATION,
+			F_DECIMAL_BOX,
+			F_DECIMAL_LABEL,
+			F_DECIMAL_SPIN,
+			F_SEPARATOR,
+			F_NEGATIVE_LABEL,
+			F_NEGATIVE_SCROLL,
+			F_NEGATIVE,
+			F_MAX_WIDGET
+		},
+		/* Currency */
+		{
+			F_CURRENCY_EXPLANATION,
+			F_DECIMAL_BOX,
+			F_DECIMAL_LABEL,
+			F_DECIMAL_SPIN,
+			F_SEPARATOR,
+			F_SYMBOL_BOX,
+			F_SYMBOL_LABEL,
+			F_SYMBOL,
+			F_NEGATIVE_LABEL,
+			F_NEGATIVE_SCROLL,
+			F_NEGATIVE,
+			F_MAX_WIDGET
+		},
+		/* Accounting */
+		{
+			F_ACCOUNTING_EXPLANATION,
+			F_DECIMAL_BOX,
+			F_DECIMAL_LABEL,
+			F_DECIMAL_SPIN,
+			F_SYMBOL_BOX,
+			F_SYMBOL_LABEL,
+			F_SYMBOL,
+			F_MAX_WIDGET
+		},
+		/* Date */
+		{
+			F_DATE_EXPLANATION,
+			F_LIST_LABEL,
+			F_LIST_SCROLL,
+			F_LIST,
+			F_MAX_WIDGET
+		},
+		/* Time */
+		{
+			F_TIME_EXPLANATION,
+			F_LIST_LABEL,
+			F_LIST_SCROLL,
+			F_LIST,
+			F_MAX_WIDGET
+		},
+		/* Percentage */
+		{
+			F_PERCENTAGE_EXPLANATION,
+			F_DECIMAL_BOX,
+			F_DECIMAL_LABEL,
+			F_DECIMAL_SPIN,
+			F_MAX_WIDGET
+		},
+		/* Fraction */
+		{
+			F_FRACTION_EXPLANATION,
+			F_LIST_LABEL,
+			F_LIST_SCROLL,
+			F_LIST,
+			F_MAX_WIDGET
+		},
+		/* Scientific */
+		{
+			F_SCIENTIFIC_EXPLANATION,
+			F_DECIMAL_BOX,
+			F_DECIMAL_LABEL,
+			F_DECIMAL_SPIN,
+			F_MAX_WIDGET
+		},
+		/* Text */
+		{
+			F_TEXT_EXPLANATION,
+			F_MAX_WIDGET
+		},
+		/* Special */
+		{
+			F_SPECIAL_EXPLANATION,
+			F_MAX_WIDGET
+		},
+		/* Custom */
+		{
+			F_CUSTOM_EXPLANATION,
+			F_CODE_BOX,
+			F_CODE_LABEL,
+			F_ENTRY,
+			F_LIST_LABEL,
+			F_LIST_SCROLL,
+			F_LIST,
+			F_MAX_WIDGET
+		}
+	};
+
+	FormatFamily const old_page = nfs->format.current_type;
+	int i;
+	FormatWidget tmp;
+
+	START_LOCALE_SWITCH;
+
+	/* Hide widgets from old page */
+	if (old_page >= 0) {
+		int i, j;
+		FormatWidget wi, wj;
+		for (i = 0; (wi = contents[old_page][i]) != F_MAX_WIDGET ; ++i) {
+			for (j = 0; (wj = contents[page][j]) != F_MAX_WIDGET ; ++j)
+				if (wi == wj)
+					goto stays;
+			gtk_widget_hide (nfs->format.widget[wi]);
+		stays:
+			; /* No more */
+		}
+	}
+
+	/* Set the default format if appropriate */
+	if (page == FMT_GENERAL || page == FMT_ACCOUNT || page == FMT_FRACTION || page == FMT_TEXT) {
+		int list_elem = 0;
+		char *tmp;
+		if (page == nfs->format.spec->family)
+			list_elem = nfs->format.spec->family_info.list_element;
+
+		tmp = style_format_str_as_XL (cell_formats[page][list_elem], TRUE);
+		format_entry_set_text (nfs, tmp);
+		g_free (tmp);
+	}
+
+	nfs->format.current_type = page;
+	for (i = 0; (tmp = contents[page][i]) != F_MAX_WIDGET ; ++i) {
+		GtkWidget *w = nfs->format.widget[tmp];
+
+		switch (tmp) {
+		case F_LIST: {
+			int start = 0, end = -1;
+			GtkTreeIter select;
+
+			switch (page) {
+			case FMT_DATE:
+			case FMT_TIME:
+			case FMT_FRACTION:
+				start = end = page;
+				break;
+
+			case FMT_CUSTOM:
+				start = 0; end = 8;
+				break;
+
+			default :
+				g_assert_not_reached ();
+			};
+
+			select.stamp = 0;
+			gtk_list_store_clear (nfs->format.formats.model);
+			for (; start <= end ; ++start)
+			  fmt_dialog_init_fmt_list (nfs,
+						    cell_formats[start], &select);
+
+			/* If this is the custom page and the format has
+			 * not been found append it */
+			/* TODO We should add the list of other custom formats created.
+			 *      It should be easy.  All that is needed is a way to differentiate
+			 *      the std formats and the custom formats in the GnmFormat hash.
+			 */
+			if  (page == FMT_CUSTOM && select.stamp == 0) {
+				char *tmp = style_format_as_XL (nfs->format.spec, TRUE);
+				format_entry_set_text (nfs, tmp);
+				g_free (tmp);
+			} else if (select.stamp == 0)
+				gtk_tree_model_get_iter_first (
+					GTK_TREE_MODEL (nfs->format.formats.model),
+					&select);
+
+			if (select.stamp != 0)
+				gtk_tree_selection_select_iter (
+					nfs->format.formats.selection, &select);
+
+			break;
+		}
+
+		case F_NEGATIVE:
+			fillin_negative_samples (nfs);
+			break;
+
+		case F_DECIMAL_SPIN:
+			gtk_spin_button_set_value (GTK_SPIN_BUTTON (nfs->format.widget[F_DECIMAL_SPIN]),
+						   nfs->format.num_decimals);
+			break;
+
+		case F_SEPARATOR:
+			gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (nfs->format.widget[F_SEPARATOR]),
+						      nfs->format.use_separator);
+			break;
+
+		default:
+			; /* Nothing */
+		}
+
+		gtk_widget_show (w);
+	}
+
+#if 0
+	if ((cl = GTK_CLIST (nfs->format.widget[F_LIST])) != NULL)
+		gnumeric_clist_make_selection_visible (cl);
+#endif
+
+	draw_format_preview (nfs, TRUE);
+
+	END_LOCALE_SWITCH;
+}
+
+/*
+ * Callback routine to manage the relationship between the number
+ * formating radio buttons and the widgets required for each mode.
+ */
+
+static void
+cb_format_class_changed (G_GNUC_UNUSED GtkTreeSelection *ignored, 
+			 NumberFormatSelector *nfs)
+{
+	int selected_item = 0;
+	GList *list;
+	GtkTreeSelection *selection = gtk_tree_view_get_selection 
+		(GTK_TREE_VIEW(nfs->format.menu));
+
+	list = gtk_tree_selection_get_selected_rows 
+		(selection, &nfs->format.menu_model);
+	if (list) {
+		GtkTreePath *path;
+		path = list->data;
+		selected_item = *(gtk_tree_path_get_indices (path));
+		
+		if (selected_item >= 0) {
+			fmt_dialog_enable_widgets (nfs, selected_item);
+		}
+		g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
+		g_list_free (list);
+	}
+}
+
+static void
+cb_format_entry_changed (GtkEditable *w, NumberFormatSelector *nfs)
+{
+	char *fmt;
+	if (!nfs->enable_edit)
+		return;
+
+	fmt = style_format_delocalize (gtk_entry_get_text (GTK_ENTRY (w)));
+	if (strcmp (nfs->format.spec->format, fmt)) {
+		style_format_unref (nfs->format.spec);
+		nfs->format.spec = style_format_new_XL (fmt, FALSE);
+		g_signal_emit (GTK_OBJECT (nfs),
+			       nfs_signals[NUMBER_FORMAT_CHANGED], 0,
+			       fmt);
+		draw_format_preview (nfs, FALSE);
+	}
+	g_free (fmt);
+}
+
+/*
+ * We only want to emit the number format changed signal once for each
+ * format change. When not blocking signals when calling
+ * gtk_entry_set_text, one would be emitted for deleting the old text
+ * and one for inserting the new. That's why we block the signal and
+ * invoke cb_format_entry_changed explicitly.
+ */
+static void
+format_entry_set_text (NumberFormatSelector *nfs, gchar *text)
+{
+	GtkEntry *entry = GTK_ENTRY (nfs->format.widget[F_ENTRY]);
+
+	g_signal_handler_block (entry, nfs->format.entry_changed_id);
+	gtk_entry_set_text (entry, text);
+	g_signal_handler_unblock (entry, nfs->format.entry_changed_id);
+	cb_format_entry_changed (GTK_EDITABLE (entry), nfs);
+}
+
+static void
+cb_format_list_select (GtkTreeSelection *selection, NumberFormatSelector *nfs)
+{
+	GtkTreeIter iter;
+	gchar *text;
+
+	if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
+		return;
+
+	gtk_tree_model_get (GTK_TREE_MODEL (nfs->format.formats.model),
+		&iter, 0, &text, -1);
+	format_entry_set_text (nfs, text);
+}
+
+static gboolean
+cb_format_currency_select (G_GNUC_UNUSED GtkWidget *ct,
+			   char * new_text, NumberFormatSelector *nfs)
+{
+	int i;
+
+	/* ignore the clear while assigning a new value */
+	if (!nfs->enable_edit || new_text == NULL || *new_text == '\0')
+		return FALSE;
+
+	for (i = 0; currency_symbols[i].symbol != NULL ; ++i)
+		if (!strcmp (_(currency_symbols[i].description), new_text)) {
+			nfs->format.currency_index = i;
+			break;
+		}
+
+	if (nfs->format.current_type == 1 || nfs->format.current_type == 2)
+		fillin_negative_samples (nfs);
+	draw_format_preview (nfs, TRUE);
+
+	return TRUE;
+}
+
+static void
+cb_format_negative_form_selected (GtkTreeSelection *selection, NumberFormatSelector *nfs)
+{
+	GtkTreeIter iter;
+	int type;
+
+	if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
+		return;
+
+	gtk_tree_model_get (GTK_TREE_MODEL (nfs->format.negative_types.model),
+		&iter, 0, &type, -1);
+	nfs->format.negative_format = type;
+	draw_format_preview (nfs, TRUE);
+}
+
+static gint
+funny_currency_order (gconstpointer _a, gconstpointer _b)
+{
+	char const *a = (char const *)_a;
+	char const *b = (char const *)_b;
+
+	/* Keep the special 1 char versions, and both euro forms at the top */
+	gboolean a1 = a[0] && (*(g_utf8_next_char (a)) == '\0' ||
+			       0x20AC == g_utf8_get_char (a)); /* euro */
+	gboolean b1 = b[0] && (*(g_utf8_next_char (b)) == '\0' ||
+			       0x20AC == g_utf8_get_char (b)); /* euro */
+
+	if (a1) {
+		if (b1) {
+			return strcmp (a, b);
+		} else {
+			return -1;
+		}
+	} else {
+		if (b1) {
+			return +1;
+		} else {
+			return strcmp (a, b);
+		}
+	}
+}
+
+static void
+set_format_category (NumberFormatSelector *nfs, int row)
+{
+	GtkTreePath *path;
+	GtkTreeSelection *selection = gtk_tree_view_get_selection 
+		((GTK_TREE_VIEW(nfs->format.menu)));
+
+	path = gtk_tree_path_new_from_indices (row, -1);
+	gtk_tree_selection_select_path  (selection, path);
+	gtk_tree_path_free (path);
+}
+
+
+static void
+set_format_category_menu_from_style (NumberFormatSelector *nfs)
+{
+  	FormatFamily page;
+
+  	g_return_if_fail (IS_NUMBER_FORMAT_SELECTOR (nfs));
+
+	/* Attempt to extract general parameters from the current format */
+	if ((page = nfs->format.spec->family) < 0)
+		page = FMT_CUSTOM; /* Default to custom */
+
+	set_format_category (nfs, page);
+	fmt_dialog_enable_widgets (nfs, page);
+}
+
+static void
+populate_menu (NumberFormatSelector *nfs)
+{
+	GtkTreeViewColumn *column;
+	GtkTreeSelection  *selection;
+	GtkTreeIter iter;
+	GtkCellRenderer *renderer;
+	char const * const *categories = format_category_names;
+
+	nfs->format.menu_model = GTK_TREE_MODEL (gtk_list_store_new 
+						(1, G_TYPE_STRING));
+	gtk_tree_view_set_model (GTK_TREE_VIEW (nfs->format.menu), 
+				 nfs->format.menu_model);
+	selection = gtk_tree_view_get_selection 
+		(GTK_TREE_VIEW(nfs->format.menu));
+	gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+	
+	while (*categories) {
+		gtk_list_store_append 
+			(GTK_LIST_STORE (nfs->format.menu_model), &iter);
+		gtk_list_store_set (GTK_LIST_STORE (nfs->format.menu_model),
+				    &iter, 0, _(*categories), -1);
+		categories++;
+	}
+
+	renderer = gtk_cell_renderer_text_new ();
+	column = gtk_tree_view_column_new_with_attributes ("", renderer,
+							   "text", 0,
+							   NULL);
+	gtk_tree_view_append_column (GTK_TREE_VIEW(nfs->format.menu), column);
+
+	g_signal_connect (selection,
+		"changed",
+		G_CALLBACK (cb_format_class_changed), nfs);
+}
+
+
+/*
+ * static void
+ * fmt_dialog_init_format_page (FormatState *state)
+ */
+
+static void
+nfs_init (NumberFormatSelector *nfs)
+{
+	/* The various format widgets */
+	static char const *const widget_names[] = {
+		"format_general_explanation",
+		"format_number_explanation",
+		"format_currency_explanation",
+		"format_accounting_explanation",
+		"format_date_explanation",
+		"format_time_explanation",
+		"format_percentage_explanation",
+		"format_fraction_explanation",
+		"format_scientific_explanation",
+		"format_text_explanation",
+		"format_special_explanation",
+		"format_custom_explanation",
+
+		"format_separator",
+		"format_symbol_label",
+		"format_symbol_select",
+		"format_entry",
+		"format_list_label",
+		"format_list_scroll",
+		"format_list",
+		"format_number_decimals",
+		"format_negatives_label",
+		"format_negatives_scroll",
+		"format_negatives",
+		"format_decimal_label",
+		"format_code_label",
+		"format_symbol_box",
+		"format_decimal_box",
+		"format_code_box",
+		NULL
+	};
+
+	GtkWidget *tmp;
+	GtkTreeViewColumn *column;
+	GoComboText *combo;
+	char const *name;
+	int i;
+	FormatFamily page;
+
+	GtkWidget *toplevel;
+	GtkWidget *old_parent;
+
+	nfs->enable_edit = FALSE;
+	nfs->locale = NULL;
+
+	nfs->gui = gnm_glade_xml_new (NULL, "format-selector.glade", NULL, NULL);
+	if (nfs->gui == NULL)
+		return;
+
+	toplevel = glade_xml_get_widget (nfs->gui, "number_box");
+	old_parent = gtk_widget_get_toplevel (toplevel);
+	gtk_widget_reparent (toplevel, GTK_WIDGET (nfs));
+	gtk_widget_destroy (old_parent);
+	gtk_widget_queue_resize (toplevel);
+
+	nfs->format.spec = style_format_general ();
+	style_format_ref (nfs->format.spec);
+
+	nfs->format.preview = NULL;
+
+	/* The handlers will set the format family later.  -1 flags that
+	 * all widgets are already hidden. */
+	nfs->format.current_type = -1;
+
+	/* Even if the format was not recognized it has set intelligent defaults */
+	nfs->format.use_separator = nfs->format.spec->family_info.thousands_sep;
+	nfs->format.num_decimals = nfs->format.spec->family_info.num_decimals;
+	nfs->format.negative_format = nfs->format.spec->family_info.negative_fmt;
+	nfs->format.currency_index = nfs->format.spec->family_info.currency_symbol_index;
+
+	nfs->format.preview_box = glade_xml_get_widget (nfs->gui, "preview_box");
+	nfs->format.preview = GTK_TEXT_VIEW (glade_xml_get_widget (nfs->gui, "preview"));
+	{
+		PangoFontMetrics *metrics;
+		PangoContext *context;
+		GtkWidget *w = GTK_WIDGET (nfs->format.preview);
+		gint char_width;
+
+		/* request width in number of chars */
+		context = gtk_widget_get_pango_context (w);
+		metrics = pango_context_get_metrics (context,
+						     gtk_widget_get_style(w)->font_desc,
+						     pango_context_get_language (context));
+		char_width = pango_font_metrics_get_approximate_char_width (metrics);
+		gtk_widget_set_size_request (w, PANGO_PIXELS (char_width) * FORMAT_PREVIEW_MAX, -1);
+		pango_font_metrics_unref (metrics);
+	}
+	nfs->format.preview_buffer = gtk_text_view_get_buffer (nfs->format.preview);
+
+	nfs->format.menu = glade_xml_get_widget (nfs->gui, "format_menu");
+	populate_menu (nfs);
+
+	/* Collect all the required format widgets and hide them */
+	for (i = 0; (name = widget_names[i]) != NULL; ++i) {
+		tmp = glade_xml_get_widget (nfs->gui, name);
+
+		if (tmp == NULL) {
+			g_warning ("nfs_init : failed to load widget %s", name);
+		}
+
+		g_return_if_fail (tmp != NULL);
+
+		gtk_widget_hide (tmp);
+		nfs->format.widget[i] = tmp;
+	}
+
+	/* set minimum heights */
+	gtk_widget_set_size_request (nfs->format.widget[F_LIST], -1, 100);
+	gtk_widget_set_size_request (nfs->format.widget[F_NEGATIVE], -1, 100);
+
+	/* use size group for better widget alignment */
+	nfs->format.size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+	gtk_size_group_add_widget (nfs->format.size_group,
+				   nfs->format.widget[F_SYMBOL_LABEL]);
+	gtk_size_group_add_widget (nfs->format.size_group,
+				   nfs->format.widget[F_DECIMAL_LABEL]);
+
+	/* hide preview by default until a value is set */
+	gtk_widget_hide (nfs->format.preview_box);
+
+	/* setup the structure of the negative type list */
+	nfs->format.negative_types.model = gtk_list_store_new (3,
+							       G_TYPE_INT,
+							       G_TYPE_STRING,
+							       G_TYPE_STRING);
+	nfs->format.negative_types.view = GTK_TREE_VIEW (nfs->format.widget[F_NEGATIVE]);
+	gtk_tree_view_set_model (nfs->format.negative_types.view,
+				 GTK_TREE_MODEL (nfs->format.negative_types.model));
+	column = gtk_tree_view_column_new_with_attributes (_("Negative Number Format"),
+							   gtk_cell_renderer_text_new (),
+							   "text",		1,
+							   "foreground",	2,
+							   NULL);
+	gtk_tree_view_append_column (nfs->format.negative_types.view, column);
+	nfs->format.negative_types.selection =
+		gtk_tree_view_get_selection (nfs->format.negative_types.view);
+	gtk_tree_selection_set_mode (nfs->format.negative_types.selection,
+				     GTK_SELECTION_SINGLE);
+	g_signal_connect (G_OBJECT (nfs->format.negative_types.selection),
+			  "changed",
+			  G_CALLBACK (cb_format_negative_form_selected), nfs);
+
+	/* Catch changes to the spin box */
+	g_signal_connect (G_OBJECT (nfs->format.widget[F_DECIMAL_SPIN]),
+			  "value_changed",
+			  G_CALLBACK (cb_decimals_changed), nfs);
+
+	/* Setup special handlers for : Numbers */
+	g_signal_connect (G_OBJECT (nfs->format.widget[F_SEPARATOR]),
+			  "toggled",
+			  G_CALLBACK (cb_separator_toggle), nfs);
+
+	/* setup custom format list */
+	nfs->format.formats.model =
+		gtk_list_store_new (1, G_TYPE_STRING);
+	nfs->format.formats.view =
+		GTK_TREE_VIEW (nfs->format.widget[F_LIST]);
+	gtk_tree_view_set_model (nfs->format.formats.view,
+				 GTK_TREE_MODEL (nfs->format.formats.model));
+	column = gtk_tree_view_column_new_with_attributes (_("Number Formats"),
+							   gtk_cell_renderer_text_new (),
+							   "text",		0,
+							   NULL);
+	gtk_tree_view_append_column (nfs->format.formats.view, column);
+	nfs->format.formats.selection =
+		gtk_tree_view_get_selection (nfs->format.formats.view);
+	gtk_tree_selection_set_mode (nfs->format.formats.selection,
+				     GTK_SELECTION_BROWSE);
+	g_signal_connect (G_OBJECT (nfs->format.formats.selection),
+			  "changed",
+			  G_CALLBACK (cb_format_list_select), nfs);
+
+	/* Setup handler Currency & Accounting currency symbols */
+	combo = GO_COMBO_TEXT (nfs->format.widget[F_SYMBOL]);
+	if (combo != NULL) {
+		GList *ptr, *l = NULL;
+
+		for (i = 0; currency_symbols[i].symbol != NULL ; ++i)
+			l = g_list_append (l, _((gchar *)currency_symbols[i].description));
+		l = g_list_sort (l, funny_currency_order);
+
+		for (ptr = l; ptr != NULL ; ptr = ptr->next)
+			go_combo_text_add_item	(combo, ptr->data);
+		g_list_free (l);
+		go_combo_text_set_text (combo,
+					 _((const gchar *)currency_symbols[nfs->format.currency_index].description),
+					 GO_COMBO_TEXT_FROM_TOP);
+		g_signal_connect (G_OBJECT (combo),
+				  "entry_changed",
+				  G_CALLBACK (cb_format_currency_select), nfs);
+	}
+
+	/* Setup special handler for Custom */
+	nfs->format.entry_changed_id 
+		= g_signal_connect (G_OBJECT (nfs->format.widget[F_ENTRY]),
+				    "changed",
+				    G_CALLBACK (cb_format_entry_changed), nfs);
+
+	/* Connect signal for format menu */
+	set_format_category_menu_from_style (nfs);
+
+	if ((page = nfs->format.spec->family) < 0)
+		page = FMT_CUSTOM; /* Default to custom */
+	fmt_dialog_enable_widgets (nfs, page);
+
+	nfs->enable_edit = TRUE;
+}
+
+static void
+nfs_destroy (GtkObject *object)
+{
+  	NumberFormatSelector *nfs = NUMBER_FORMAT_SELECTOR (object);
+
+	g_free (nfs->locale);
+	nfs->locale = NULL;
+
+	if (nfs->format.spec) {
+		style_format_unref (nfs->format.spec);
+		nfs->format.spec = NULL;
+	}
+
+	if (nfs->format.size_group) {
+		g_object_unref (nfs->format.size_group);
+		nfs->format.size_group = NULL;
+	}
+
+	if (nfs->value) {
+		value_release (nfs->value);
+		nfs->value = NULL;
+	}
+
+	if (nfs->gui) {
+		g_object_unref (G_OBJECT (nfs->gui));
+		nfs->gui = NULL;
+	}
+
+	((GtkObjectClass *)nfs_parent_class)->destroy (object);
+}
+
+static void
+nfs_class_init (GtkObjectClass *klass)
+{
+	klass->destroy = nfs_destroy;
+
+	nfs_parent_class = g_type_class_peek (gtk_hbox_get_type ());
+
+	nfs_signals[NUMBER_FORMAT_CHANGED] =
+		g_signal_new ("number_format_changed",
+			      G_OBJECT_CLASS_TYPE (klass),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (NumberFormatSelectorClass, number_format_changed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1, G_TYPE_POINTER);
+}
+
+GSF_CLASS (NumberFormatSelector, number_format_selector,
+	   nfs_class_init, nfs_init, GTK_TYPE_HBOX)
+
+GtkWidget *
+number_format_selector_new (void)
+{
+	return g_object_new (NUMBER_FORMAT_SELECTOR_TYPE, NULL);
+}
+
+void
+number_format_selector_set_focus (NumberFormatSelector *nfs)
+{
+	g_return_if_fail (IS_NUMBER_FORMAT_SELECTOR (nfs));
+
+	gtk_widget_grab_focus (GTK_WIDGET (nfs->format.menu));
+}
+
+void
+number_format_selector_set_style_format (NumberFormatSelector *nfs,
+					 GnmFormat *style_format)
+{
+	GoComboText *combo;
+
+  	g_return_if_fail (IS_NUMBER_FORMAT_SELECTOR (nfs));
+	g_return_if_fail (style_format != NULL);
+
+	style_format_ref (style_format);
+
+  	style_format_unref (nfs->format.spec);
+
+	nfs->format.spec = style_format;
+
+	nfs->format.use_separator = style_format->family_info.thousands_sep;
+	nfs->format.num_decimals = style_format->family_info.num_decimals;
+	nfs->format.negative_format = style_format->family_info.negative_fmt;
+	nfs->format.currency_index = style_format->family_info.currency_symbol_index;
+
+	combo = GO_COMBO_TEXT (nfs->format.widget[F_SYMBOL]);
+	go_combo_text_set_text
+		(combo,
+		 _((const gchar *)currency_symbols[nfs->format.currency_index].description),
+		 GO_COMBO_TEXT_FROM_TOP);
+
+	set_format_category_menu_from_style (nfs);
+	draw_format_preview (nfs, TRUE);
+}
+
+void
+number_format_selector_set_value (NumberFormatSelector *nfs,
+				  GnmValue const *value)
+{
+  	g_return_if_fail (IS_NUMBER_FORMAT_SELECTOR (nfs));
+	g_return_if_fail (value != NULL);
+
+	if (nfs->value)	{
+	  	value_release (nfs->value);
+	}
+	nfs->value = value_dup (value);
+
+	gtk_widget_show (nfs->format.preview_box);
+
+	draw_format_preview (nfs, TRUE);
+}
+
+void
+number_format_selector_set_date_conv (NumberFormatSelector *nfs,
+				      GnmDateConventions const *date_conv)
+{
+  	g_return_if_fail (IS_NUMBER_FORMAT_SELECTOR (nfs));
+	g_return_if_fail (date_conv != NULL);
+
+	/* FIXME is it safe ? */
+
+  	nfs->date_conv = date_conv;
+
+	draw_format_preview (nfs, TRUE);
+}
+
+void
+number_format_selector_editable_enters (NumberFormatSelector *nfs,
+					GtkWindow *window)
+{
+	g_return_if_fail (IS_NUMBER_FORMAT_SELECTOR (nfs));
+
+	gnumeric_editable_enters (window,
+				  GTK_WIDGET (nfs->format.widget[F_DECIMAL_SPIN]));
+	gnumeric_editable_enters (window,
+				  GTK_WIDGET (nfs->format.widget[F_ENTRY]));
+}
+
+
+void		
+number_format_selector_set_locale (NumberFormatSelector *nfs, 
+				   char const *locale)
+{
+	g_free (nfs->locale);
+	nfs->locale = g_strdup (locale);
+
+	cb_format_class_changed (NULL, nfs);
+}
+
+/* The following utility function should possibly be in format.h but we */
+/* access to the array of category names which are better located here. */
+char const *    
+number_format_selector_format_classification (GnmFormat const *style_format)
+{
+  	FormatFamily page = style_format->family;
+
+	if (page < 0 || page > FMT_CUSTOM)
+		page = FMT_CUSTOM; /* Default to custom */
+
+	return _(format_category_names[page]);
+}
--- /dev/null
+++ lib/goffice/split/widgets/widget-font-selector.h
@@ -0,0 +1,32 @@
+#ifndef GNUMERIC_WIDGET_FONT_SELECTOR_H
+#define GNUMERIC_WIDGET_FONT_SELECTOR_H
+
+#include <gui-gnumeric.h>
+#include <style.h>
+///#include <libfoocanvas/foo-canvas.h>
+#include <gtk/gtkwindow.h>
+
+#define FONT_SELECTOR_TYPE        (font_selector_get_type ())
+#define FONT_SELECTOR(obj)        (G_TYPE_CHECK_INSTANCE_CAST((obj), FONT_SELECTOR_TYPE, FontSelector))
+#define IS_FONT_SELECTOR(obj)     (G_TYPE_CHECK_INSTANCE_TYPE((obj), FONT_SELECTOR_TYPE))
+
+typedef struct _FontSelector FontSelector;
+
+GType    font_selector_get_type (void);
+GtkWidget *font_selector_new      (void);
+
+void font_selector_set_value       (FontSelector *fs, GnmValue const *v);
+void font_selector_set_name        (FontSelector *fs, char const *font_name);
+void font_selector_set_style       (FontSelector *fs,
+				    gboolean is_bold, gboolean is_italic);
+void font_selector_set_underline   (FontSelector *fs, StyleUnderlineType sut);
+void font_selector_set_strike      (FontSelector *fs, gboolean strikethrough);
+void font_selector_set_color       (FontSelector *fs, GnmColor *color);
+void font_selector_set_points      (FontSelector *fs, double point_size);
+void font_selector_editable_enters (FontSelector *fs, GtkWindow *dialog);
+
+void font_selector_set_from_pango  (FontSelector *fs, PangoFontDescription const *desc);
+void font_selector_get_pango  	   (FontSelector *fs, PangoFontDescription *desc);
+
+#endif /* GNUMERIC_WIDGET_FONT_SELECTOR_H */
+
--- /dev/null
+++ lib/goffice/split/widgets/widget-format-selector.h
@@ -0,0 +1,52 @@
+/**
+ * widget-number-format-selector.h:  Implements a widget to select number format.
+ *
+ * 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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ **/
+
+#ifndef __WIDGET_FORMAT_SELECTOR_H__
+#define __WIDGET_FORMAT_SELECTOR_H__
+
+//#include <gui-gnumeric.h>
+#include <gui-util.h>
+
+#define NUMBER_FORMAT_SELECTOR_TYPE        (number_format_selector_get_type ())
+#define NUMBER_FORMAT_SELECTOR(obj)        (G_TYPE_CHECK_INSTANCE_CAST((obj), NUMBER_FORMAT_SELECTOR_TYPE, NumberFormatSelector))
+#define IS_NUMBER_FORMAT_SELECTOR(obj)     (G_TYPE_CHECK_INSTANCE_TYPE((obj), NUMBER_FORMAT_SELECTOR_TYPE))
+
+typedef struct _NumberFormatSelector NumberFormatSelector;
+
+
+GType		number_format_selector_get_type	(void);
+GtkWidget * 	number_format_selector_new  	(void);
+
+void		number_format_selector_set_focus (NumberFormatSelector *nfs);
+void		number_format_selector_set_style_format (NumberFormatSelector *nfs,
+							 GnmFormat *style_format);
+void		number_format_selector_set_value (NumberFormatSelector *nfs,
+						  GnmValue const *value);
+void		number_format_selector_set_date_conv (NumberFormatSelector *nfs,
+						      GnmDateConventions const *date_conv);
+void		number_format_selector_editable_enters (NumberFormatSelector *nfs,
+							GtkWindow *window);
+void		number_format_selector_set_locale (NumberFormatSelector *nfs, 
+						   char const *locale);
+
+/* Number Format Selector Utilities */
+
+char const *    number_format_selector_format_classification (GnmFormat const *style_format);
+
+#endif /*__WIDGET_FORMAT_SELECTOR_H__*/
+
--- /dev/null
+++ lib/goffice/split/widgets/Makefile.am
@@ -0,0 +1,10 @@
+noinst_LTLIBRARIES = libgoffice-split-widgets.la
+
+AM_CFLAGS = $(GLIB_CFLAGS) $(GSF_CFLAGS) $(GNOME_CFLAGS) $(ART_CFLAGS) $(GLADE_CFLAGS) $(PRINT_CFLAGS)
+
+libgoffice_split_widgets_la_SOURCES = \
+	widget-format-selector.h \
+	widget-format-selector.c \
+	widget-font-selector.h
+
+include $(srcdir)/../../goffice.mk


More information about the gnucash-changes mailing list