libgnomedb r1766 - in trunk: . doc/C/tmpl extra/demos libgnomedb



Author: vivien
Date: Mon Jan  5 20:07:43 2009
New Revision: 1766
URL: http://svn.gnome.org/viewvc/libgnomedb?rev=1766&view=rev

Log:
2009-01-05  Vivien Malerba <malerba gnome-db org>

	* doc/C/tmpl/gnome-db-basic-form.sgml:
	* doc/C/tmpl/gnome-db-raw-grid.sgml:
	* extra/demos/grid_data_layout.c:
	* extra/demos/example_automatic_layout.xml:
	* extra/demos/Makefile.am:
	* extra/demos/form_data_layout.c:
	* libgnomedb/gnome-db-data-widget.[ch]:
	* libgnomedb/gnome-db-basic-form.c:
	* libgnomedb/gnome-db-raw-grid.c:
	* libgnomedb/gnome-db-raw-form.c:
	* libgnomedb/utility.[ch]: applied patch from
	Carlos Savoretti which is a first implementation
	of the custom layout in forms and grids


Added:
   trunk/extra/demos/example_automatic_layout.xml
   trunk/extra/demos/form_data_layout.c
   trunk/extra/demos/grid_data_layout.c
Modified:
   trunk/ChangeLog
   trunk/doc/C/tmpl/gnome-db-basic-form.sgml
   trunk/doc/C/tmpl/gnome-db-raw-grid.sgml
   trunk/extra/demos/Makefile.am
   trunk/libgnomedb/gnome-db-basic-form.c
   trunk/libgnomedb/gnome-db-data-widget.c
   trunk/libgnomedb/gnome-db-data-widget.h
   trunk/libgnomedb/gnome-db-raw-form.c
   trunk/libgnomedb/gnome-db-raw-grid.c
   trunk/libgnomedb/utility.c
   trunk/libgnomedb/utility.h

Modified: trunk/doc/C/tmpl/gnome-db-basic-form.sgml
==============================================================================
--- trunk/doc/C/tmpl/gnome-db-basic-form.sgml	(original)
+++ trunk/doc/C/tmpl/gnome-db-basic-form.sgml	Mon Jan  5 20:07:43 2009
@@ -39,6 +39,11 @@
 @arg1: 
 @arg2: 
 
+<!-- ##### ARG GnomeDbBasicForm:data-layout ##### -->
+<para>
+
+</para>
+
 <!-- ##### ARG GnomeDbBasicForm:entries-auto-default ##### -->
 <para>
 

Modified: trunk/doc/C/tmpl/gnome-db-raw-grid.sgml
==============================================================================
--- trunk/doc/C/tmpl/gnome-db-raw-grid.sgml	(original)
+++ trunk/doc/C/tmpl/gnome-db-raw-grid.sgml	Mon Jan  5 20:07:43 2009
@@ -52,6 +52,11 @@
 @dbrawgrid: the object which received the signal.
 @arg1: 
 
+<!-- ##### ARG GnomeDbRawGrid:data-layout ##### -->
+<para>
+
+</para>
+
 <!-- ##### ARG GnomeDbRawGrid:global-actions-visible ##### -->
 <para>
 

Modified: trunk/extra/demos/Makefile.am
==============================================================================
--- trunk/extra/demos/Makefile.am	(original)
+++ trunk/extra/demos/Makefile.am	Mon Jan  5 20:07:43 2009
@@ -23,9 +23,11 @@
 	form.c \
 	form_rw.c \
 	form_pict.c \
+	form_data_layout.c \
 	grid.c \
 	grid_rw.c \
 	grid_pict.c \
+	grid_data_layout.c \
 	linked_grid_form.c \
 	linked_model_param.c \
 	console.c \
@@ -33,7 +35,7 @@
 	ddl_queries.c \
 	$(canvassources)
 
-demofiles = demo_db.db demo_meta.db
+demofiles = demo_db.db demo_meta.db example_automatic_layout.xml
 
 AM_CPPFLAGS = \
 	-I$(top_srcdir) \

Added: trunk/extra/demos/example_automatic_layout.xml
==============================================================================
--- (empty file)
+++ trunk/extra/demos/example_automatic_layout.xml	Mon Jan  5 20:07:43 2009
@@ -0,0 +1,492 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<data_layouts>
+  <data_layout name="details" parent_table="contacts">
+    <data_layout_groups>
+      <data_layout_group name="header" columns_count="2" sequence="1" title="Overview">
+        <trans_set>
+          <trans loc="de_AT" val="Ubersicht"/>
+          <trans loc="de_BE" val="Overview"/>
+          <trans loc="de_DE" val="Ubersicht"/>
+          <trans loc="en_GB" val="Overview"/>
+          <trans loc="en_US" val="Overview"/>
+        </trans_set>
+        <data_layout_item name="contact_id" editable="true" use_default_formatting="true" sequence="1">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="name_full" use_default_formatting="true" sequence="2">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+      <data_layout_group name="main" columns_count="2" sequence="2">
+        <data_layout_group name="name" columns_count="1" sequence="1" title="Name">
+          <trans_set>
+            <trans loc="de_AT" val="Name"/>
+            <trans loc="de_BE" val="Name"/>
+            <trans loc="de_DE" val="Name"/>
+            <trans loc="en_GB" val="Name"/>
+            <trans loc="en_US" val="Name"/>
+          </trans_set>
+          <data_layout_item name="name_title" editable="true" use_default_formatting="true" sequence="1">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="name_first" editable="true" use_default_formatting="true" sequence="2">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="name_middle" editable="true" use_default_formatting="true" sequence="3">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="name_last" editable="true" use_default_formatting="true" sequence="4">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+        </data_layout_group>
+        <data_layout_group name="address" columns_count="1" sequence="2" title="Address">
+          <trans_set>
+            <trans loc="de_AT" val="Addresse"/>
+            <trans loc="de_BE" val="Address"/>
+            <trans loc="de_DE" val="Addresse"/>
+            <trans loc="en_GB" val="Address"/>
+            <trans loc="en_US" val="Address"/>
+          </trans_set>
+          <data_layout_item name="address_street" editable="true" use_default_formatting="true" sequence="1">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="address_town" editable="true" use_default_formatting="true" sequence="2">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="address_state" editable="true" use_default_formatting="true" sequence="3">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="address_postcode" editable="true" use_default_formatting="true" sequence="4">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="address_country" editable="true" use_default_formatting="true" sequence="5">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+        </data_layout_group>
+        <data_layout_group name="telephone" columns_count="1" sequence="3" title="Telephone">
+          <trans_set>
+            <trans loc="de_AT" val="Telefon"/>
+            <trans loc="de_BE" val="Telephone"/>
+            <trans loc="de_DE" val="Telefon"/>
+            <trans loc="en_GB" val="Telephone"/>
+            <trans loc="en_US" val="Telephone"/>
+          </trans_set>
+          <data_layout_item name="tel_work" editable="true" use_default_formatting="true" sequence="1">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="tel_mobile" editable="true" use_default_formatting="true" sequence="2">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="tel_home" editable="true" use_default_formatting="true" sequence="3">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="tel_fax" editable="true" use_default_formatting="true" sequence="4">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+        </data_layout_group>
+        <data_layout_item name="date_of_birth" editable="true" use_default_formatting="true" sequence="4">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="picture" editable="true" use_default_formatting="true" sequence="5">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="comments" editable="true" use_default_formatting="true" sequence="6">
+          <formatting format_thousands_separator="true" format_decimal_places="2" format_text_multiline="true"/>
+        </data_layout_item>
+        <data_layout_item name="website" editable="true" use_default_formatting="true" sequence="7">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="email" editable="true" use_default_formatting="true" sequence="8">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_button script="# example helloworld.py&#10;&#10;import pygtk&#10;pygtk.require('2.0')&#10;import gtk&#10;&#10;class HelloWorld:&#10;&#10;    # This is a callback function. The data arguments are ignored&#10;    # in this example. More on callbacks below.&#10;    def hello(self, widget, data=None):&#10;        print &quot;Hello World&quot;&#10;&#10;    def delete_event(self, widget, event, data=None):&#10;        # If you return FALSE in the &quot;delete_event&quot; signal handler,&#10;        # GTK will emit the &quot;destroy&quot; signal. Returning TRUE means&#10;        # you don't want the window to be destroyed.&#10;        # This is useful for popping up 'are you sure you want to quit?'&#10;        # type dialogs.&#10;&#10;        # Change FALSE to TRUE and the main window will not be destroyed&#10;        # with a &quot;delete_event&quot;.&#10;        return False&#10;&#10;    def destroy(self, widget, data=None):&#10;        gtk.main_quit()&#10;&#
 10;    def __init__(self):&#10;        # create a new window&#10;        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)&#10;    &#10;        # When the window is given the &quot;delete_event&quot; signal (this is given&#10;        # by the window manager, usually by the &quot;close&quot; option, or on the&#10;        # titlebar), we ask it to call the delete_event () function&#10;        # as defined above. The data passed to the callback&#10;        # function is NULL and is ignored in the callback function.&#10;        self.window.connect(&quot;delete_event&quot;, self.delete_event)&#10;    &#10;        # Here we connect the &quot;destroy&quot; event to a signal handler.  &#10;        # This event occurs when we call gtk_widget_destroy() on the window,&#10;        # or if we return FALSE in the &quot;delete_event&quot; callback.&#10;        self.window.connect(&quot;destroy&quot;, self.destroy)&#10;    &#10;        # Sets the border width of the window.&#10;        self.win
 dow.set_border_width(10)&#10;    &#10;        # Creates a new button with the label &quot;Hello World&quot;.&#10;        contact_name = record[&quot;name_full&quot;];&#10;        self.button = gtk.Button(&quot;Hello World, &quot; + contact_name)&#10;    &#10;        # When the button receives the &quot;clicked&quot; signal, it will call the&#10;        # function hello() passing it None as its argument.  The hello()&#10;        # function is defined above.&#10;        self.button.connect(&quot;clicked&quot;, self.hello, None)&#10;    &#10;        # This will cause the window to be destroyed by calling&#10;        # gtk_widget_destroy(window) when &quot;clicked&quot;.  Again, the destroy&#10;        # signal could come from here, or the window manager.&#10;        self.button.connect_object(&quot;clicked&quot;, gtk.Widget.destroy, self.window)&#10;    &#10;        # This packs the button into the window (a GTK container).&#10;        self.window.add(self.button)&#10;    &#10;
         # The final step is to display this newly created widget.&#10;        self.button.show()&#10;    &#10;        # and the window&#10;        self.window.show()&#10;&#10;    def main(self):&#10;        # All PyGTK applications must have a gtk.main(). Control ends here&#10;        # and waits for an event to occur (like a key press or mouse event).&#10;        gtk.main()&#10;&#10;# If the program is run directly or passed as an argument to the python&#10;# interpreter then create a HelloWorld instance and show it&#10;if __name__ == &quot;__main__&quot;:&#10;    hello = HelloWorld()&#10;    hello.main()&#10;" title="Test Button" sequence="9"/>
+      </data_layout_group>
+    </data_layout_groups>
+  </data_layout>
+  <data_layout name="list" parent_table="contacts">
+    <data_layout_groups>
+      <data_layout_group name="main" columns_count="1" sequence="1">
+        <data_layout_item name="contact_id" use_default_formatting="true" sequence="1">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="name_title" editable="true" use_default_formatting="true" sequence="2">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="name_first" editable="true" use_default_formatting="true" sequence="3">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="name_last" editable="true" use_default_formatting="true" sequence="4">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="address_country" editable="true" use_default_formatting="true" sequence="5">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="comments" editable="true" use_default_formatting="true" sequence="6">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+    </data_layout_groups>
+  </data_layout>
+  <data_layout name="details" parent_table="invoice_lines">
+    <data_layout_groups>
+      <data_layout_group name="main" columns_count="1" sequence="1">
+        <data_layout_item name="invoice_lines_id" editable="true" use_default_formatting="true" sequence="1">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="invoice_id" editable="true" use_default_formatting="true" sequence="2">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="product_id" editable="true" use_default_formatting="true" sequence="3">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="product_name" editable="true" use_default_formatting="true" sequence="4">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="product_price" editable="true" use_default_formatting="true" sequence="5">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="count" editable="true" use_default_formatting="true" sequence="6">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="total_price" use_default_formatting="true" sequence="7">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="vat_percentage" editable="true" use_default_formatting="true" sequence="8">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="total_price_vat" use_default_formatting="true" sequence="9">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+    </data_layout_groups>
+  </data_layout>
+  <data_layout name="list" parent_table="invoice_lines">
+    <data_layout_groups>
+      <data_layout_group name="main" columns_count="1" sequence="1">
+        <data_layout_item name="invoice_lines_id" editable="true" use_default_formatting="true" sequence="1">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="invoice_id" editable="true" use_default_formatting="true" sequence="2">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="product_id" editable="true" use_default_formatting="true" sequence="3">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="product_name" editable="true" use_default_formatting="true" sequence="4">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="product_price" editable="true" use_default_formatting="true" sequence="5">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="count" editable="true" use_default_formatting="true" sequence="6">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="total_price" editable="true" use_default_formatting="true" sequence="7">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+    </data_layout_groups>
+  </data_layout>
+  <data_layout name="details" parent_table="invoices">
+    <data_layout_groups>
+      <data_layout_group name="header" columns_count="2" sequence="1" title="Overview">
+        <trans_set>
+          <trans loc="de_AT" val="Ãbersicht"/>
+          <trans loc="de_BE" val="Overview"/>
+          <trans loc="de_DE" val="Ãbersicht"/>
+          <trans loc="en_GB" val="Overview"/>
+          <trans loc="en_US" val="Overview"/>
+        </trans_set>
+        <data_layout_item name="invoice_id" use_default_formatting="true" sequence="1">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="date" editable="true" use_default_formatting="true" sequence="2">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+      <data_layout_group name="main" columns_count="1" sequence="2">
+        <data_layout_group name="customer" columns_count="2" sequence="1" title="Customer">
+          <trans_set>
+            <trans loc="de_AT" val="Kunde"/>
+            <trans loc="de_BE" val="Customer"/>
+            <trans loc="de_DE" val="Kunde"/>
+            <trans loc="en_GB" val="Customer"/>
+            <trans loc="en_US" val="Customer"/>
+          </trans_set>
+          <data_layout_item name="contact_id" editable="true" use_default_formatting="true" sequence="1">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="name_full" relationship="contacts" use_default_formatting="true" sequence="2">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+        </data_layout_group>
+        <data_layout_portal relationship="invoice_lines" name="invoice_lines" sequence="2">
+          <data_layout_item name="product_id" editable="true" use_default_formatting="true" sequence="1">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="product_name" editable="true" use_default_formatting="true" sequence="2">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="product_price" editable="true" use_default_formatting="true" sequence="3">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="vat_percentage" editable="true" use_default_formatting="true" sequence="4">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="count" editable="true" use_default_formatting="true" sequence="5">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="total_price" editable="true" use_default_formatting="true" sequence="6">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="total_price_vat" editable="true" use_default_formatting="true" sequence="7">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+        </data_layout_portal>
+        <data_layout_item name="price_total" use_default_formatting="true" sequence="3">
+          <formatting format_thousands_separator="true" format_decimal_places_restricted="true" format_decimal_places="2" format_currency_symbol="CAD"/>
+        </data_layout_item>
+        <data_layout_item name="vat_total" use_default_formatting="true" sequence="4">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="price_total_with_vat" use_default_formatting="true" sequence="5">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="comment" editable="true" use_default_formatting="true" sequence="6">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+    </data_layout_groups>
+  </data_layout>
+  <data_layout name="list" parent_table="invoices">
+    <data_layout_groups>
+      <data_layout_group name="main" columns_count="1" sequence="1">
+        <data_layout_item name="invoice_id" use_default_formatting="true" sequence="1">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="contact_id" editable="true" use_default_formatting="true" sequence="2">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="name_full" relationship="contacts" editable="true" use_default_formatting="true" sequence="3">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="price_total" editable="true" use_default_formatting="true" sequence="4">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="date" editable="true" use_default_formatting="true" sequence="5">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="comment" editable="true" use_default_formatting="true" sequence="6">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+    </data_layout_groups>
+  </data_layout>
+  <data_layout name="list_related_related_invoice_lines" parent_table="invoices">
+    <data_layout_groups>
+      <data_layout_group name="main" columns_count="1" sequence="1">
+        <data_layout_item name="product_id" editable="true" use_default_formatting="true" sequence="1">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="product_name" editable="true" use_default_formatting="true" sequence="2">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="product_price" editable="true" use_default_formatting="true" sequence="3">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="count" editable="true" use_default_formatting="true" sequence="4">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="total_price" use_default_formatting="true" sequence="5">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="vat_percentage" editable="true" use_default_formatting="true" sequence="6">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="total_price_vat" use_default_formatting="true" sequence="7">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+    </data_layout_groups>
+  </data_layout>
+  <data_layout name="list_related_related_invoice_lines" parent_table="invoice_lines">
+    <data_layout_groups>
+      <data_layout_group name="main" columns_count="1" sequence="1">
+        <data_layout_item name="product_id" editable="true" use_default_formatting="true" sequence="1">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="product_name" editable="true" use_default_formatting="true" sequence="2">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="product_price" editable="true" use_default_formatting="true" sequence="3">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="count" editable="true" use_default_formatting="true" sequence="4">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="total_price" use_default_formatting="true" sequence="5">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="vat_percentage" editable="true" use_default_formatting="true" sequence="6">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="total_price_vat" use_default_formatting="true" sequence="7">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+    </data_layout_groups>
+  </data_layout>
+  <data_layout name="details" parent_table="products">
+    <data_layout_groups>
+      <data_layout_group name="header" columns_count="2" sequence="1" title="Overview">
+        <trans_set>
+          <trans loc="de_AT" val="Overview"/>
+          <trans loc="de_BE" val="Overview"/>
+          <trans loc="de_DE" val="Overview"/>
+          <trans loc="en_GB" val="Overview"/>
+          <trans loc="en_US" val="Overview"/>
+        </trans_set>
+        <data_layout_item name="ref" use_default_formatting="true" sequence="1">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="name" editable="true" use_default_formatting="true" sequence="2">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+      <data_layout_group name="main" columns_count="2" sequence="2" title="Details">
+        <trans_set>
+          <trans loc="de_AT" val="Details"/>
+          <trans loc="de_BE" val="Details"/>
+          <trans loc="de_DE" val="Details"/>
+          <trans loc="en_GB" val="Details"/>
+          <trans loc="en_US" val="Details"/>
+        </trans_set>
+<data_layout_notebook name="notebook_contact" columns_count="1" sequence="1">
+      <data_layout_group name="name" columns_count="1" sequence="1" title="Name">
+        <data_layout_item name="category" editable="true" use_default_formatting="true" sequence="1">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+      <data_layout_group name="amount" columns_count="1" sequence="2" title="Amount">
+        <data_layout_item name="price" editable="true" use_default_formatting="true" sequence="2">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+      <data_layout_group name="warehouse" columns_count="1" sequence="3" title="Warehouse">
+        <data_layout_item name="wh_stored" editable="true" use_default_formatting="true" sequence="1">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+</data_layout_notebook>
+      </data_layout_group>
+    </data_layout_groups>
+  </data_layout>
+  <data_layout name="list" parent_table="products">
+    <data_layout_groups>
+      <data_layout_group name="main" columns_count="1" sequence="1"    title="Overview">
+        <data_layout_item name="ref" use_default_formatting="true" sequence="1">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="name" editable="true" use_default_formatting="true" sequence="2">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="price" editable="true" use_default_formatting="true" sequence="3">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="category" editable="true" use_default_formatting="true" sequence="4">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+    </data_layout_groups>
+  </data_layout>
+  <data_layout name="details" parent_table="staff">
+    <data_layout_groups>
+      <data_layout_group name="header" columns_count="2" sequence="1" title="Overview">
+        <trans_set>
+          <trans loc="de_AT" val="Overview"/>
+          <trans loc="de_BE" val="Overview"/>
+          <trans loc="de_DE" val="Overview"/>
+          <trans loc="en_GB" val="Overview"/>
+          <trans loc="en_US" val="Overview"/>
+        </trans_set>
+        <data_layout_item name="staff_id" use_default_formatting="true" sequence="1">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="name_last" editable="true" use_default_formatting="true" sequence="2">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+      <data_layout_group name="main" columns_count="2" sequence="2">
+        <data_layout_item name="position" editable="true" use_default_formatting="true" sequence="1">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_group name="name" columns_count="1" sequence="2" title="Name">
+          <trans_set>
+            <trans loc="de_AT" val="Name"/>
+            <trans loc="de_BE" val="Name"/>
+            <trans loc="de_DE" val="Name"/>
+            <trans loc="en_GB" val="Name"/>
+            <trans loc="en_US" val="Name"/>
+          </trans_set>
+          <data_layout_item name="name_title" editable="true" use_default_formatting="true" sequence="1">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="name_first" editable="true" use_default_formatting="true" sequence="2">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="name_second" editable="true" use_default_formatting="true" sequence="3">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="name_last" editable="true" use_default_formatting="true" sequence="4">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+        </data_layout_group>
+        <data_layout_group name="address" columns_count="1" sequence="3" title="Address">
+          <trans_set>
+            <trans loc="de_AT" val="Address"/>
+            <trans loc="de_BE" val="Address"/>
+            <trans loc="de_DE" val="Address"/>
+            <trans loc="en_GB" val="Address"/>
+            <trans loc="en_US" val="Address"/>
+          </trans_set>
+          <data_layout_item name="address_state" editable="true" use_default_formatting="true" sequence="1">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="address_street" editable="true" use_default_formatting="true" sequence="2">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="address_country" editable="true" use_default_formatting="true" sequence="3">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="address_postcode" editable="true" use_default_formatting="true" sequence="4">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+          <data_layout_item name="address_town" editable="true" use_default_formatting="true" sequence="5">
+            <formatting format_thousands_separator="true" format_decimal_places="2"/>
+          </data_layout_item>
+        </data_layout_group>
+        <data_layout_item name="date_of_birth" editable="true" use_default_formatting="true" sequence="4">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+    </data_layout_groups>
+  </data_layout>
+  <data_layout name="list" parent_table="staff">
+    <data_layout_groups>
+      <data_layout_group name="main" columns_count="1" sequence="1">
+        <data_layout_item name="staff_id" use_default_formatting="true" sequence="1">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="name_first" editable="true" use_default_formatting="true" sequence="2">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="name_last" editable="true" use_default_formatting="true" sequence="3">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+        <data_layout_item name="position" editable="true" use_default_formatting="true" sequence="4">
+          <formatting format_thousands_separator="true" format_decimal_places="2"/>
+        </data_layout_item>
+      </data_layout_group>
+    </data_layout_groups>
+  </data_layout>
+</data_layouts>

Added: trunk/extra/demos/form_data_layout.c
==============================================================================
--- (empty file)
+++ trunk/extra/demos/form_data_layout.c	Mon Jan  5 20:07:43 2009
@@ -0,0 +1,80 @@
+/* Forms/Automatic data_layout
+ *
+ * A GnomeDbForm widget where automatic 'data_layout' is used to display
+ * 
+ */
+
+#include <libgnomedb/libgnomedb.h>
+
+extern GdaConnection *demo_cnc;
+extern GdaSqlParser *demo_parser;
+static GtkWidget *window = NULL;
+
+GtkWidget *
+do_form_data_layout (GtkWidget *do_widget)
+{  
+	if (!window) {
+		GdaStatement *stmt;
+		GtkWidget *vbox;
+		GtkWidget *label;
+		GdaDataModel *model;
+		GtkWidget *form;
+		GnomeDbRawForm *raw_form;
+		GdaSet *data_set;
+		GdaHolder *param;
+		GValue *value;
+		
+		window = gtk_dialog_new_with_buttons ("Form with automatic 'data_layout'",
+						      GTK_WINDOW (do_widget),
+						      0,
+						      GTK_STOCK_CLOSE,
+						      GTK_RESPONSE_NONE,
+						      NULL);
+		
+		g_signal_connect (window, "response",
+				  G_CALLBACK (gtk_widget_destroy), NULL);
+		g_signal_connect (window, "destroy",
+				  G_CALLBACK (gtk_widget_destroyed), &window);
+		
+		vbox = gtk_vbox_new (FALSE, 5);
+		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
+		gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
+		
+		label = gtk_label_new ("The following GnomeDbForm widget displays data from the 'products' table.\n\n"
+				       "\n "
+				       ".");
+		gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+		
+		/* Create the demo widget */
+		stmt = gda_sql_parser_parse_string (demo_parser, 
+						    "SELECT ref, category, name, price, wh_stored FROM products", 
+						    NULL, NULL);
+		model = gda_connection_statement_execute_select (demo_cnc, stmt, NULL, NULL);
+		g_object_unref (stmt)
+;
+		GError *error = NULL;
+		if (!gda_data_select_compute_modification_statements (GDA_DATA_SELECT (model), &error)) {
+			g_print ("===> %s\n", error && error->message ? error->message : "No detail");
+		}
+		form = gnome_db_form_new (model);
+		g_object_unref (model);
+
+		g_object_get (G_OBJECT (form), "raw_form", &raw_form, NULL);
+		gnome_db_utility_set_data_layout_from_file
+			(GNOME_DB_DATA_WIDGET (raw_form),
+			 "./example_automatic_layout.xml", "products");
+
+		gtk_box_pack_start (GTK_BOX (vbox), form, TRUE, TRUE, 0);
+
+		gtk_widget_set_size_request (window, 500, 500);
+	}
+
+	if (!GTK_WIDGET_VISIBLE (window))
+		gtk_widget_show_all (window);
+	else
+		gtk_widget_destroy (window);
+
+	return window;
+}
+
+

Added: trunk/extra/demos/grid_data_layout.c
==============================================================================
--- (empty file)
+++ trunk/extra/demos/grid_data_layout.c	Mon Jan  5 20:07:43 2009
@@ -0,0 +1,91 @@
+/* Grids/Automatic data_layout
+ *
+ * A GnomeDbGrid widget where automatic 'data_layout' is used to display
+ * 
+ */
+
+#include <libgnomedb/libgnomedb.h>
+
+extern GdaConnection *demo_cnc;
+extern GdaSqlParser *demo_parser;
+static GtkWidget *window = NULL;
+
+GtkWidget *
+do_grid_data_layout (GtkWidget *do_widget)
+{  
+	if (!window) {
+                GdaStatement *stmt;
+		GtkWidget *vbox;
+		GtkWidget *label;
+		GdaDataModel *model;
+		GtkWidget *grid;
+		GnomeDbRawGrid *raw_grid;
+		GdaSet *data_set;
+		GdaHolder *param;
+		GValue *value;
+		
+		window = gtk_dialog_new_with_buttons ("Grid with the automatic 'data_layout'",
+						      GTK_WINDOW (do_widget),
+						      0,
+						      GTK_STOCK_CLOSE,
+						      GTK_RESPONSE_NONE,
+						      NULL);
+		
+		g_signal_connect (window, "response",
+				  G_CALLBACK (gtk_widget_destroy), NULL);
+		g_signal_connect (window, "destroy",
+				  G_CALLBACK (gtk_widget_destroyed), &window);
+		
+		vbox = gtk_vbox_new (FALSE, 5);
+		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
+		gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
+		
+		label = gtk_label_new ("The following GnomeDbGrid widget displays data from the 'products' table.\n\n"
+				       "\n"
+				       "\n"
+				       ".");
+		gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+		
+		/* Create the demo widget */
+		//stmt = gda_sql_parser_parse_string (demo_parser, "SELECT ref, wh_stored, category, name, price FROM products", NULL, NULL);
+		stmt = gda_sql_parser_parse_string (demo_parser, "SELECT p.ref, p.wh_stored, p.category, p.name, p.price, w.name FROM products p LEFT JOIN warehouses w ON (w.id=p.wh_stored)", NULL, NULL);
+                model = gda_connection_statement_execute_select (demo_cnc, stmt, NULL, NULL);
+                g_object_unref (stmt);
+                gda_data_select_compute_modification_statements (GDA_DATA_SELECT (model), NULL);
+		grid = gnome_db_grid_new (model);
+		g_object_unref (model);
+
+		/* specify that we want to use the 'data_layout' plugin */
+		g_object_get (G_OBJECT (grid), "raw_grid", &raw_grid, NULL);
+		/* data_set = GDA_SET (gnome_db_data_widget_get_current_data (GNOME_DB_DATA_WIDGET (raw_grid))); */
+		/* param = gda_set_get_holder (data_set, "pict"); */
+
+		/* value = gda_value_new_from_string ("data_layout", G_TYPE_STRING); */
+		/* gda_holder_set_attribute (param, GNOME_DB_ATTRIBUTE_PLUGIN, value); */
+		/* gda_value_free (value); */
+		//
+		//gpointer d[2];
+		//d[0] = "./example_automatic_layout_full.xml";
+		//d[1] = "products";
+
+		//g_object_set (G_OBJECT (raw_grid), "data_layout", d, NULL);
+		//
+		gnome_db_utility_set_data_layout_from_file
+			(GNOME_DB_DATA_WIDGET (raw_grid),
+			 "./example_automatic_layout.xml", "products");
+		//
+
+		gtk_box_pack_start (GTK_BOX (vbox), grid, TRUE, TRUE, 0);
+
+		gtk_widget_set_size_request (window, 500, 500);
+	}
+
+	if (!GTK_WIDGET_VISIBLE (window))
+		gtk_widget_show_all (window);
+	else
+		gtk_widget_destroy (window);
+
+	return window;
+}
+
+

Modified: trunk/libgnomedb/gnome-db-basic-form.c
==============================================================================
--- trunk/libgnomedb/gnome-db-basic-form.c	(original)
+++ trunk/libgnomedb/gnome-db-basic-form.c	Mon Jan  5 20:07:43 2009
@@ -69,6 +69,7 @@
 {
         PROP_0,
 	PROP_LAYOUT_SPEC,
+	PROP_DATA_LAYOUT,
 	PROP_PARAMLIST,
 	PROP_HEADERS_SENSITIVE,
 	PROP_SHOW_ACTIONS,
@@ -87,6 +88,7 @@
 	GtkWidget              *entries_table;
 	GtkWidget              *entries_glade;
 	GSList                 *hidden_entries;
+	GtkScrolledWindow      *scrolled_window;  /* Window child. */
 
 	gboolean                headers_sensitive;
 	gboolean                forward_param_updates; /* forward them to the GnomeDbDataEntry widgets ? */
@@ -169,6 +171,10 @@
 					 g_param_spec_pointer ("layout_spec", 
 							       _("Pointer to a GnomeDbFormLayoutSpec structure"), NULL,
 							       G_PARAM_WRITABLE));
+	g_object_class_install_property (object_class, PROP_DATA_LAYOUT,
+					 g_param_spec_pointer ("data_layout", 
+							       _("Pointer to an XML data layout specification"), NULL,
+							       G_PARAM_WRITABLE));
 	g_object_class_install_property (object_class, PROP_PARAMLIST,
 					 g_param_spec_pointer ("paramlist", 
 							       _("List of parameters to show in the form"), NULL,
@@ -413,6 +419,759 @@
 }
 
 static void
+load_xml_data_layout_button (GnomeDbBasicForm  *form,
+			     xmlNodePtr         node,
+			     gpointer           data)
+{
+	g_print ("%s:\n", __func__);
+	g_return_if_fail (form && GNOME_DB_IS_BASIC_FORM (form));
+	g_return_if_fail (data && GTK_IS_TABLE(data));
+
+	gchar *name = NULL;
+	gchar *title = NULL;
+	gchar *script = NULL;
+	gint sequence = 0;
+
+	xmlChar *str;
+	str = xmlGetProp (node, "title");
+	if (str) {
+		title = g_strdup (str);
+		g_print ("title: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "script");
+	if (str) {
+		script = g_strdup (str);
+		g_print ("script: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "sequence");
+	if (str) {
+		sequence = atoi (str);
+		g_print ("sequence: %s\n", str);
+		xmlFree (str);
+	}
+
+	GtkButton *button = (GtkButton *) gtk_button_new_with_mnemonic (title);
+	gtk_widget_show (GTK_WIDGET(button));
+
+	gint n_columns, n_rows;
+	g_object_get (G_OBJECT(data), "n-columns", &n_columns, NULL);
+	g_object_get (G_OBJECT(data), "n-rows", &n_rows, NULL);
+
+	gint col, row;
+	col = 2 * ((sequence - 1) / n_rows);
+	row = (sequence - 1) % n_rows;
+
+	gtk_table_attach (GTK_TABLE(data), GTK_WIDGET(button),
+			  col, col + 2, row, row + 1,
+			  (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
+			  (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), 0, 0);
+
+	xmlNodePtr child;
+	for (child = node->children; child != NULL; child = child->next) {
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "script")) {
+			// load_data_layout_button_script (table, child);
+		}
+	}
+}
+
+static void
+load_xml_data_layout_item (GnomeDbBasicForm  *form,
+			   xmlNodePtr         node,
+			   gpointer           data)
+{
+	g_print ("%s:\n", __func__);
+	g_return_if_fail (form && GNOME_DB_IS_BASIC_FORM (form));
+	g_return_if_fail (data && GTK_IS_TABLE(data));
+
+	gchar *name = NULL;
+	gint sequence = 0;
+	gboolean editable = FALSE;
+	gboolean sort_ascending = FALSE;
+
+	xmlChar *str;
+	str = xmlGetProp (node, "name");
+	if (str) {
+		name = g_strdup (str);
+		g_print ("name: %s\n", str);
+		xmlFree (str);
+	}
+
+	/* str = xmlGetProp (node, "relationship"); */
+	/* if (str) { */
+	/* 	g_print ("relationship: %s\n", str); */
+	/* 	xmlFree (str); */
+	/* } */
+
+	/* str = xmlGetProp (node, "related_relationship"); */
+	/* if (str) { */
+	/* 	g_print ("related_relationship: %s\n", str); */
+	/* 	xmlFree (str); */
+	/* } */
+
+	str = xmlGetProp (node, "sequence");
+	if (str) {
+		sequence = atoi (str);
+		g_print ("sequence: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "editable");
+	if (str) {
+		editable = (*str == 't' || *str == 'T') ? TRUE : FALSE;
+		g_print ("editable: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "sort_ascending");
+	if (str) {
+		sort_ascending = (*str == 't' || *str == 'T') ? TRUE : FALSE;
+		g_print ("sort_ascending: %s\n", str);
+		xmlFree (str);
+	}
+
+	/* GSList *slist = form->priv->set->holders; */
+	/* while (slist != NULL) { */
+	/* 	GdaHolder *holder = slist->data; */
+	/* 	g_print ("SET HOLDER=%s\n", gda_holder_get_id (holder)); */
+	/* 	slist = g_slist_next (slist); */
+	/* } */
+
+	gint n_columns, n_rows;
+	g_object_get (G_OBJECT(data), "n-columns", &n_columns, NULL);
+	g_object_get (G_OBJECT(data), "n-rows", &n_rows, NULL);
+
+	gint col, row;
+	col = 2 * ((sequence - 1) / n_rows);
+	row = (sequence - 1) % n_rows;
+
+	GdaHolder *holder = gda_set_get_holder (form->priv->set, name);
+	g_return_if_fail (holder != NULL);
+
+	/* const gchar *id = gda_holder_get_id (holder); */
+
+	/* const gchar *text; */
+	/* const GValue *value = gda_holder_get_attribute (holder, GDA_ATTRIBUTE_DESCRIPTION); */
+	/* if (value != NULL && G_VALUE_HOLDS(value, G_TYPE_STRING)) */
+	/* 	text = g_value_get_string (value); */
+	/* else */
+	/* 	text = id; */
+	GdaDataModel *model = gnome_db_data_widget_get_gda_model (form);
+
+	const gchar *text;
+	text = gda_utility_data_model_find_column_description (model, name);
+	if (text == NULL)
+		text = gda_holder_get_id (holder);
+
+	GtkLabel *label = GTK_LABEL(gtk_label_new (text));
+	gtk_widget_show (GTK_WIDGET(label));
+	gtk_table_attach (GTK_TABLE(data), GTK_WIDGET(label),
+			  col, col + 1, row, row + 1,
+			  (GtkAttachOptions) GTK_FILL,
+			  (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), 0, 0);
+	gtk_misc_set_alignment (GTK_MISC(label), 0, /* 0 */ 0.5);
+
+	GtkAlignment *alignment = GTK_ALIGNMENT(gtk_alignment_new (0.5, 0.5, 1, 1));
+	gtk_widget_show (GTK_WIDGET(alignment));
+	gtk_table_attach (GTK_TABLE(data), GTK_WIDGET(alignment),
+			  col + 1, col + 2, row, row + 1,
+			  (GtkAttachOptions) (GTK_EXPAND|GTK_FILL),
+			  (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0);
+	gtk_alignment_set_padding (GTK_ALIGNMENT(alignment), 0, 0, 12, 0);
+
+	GtkHBox *hbox = GTK_HBOX(gtk_hbox_new (FALSE, /* 0 */ 6));
+	gtk_widget_show (GTK_WIDGET(hbox));
+	gtk_container_add (GTK_CONTAINER(alignment), GTK_WIDGET(hbox));
+
+	// name hbox (both name and id are equals)
+	gtk_widget_set_name (GTK_WIDGET(hbox), name);
+
+	g_free (name);
+
+	xmlNodePtr child;
+	for (child = node->children; child != NULL; child = child->next) {
+
+		/* if (child->type == XML_ELEMENT_NODE && */
+		/*     !xmlStrcmp (child->name, (const xmlChar *) "formatting")) { */
+		/* } */
+
+		/* if (child->type == XML_ELEMENT_NODE && */
+		/*     !xmlStrcmp (child->name, (const xmlChar *) "title_custom")) { */
+		/* } */
+	}
+}
+
+static gint
+count_items (xmlNodePtr  node)
+{
+	gint n = 0;
+
+	g_return_val_if_fail (node->type == XML_ELEMENT_NODE &&
+			      (!xmlStrcmp (node->name, (const xmlChar *) "data_layout_group") ||
+			       !xmlStrcmp (node->name, (const xmlChar *) "data_layout_portal") ||
+			       !xmlStrcmp (node->name, (const xmlChar *) "data_layout_notebook")), -1);
+
+	if (node->children) {
+		xmlNodePtr child;
+		child = node->children;
+		while (child) {
+			if (child->type == XML_ELEMENT_NODE &&
+			    (!xmlStrcmp (child->name, (const xmlChar *) "data_layout_group") ||
+			     !xmlStrcmp (child->name, (const xmlChar *) "data_layout_item") ||
+			     !xmlStrcmp (child->name, (const xmlChar *) "data_layout_portal") ||
+			     !xmlStrcmp (node->name, (const xmlChar *) "data_layout_notebook") ||
+			     !xmlStrcmp (child->name, (const xmlChar *) "data_layout_button"))) {
+				n++;
+			}
+			child = child->next;
+		}
+	}
+
+	return n;
+}
+
+static void
+load_xml_data_layout_portal (GnomeDbBasicForm  *form,
+			     xmlNodePtr         node,
+			     gpointer           data)
+{
+	g_return_if_fail (form && GNOME_DB_IS_BASIC_FORM (form));
+
+	gchar *name = NULL;
+	gchar *relationship = NULL;
+	gint sequence = 0;
+	gboolean hidden = FALSE;
+	gint columns_count = 1;
+
+	xmlChar *str;
+	str = xmlGetProp (node, "name");
+	if (str) {
+		name = g_strdup (str);
+		g_print ("name: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "relationship");
+	if (str) {
+		relationship = g_strdup (str);
+		g_print ("relationship: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "sequence");
+	if (str) {
+		sequence = atoi (str);
+		g_print ("sequence: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "hidden");
+	if (str) {
+		hidden = *str == 't' || *str == 'T' ? TRUE : FALSE;
+		g_print ("hidden: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "columns_count");
+	if (str) {
+		columns_count = atoi (str);
+		g_print ("columns_count: %s\n", str);
+		xmlFree (str);
+	}
+
+	GtkVBox *vbox;
+	vbox = gtk_vbox_new (FALSE, 0);
+	gtk_widget_show (GTK_WIDGET(vbox));
+
+	gint n_columns, n_rows;
+	g_object_get (G_OBJECT(data), "n-columns", &n_columns, NULL);
+	g_object_get (G_OBJECT(data), "n-rows", &n_rows, NULL);
+
+	gint col, row;
+	col = 2 * ((sequence - 1) / n_rows);
+	row = (sequence - 1) % n_rows;
+
+	gtk_table_attach (GTK_TABLE(data), GTK_WIDGET(vbox),
+			  col, col + 2, row, row + 1,
+			  (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
+			  (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), 0, 0);
+
+	gtk_widget_set_name (vbox, name);
+
+	if (!xmlStrcmp (node->parent->name, (const xmlChar *) "data_layout_group")) {
+
+
+		gint n_columns, n_rows;
+		g_object_get (G_OBJECT(data), "n-columns", &n_columns, NULL);
+		g_object_get (G_OBJECT(data), "n-rows", &n_rows, NULL);
+
+		gint col, row;
+		col = 2 * ((sequence - 1) / n_rows);
+		row = (sequence - 1) % n_rows;
+
+		gtk_table_attach (GTK_TABLE(data), GTK_WIDGET(vbox),
+				  col, col + 2, row, row + 1,
+				  (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
+				  (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), 0, 0);
+	} else
+	if (!xmlStrcmp (node->parent->name, (const xmlChar *) "data_layout_notebook")) {
+
+		GtkLabel *label;
+		gchar *markup = g_strdup_printf ("<b>%s</b>", (name != NULL) ? name : "");
+		label = GTK_LABEL(gtk_label_new (markup));
+		g_free (markup);
+		gtk_widget_show (GTK_WIDGET(label));
+		gtk_label_set_use_markup (label, TRUE);
+
+		gtk_container_add (GTK_CONTAINER(data), GTK_WIDGET(vbox));
+
+		gtk_notebook_set_tab_label (GTK_NOTEBOOK(data),
+					    gtk_notebook_get_nth_page
+					    (GTK_NOTEBOOK(data), sequence - 1),
+					    GTK_WIDGET(label));
+	}
+
+	g_free (name);
+	g_free (relationship);
+}
+
+static void
+load_xml_data_layout_group (GnomeDbBasicForm  *form,
+			    xmlNodePtr         node,
+			    gpointer           data);
+
+static void
+load_xml_data_layout_notebook (GnomeDbBasicForm  *form,
+			       xmlNodePtr         node,
+			       gpointer           data)
+{
+	g_return_if_fail (form && GNOME_DB_IS_BASIC_FORM (form));
+
+	gchar *name = NULL;
+	gint sequence = 0;
+	gint columns_count = 1;
+	gchar *title = NULL;
+
+	xmlChar *str;
+	str = xmlGetProp (node, "name");
+	if (str) {
+		g_print ("name: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "title");
+	if (str) {
+		g_print ("title: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "sequence");
+	if (str) {
+		sequence = atoi (str);
+		g_print ("sequence: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "columns_count");
+	if (str) {
+		g_print ("columns_count: %s\n", str);
+		xmlFree (str);
+	}
+
+	/* GtkLabel *label; */
+	/* gchar *markup = g_strdup_printf ("<b>%s</b>", (title != NULL) ? title : ""); */
+	/* label = GTK_LABEL(gtk_label_new (markup)); */
+	/* g_free (markup); */
+	/* gtk_widget_show (GTK_WIDGET(label)); */
+	/* gtk_label_set_use_markup (label, TRUE); */
+
+	GtkNotebook *notebook;
+	notebook = gtk_notebook_new ();
+	gtk_widget_show (GTK_WIDGET(notebook));
+
+	gint n_columns, n_rows;
+	g_object_get (G_OBJECT(data), "n-columns", &n_columns, NULL);
+	g_object_get (G_OBJECT(data), "n-rows", &n_rows, NULL);
+
+	gint col, row;
+	col = 2 * ((sequence - 1) / n_rows);
+	row = (sequence - 1) % n_rows;
+
+	gtk_table_attach (GTK_TABLE(data), GTK_WIDGET(notebook),
+			  col, col + 2, row, row + 1,
+			  (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
+			  (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), 0, 0);
+
+	xmlNodePtr child;
+	for (child = node->children; child != NULL; child = child->next) {
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_group")) {
+			load_xml_data_layout_group (form, child, /* data */ notebook);
+		}
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_portal")) {
+			load_xml_data_layout_portal (form, child, /* data */ notebook);
+		}
+	}
+
+	g_free (name);
+	g_free (title);
+}
+
+static void
+load_xml_data_layout_group (GnomeDbBasicForm  *form,
+			    xmlNodePtr         node,
+			    gpointer           data)
+{
+	g_print ("%s:\n", __func__);
+	g_return_if_fail (form && GNOME_DB_IS_BASIC_FORM (form));
+	g_return_if_fail (form->priv->scrolled_window != NULL);
+
+	gchar *name = NULL;
+	gint sequence = 0;
+	gint columns_count = 1;
+	gchar *title = NULL;
+
+	xmlChar *str;
+	str = xmlGetProp (node, "name");
+	if (str) {
+		name = g_strdup (str);
+		g_print ("name: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "sequence");
+	if (str) {
+		sequence = atoi (str);
+		g_print ("sequence: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "columns_count");
+	if (str) {
+		columns_count = atoi (str);
+		g_print ("columns_count: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "title");
+	if (str) {
+		title = g_strdup (str);
+		g_print ("title: %s\n", str);
+		xmlFree (str);
+	}
+
+	GtkLabel *label;
+	label = GTK_LABEL(gtk_label_new (NULL));
+	gtk_widget_show (GTK_WIDGET(label));
+
+	gint n = count_items (node);
+
+	gint cols, rows;
+	cols = 2 * columns_count;
+	rows = n / columns_count + n % columns_count;
+
+	GtkTable *table;
+	table = GTK_TABLE(gtk_table_new (rows, cols, FALSE));
+	gtk_widget_show (GTK_WIDGET(table));
+
+	gtk_container_set_border_width (GTK_CONTAINER(table), 6);
+	gtk_table_set_row_spacings (table, 3);
+	gtk_table_set_col_spacings (table, 3);
+
+	if (!xmlStrcmp (node->parent->name, (const xmlChar *) "data_layout_groups")) {
+
+		GtkFrame *frame = GTK_FRAME(gtk_frame_new (NULL));
+		gtk_widget_show (GTK_WIDGET(frame));
+		gtk_frame_set_shadow_type (frame, GTK_SHADOW_NONE);
+
+		GtkAlignment *alignment = GTK_ALIGNMENT(gtk_alignment_new (0.5, 0.5, 1, 1));
+		gtk_widget_show (GTK_WIDGET(alignment));
+		gtk_container_add (GTK_CONTAINER(frame), GTK_WIDGET(alignment));
+		gtk_alignment_set_padding (alignment, 0, 0, 12, 0);
+
+		gtk_container_add (GTK_CONTAINER(alignment), GTK_WIDGET(table));
+
+		gchar *markup = g_strdup_printf ("<b>%s</b>", (title != NULL) ? title : "");
+		gtk_label_set_text (label, markup);
+		g_free (markup);
+		gtk_label_set_use_markup (label, TRUE);
+
+		gtk_frame_set_label_widget (frame, GTK_WIDGET(label));
+
+
+		gtk_box_pack_start (GTK_BOX(data), GTK_WIDGET(frame), FALSE, TRUE, 0);
+	} else
+	if (!xmlStrcmp (node->parent->name, (const xmlChar *) "data_layout_group")) {
+
+		GtkFrame *frame = GTK_FRAME(gtk_frame_new (NULL));
+		gtk_widget_show (GTK_WIDGET(frame));
+		gtk_frame_set_shadow_type (frame, GTK_SHADOW_NONE);
+
+		GtkAlignment *alignment = GTK_ALIGNMENT(gtk_alignment_new (0.5, 0.5, 1, 1));
+		gtk_widget_show (GTK_WIDGET(alignment));
+		gtk_container_add (GTK_CONTAINER(frame), GTK_WIDGET(alignment));
+		gtk_alignment_set_padding (alignment, 0, 0, 12, 0);
+
+		gtk_container_add (GTK_CONTAINER(alignment), GTK_WIDGET(table));
+
+		gchar *markup = g_strdup_printf ("<b>%s</b>", (title != NULL) ? title : "");
+		gtk_label_set_text (label, markup);
+		g_free (markup);
+		gtk_label_set_use_markup (label, TRUE);
+
+		gtk_frame_set_label_widget (frame, GTK_WIDGET(label));
+
+
+		gint n_columns, n_rows;
+		g_object_get (G_OBJECT(data), "n-columns", &n_columns, NULL);
+		g_object_get (G_OBJECT(data), "n-rows", &n_rows, NULL);
+
+		gint col, row;
+		col = 2 * ((sequence - 1) / n_rows);
+		row = (sequence - 1) % n_rows;
+
+		gtk_table_attach (GTK_TABLE(data), GTK_WIDGET(frame),
+				  col, col + 2, row, row + 1,
+				  (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
+				  (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), 0, 0);
+	} else
+	if (!xmlStrcmp (node->parent->name, (const xmlChar *) "data_layout_notebook")) {
+
+		gchar *text = g_strdup ((title != NULL) ? title : "");
+		gtk_label_set_text (label, text);
+		g_free (text);
+
+		gtk_container_add (GTK_CONTAINER(data), GTK_WIDGET(table));
+
+		gtk_notebook_set_tab_label (GTK_NOTEBOOK(data),
+					    gtk_notebook_get_nth_page
+					    (GTK_NOTEBOOK(data), sequence - 1),
+					    GTK_WIDGET(label));
+	}
+
+	xmlNodePtr child;
+	for (child = node->children; child != NULL; child = child->next) {
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_group")) {
+			load_xml_data_layout_group (form, child, /* data */ table);
+		}
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_item")) {
+			load_xml_data_layout_item (form, child, /* data */ table);
+		}
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_portal")) {
+			load_xml_data_layout_portal (form, child, /* data */ table);
+		}
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_notebook")) {
+			load_xml_data_layout_notebook (form, child, /* data */ table);
+		}
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "trans_set")) {
+			/* load_data_layout_group_trans_set (form, child, data); */
+		}
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_button")) {
+			load_xml_data_layout_button (form, child, /* data */ table);
+		}
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_item_groupby")) {
+		}
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_item_header")) {
+		}
+	}
+
+	g_free (name);
+	g_free (title);
+}
+
+static void
+load_xml_data_layout_groups (GnomeDbBasicForm  *form,
+			     xmlNodePtr         node,
+			     gpointer           data)
+{
+	g_print ("%s:\n", __func__);
+	g_return_if_fail (form && GNOME_DB_IS_BASIC_FORM (form));
+	g_return_if_fail (form->priv->scrolled_window == NULL);
+
+	form->priv->scrolled_window = GTK_SCROLLED_WINDOW
+		(gtk_scrolled_window_new (NULL, NULL));
+	gtk_scrolled_window_set_policy (form->priv->scrolled_window,
+					GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_container_border_width (GTK_CONTAINER(form->priv->scrolled_window), 6);
+	gtk_widget_show (GTK_WIDGET(form->priv->scrolled_window));
+
+	GtkVBox *vbox = GTK_VBOX(gtk_vbox_new (FALSE, 0));
+	gtk_widget_show (GTK_WIDGET(vbox));
+
+	gtk_scrolled_window_add_with_viewport (form->priv->scrolled_window,
+					       (GtkWidget *) vbox);
+	/* gtk_box_pack_start (GTK_BOX(form), (GtkWidget *) form->priv->scrolled_window, */
+	/* 		    TRUE, TRUE, 0); */
+
+	xmlNodePtr child;
+	for (child = node->children; child != NULL; child = child->next) {
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_group")) {
+			load_xml_data_layout_group (form, child, /* data */ vbox);
+		}
+	}
+
+}
+
+static void
+load_xml_data_layout (GnomeDbBasicForm  *form,
+		      xmlNodePtr         node,
+		      gpointer           data)
+{
+	g_print ("%s:\n", __func__);
+	g_return_if_fail (form && GNOME_DB_IS_BASIC_FORM (form));
+
+	gchar *parent_table = NULL;
+	gchar *name = NULL;
+
+	xmlChar *str;
+	str = xmlGetProp (node, "parent_table");
+	if (str) {
+		parent_table = g_strdup (str);
+		g_print ("parent_table: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "name");
+	if (str) {
+		name = g_strdup (str);
+		g_print ("name: %s\n", str);
+		xmlFree (str);
+	}
+
+	// Don't recurse unnecessarily
+	gboolean retval = FALSE;
+	if (strcmp ((const gchar *) data, parent_table) != 0 ||
+	    strcmp ("details", name) != 0) {
+		retval = TRUE;
+	}
+	g_free (parent_table);
+	g_free (name);
+	if (retval)
+		return;
+
+	xmlNodePtr child;
+	for (child = node->children; child != NULL; child = child->next) {
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_groups")) {
+			load_xml_data_layout_groups (form, child, data);
+		}
+	}
+
+}
+
+static void
+load_xml_data_layouts (GnomeDbBasicForm  *form,
+		       xmlNodePtr         node,
+		       gpointer           data)
+{
+	g_print ("%s:\n", __func__);
+	g_return_if_fail (form && GNOME_DB_IS_BASIC_FORM (form));
+
+	xmlNodePtr child;
+	for (child = node->children; child != NULL; child = child->next) {
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout")) {
+			load_xml_data_layout (form, child, data);
+		}
+	}
+}
+
+/* static void */
+/* load_xml_table (GnomeDbBasicForm  *form, */
+/* 		xmlNodePtr         node, */
+/* 		gpointer           data) */
+/* { */
+/* 	g_print ("%s:\n", __func__); */
+
+/* 	xmlChar *str; */
+/* 	str = xmlGetProp (node, "name"); */
+/* 	if (str) { */
+/* 		g_print ("name: %s\n", str); */
+/* 		xmlFree (str); */
+/* 	} */
+
+/* 	/\* str = xmlGetProp (node, "title"); *\/ */
+/* 	/\* if (str) { *\/ */
+/* 	/\* 	g_print ("title: %s\n", str); *\/ */
+/* 	/\* 	xmlFree (str); *\/ */
+/* 	/\* } *\/ */
+
+/* 	/\* str = xmlGetProp (node, "hidden"); *\/ */
+/* 	/\* if (str) { *\/ */
+/* 	/\* 	g_print ("hidden: %s\n", str); *\/ */
+/* 	/\* 	xmlFree (str); *\/ */
+/* 	/\* } *\/ */
+
+/* 	/\* str = xmlGetProp (node, "default"); *\/ */
+/* 	/\* if (str) { *\/ */
+/* 	/\* 	g_print ("default: %s\n", str); *\/ */
+/* 	/\* 	xmlFree (str); *\/ */
+/* 	/\* } *\/ */
+
+/* 	xmlNodePtr child; */
+/* 	for (child = node->children; child != NULL; child = child->next) { */
+
+/* 		/\* if (child->type == XML_ELEMENT_NODE && *\/ */
+/* 		/\*     !xmlStrcmp (child->name, (const xmlChar *) "fields")) { *\/ */
+
+/* 		/\* 	load_xml_fields (table, child, data); *\/ */
+/* 		/\* } *\/ */
+
+/* 		/\* if (child->type == XML_ELEMENT_NODE && *\/ */
+/* 		/\*     !xmlStrcmp (child->name, (const xmlChar *) "relationships")) { *\/ */
+
+/* 		/\* 	load_xml_relationships (table, child, data); *\/ */
+/* 		/\* } *\/ */
+
+/* 		if (child->type == XML_ELEMENT_NODE && */
+/* 		    !xmlStrcmp (child->name, (const xmlChar *) "data_layouts")) { */
+
+/* 			load_xml_data_layouts (form, child, data); */
+/* 		} */
+
+/* 		/\* if (child->type == XML_ELEMENT_NODE && *\/ */
+/* 		/\*     !xmlStrcmp (child->name, (const xmlChar *) "reports")) { *\/ */
+
+/* 		/\* 	load_xml_reports (table, child, data); *\/ */
+/* 		/\* } *\/ */
+
+/* 		/\* if (child->type == XML_ELEMENT_NODE && *\/ */
+/* 		/\*     !xmlStrcmp (child->name, (const xmlChar *) "trans_set")) { *\/ */
+
+/* 		/\* 	load_xml_table_trans_set (table, child, data); *\/ */
+/* 		/\* } *\/ */
+/* 	} */
+
+/* } */
+
+static void
 gnome_db_basic_form_set_property (GObject *object,
 				  guint param_id,
 				  const GValue *value,
@@ -467,6 +1226,28 @@
 			g_warning (_("Libglade support not built."));
 #endif
 			break;
+		case PROP_DATA_LAYOUT:
+			{
+				xmlNodePtr node = g_value_get_pointer (value);
+
+				gnome_db_basic_form_clean (form);
+
+				xmlNodePtr child;
+				for (child = node->children; child != NULL; child = child->next) {
+
+					if (child->type == XML_ELEMENT_NODE &&
+					    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_groups")) {
+						load_xml_data_layout_groups (form, child, NULL);
+					}
+				}
+
+				if (form->priv->scrolled_window != NULL) {
+					g_print ("Loaded XML file, reinit interface\n");
+				}
+				gnome_db_basic_form_fill (form);
+	
+			}
+			break;
 		case PROP_PARAMLIST:
 			if (form->priv->set) {
 #ifdef HAVE_LIBGLADE
@@ -616,6 +1397,11 @@
 
 	g_slist_free (form->priv->hidden_entries);
 	form->priv->hidden_entries = NULL;
+
+	if (form->priv->scrolled_window) {
+		gtk_widget_destroy (GTK_WIDGET(form->priv->scrolled_window));
+		form->priv->scrolled_window = NULL;
+	}
 }
 
 static void
@@ -634,6 +1420,23 @@
 static void entry_destroyed_cb (GtkWidget *entry, GnomeDbBasicForm *form);
 static void label_destroyed_cb (GtkWidget *label, GnomeDbBasicForm *form);
 
+static GtkCallback
+find_hbox (GtkWidget  *widget,
+	   gpointer    data)
+{
+	gpointer *d = data;
+
+	if (GTK_IS_CONTAINER(widget)) {
+		const gchar *name = gtk_widget_get_name (widget);
+		if (GTK_IS_HBOX(widget) &&
+		    strcmp (name, (gchar *) *d) == 0)
+			*(++d) = widget;
+		else
+			gtk_container_foreach (GTK_CONTAINER(widget),
+					       (GtkCallback) find_hbox, data);
+	}
+}
+
 /*
  * create the entries in the widget
  */
@@ -814,11 +1617,58 @@
 	}
 #endif
 
+	if (form->priv->scrolled_window != NULL) {
+
+		gtk_box_pack_start (GTK_BOX(form),
+				    (GtkWidget *) form->priv->scrolled_window,
+				    TRUE, TRUE, 0);
+
+		GSList *holders = form->priv->set->holders;
+		GSList *entries = form->priv->entries;
+		while (holders && entries) {
+			GdaHolder *holder = holders->data;
+			GnomeDbDataEntry *entry = entries->data;
+
+			const gchar *id = gda_holder_get_id (holder);
+
+			gpointer d[2];
+			d[0] = (gchar *) id;
+			d[1] = NULL;
+
+			gtk_container_foreach (GTK_CONTAINER(form->priv->scrolled_window),
+					       (GtkCallback) find_hbox, d);
+
+			GtkHBox *hbox = d[1];
+			g_print ("Hbox for: %s -- %p\n", id, hbox);
+
+			if (hbox != NULL) {
+				gboolean expand = gnome_db_data_entry_expand_in_layout
+					(GNOME_DB_DATA_ENTRY (entry));
+				form_expand = form_expand || expand;
+
+				gtk_box_pack_start (GTK_BOX(hbox), GTK_WIDGET(entry),
+						    expand, TRUE, 0);
+				gtk_widget_show (GTK_WIDGET(entry));
+
+				if (!g_object_get_data (G_OBJECT(hbox), "show_actions"))
+					gnome_db_data_entry_set_attributes
+						(GNOME_DB_DATA_ENTRY(entry),
+						 0, GDA_VALUE_ATTR_ACTIONS_SHOWN);
+			}
+
+			holders = g_slist_next (holders);
+			entries = g_slist_next (entries);
+		}
+
+		g_assert (holders == NULL && entries == NULL);
+		gtk_widget_show (GTK_WIDGET(form->priv->scrolled_window));
+	}
+
 	/* 
 	 * There is no layout spec (or the provided one could not be used),
 	 * so use the default tables arrangment
 	 */
-	if (!form->priv->layout_spec) {
+	if (!form->priv->layout_spec && form->priv->scrolled_window == NULL) {
 		GtkWidget *table, *label;
 
 		/* creating a table for all the entries */

Modified: trunk/libgnomedb/gnome-db-data-widget.c
==============================================================================
--- trunk/libgnomedb/gnome-db-data-widget.c	(original)
+++ trunk/libgnomedb/gnome-db-data-widget.c	Mon Jan  5 20:07:43 2009
@@ -373,3 +373,19 @@
 	else 
 		return GNOME_DB_DATA_WIDGET_WRITE_ON_DEMAND;
 }
+
+/**
+ * gnome_db_data_widget_set_data_layout
+ * @iface: an object which implements the #GnomeDbDataWidget interface
+ * @string: xml string
+ *
+ * Sets a data layout according an XML string in the @iface widget .
+ */
+void 
+gnome_db_data_widget_set_data_layout (GnomeDbDataWidget *iface, const gpointer data)
+{
+	g_return_if_fail (GNOME_DB_IS_DATA_WIDGET (iface));
+
+	if (GNOME_DB_DATA_WIDGET_GET_IFACE (iface)->set_data_layout)
+		(GNOME_DB_DATA_WIDGET_GET_IFACE (iface)->set_data_layout) (iface, data);	
+}

Modified: trunk/libgnomedb/gnome-db-data-widget.h
==============================================================================
--- trunk/libgnomedb/gnome-db-data-widget.h	(original)
+++ trunk/libgnomedb/gnome-db-data-widget.h	Mon Jan  5 20:07:43 2009
@@ -59,6 +59,7 @@
 	void                 (* set_gda_model)       (GnomeDbDataWidget *iface, GdaDataModel *model);
 	gboolean             (* set_write_mode)      (GnomeDbDataWidget *iface, GnomeDbDataWidgetWriteMode mode);
 	GnomeDbDataWidgetWriteMode (* get_write_mode)(GnomeDbDataWidget *iface);
+	void                 (* set_data_layout)     (GnomeDbDataWidget *iface, const gpointer data);
 
 	/* signals */
 	void                 (* proxy_changed)       (GnomeDbDataWidget *iface, GdaDataProxy *proxy);

Modified: trunk/libgnomedb/gnome-db-raw-form.c
==============================================================================
--- trunk/libgnomedb/gnome-db-raw-form.c	(original)
+++ trunk/libgnomedb/gnome-db-raw-form.c	Mon Jan  5 20:07:43 2009
@@ -62,6 +62,7 @@
 static void            gnome_db_raw_form_widget_set_gda_model (GnomeDbDataWidget *iface, GdaDataModel *model);
 static gboolean        gnome_db_raw_form_widget_set_write_mode (GnomeDbDataWidget *iface, GnomeDbDataWidgetWriteMode mode);
 static GnomeDbDataWidgetWriteMode gnome_db_raw_form_widget_get_write_mode (GnomeDbDataWidget *iface);
+static void gnome_db_raw_form_set_data_layout (GnomeDbDataWidget  *iface, gpointer  data);
 
 struct _GnomeDbRawFormPriv
 {
@@ -134,6 +135,7 @@
 	iface->set_gda_model = gnome_db_raw_form_widget_set_gda_model;
 	iface->set_write_mode = gnome_db_raw_form_widget_set_write_mode;
 	iface->get_write_mode = gnome_db_raw_form_widget_get_write_mode;
+	iface->set_data_layout = gnome_db_raw_form_set_data_layout;
 }
 
 static void
@@ -1022,3 +1024,15 @@
 
 	return form->priv->write_mode;
 }
+
+static void
+gnome_db_raw_form_set_data_layout (GnomeDbDataWidget  *iface, gpointer  data)
+{
+	GnomeDbRawForm *raw_form;
+	
+	g_return_if_fail (GNOME_DB_IS_RAW_FORM (iface));
+	raw_form = GNOME_DB_RAW_FORM (iface);
+	g_return_if_fail (raw_form->priv);
+
+	g_object_set (G_OBJECT (raw_form), "data_layout", data, NULL);
+}

Modified: trunk/libgnomedb/gnome-db-raw-grid.c
==============================================================================
--- trunk/libgnomedb/gnome-db-raw-grid.c	(original)
+++ trunk/libgnomedb/gnome-db-raw-grid.c	Mon Jan  5 20:07:43 2009
@@ -69,6 +69,7 @@
 static void            gnome_db_raw_grid_widget_set_gda_model             (GnomeDbDataWidget *iface, GdaDataModel *model);
 static gboolean        gnome_db_raw_grid_widget_set_write_mode (GnomeDbDataWidget *iface, GnomeDbDataWidgetWriteMode mode);
 static GnomeDbDataWidgetWriteMode gnome_db_raw_grid_widget_get_write_mode (GnomeDbDataWidget *iface);
+static void            gnome_db_raw_grid_set_data_layout (GnomeDbDataWidget  *iface, gpointer  data);
 
 typedef struct {
 	GdaSetGroup     *group;
@@ -76,6 +77,7 @@
 	GtkCellRenderer *info_cell;
 	gboolean         info_shown;
 	gboolean         data_locked; /* TRUE if no modification allowed on that column */
+        gchar           *tooltip_text;
 } ColumnData;
 
 #define COLUMN_DATA(x) ((ColumnData *)(x))
@@ -91,6 +93,8 @@
 
 	GSList                     *columns_data; /* list of ColumnData */
 
+	GSList                     *reordered_indexes;  /* Indexes of the reordered columns. */
+
 	gboolean                    default_show_info_cell;
 	gboolean                    default_show_global_actions;
 
@@ -123,6 +127,7 @@
 {
         PROP_0,
 	PROP_MODEL,
+	PROP_DATA_LAYOUT,
 	PROP_INFO_CELL_VISIBLE,
 	PROP_GLOBAL_ACTIONS_VISIBLE
 };
@@ -215,6 +220,7 @@
 	iface->set_gda_model = gnome_db_raw_grid_widget_set_gda_model;
 	iface->set_write_mode = gnome_db_raw_grid_widget_set_write_mode;
 	iface->get_write_mode = gnome_db_raw_grid_widget_get_write_mode;	
+	iface->set_data_layout = gnome_db_raw_grid_set_data_layout;
 }
 
 static void
@@ -256,6 +262,11 @@
 	g_object_class_install_property (object_class, PROP_MODEL,
                                          g_param_spec_object ("model", _("Data to display"), NULL, GDA_TYPE_DATA_MODEL,
 							      G_PARAM_READABLE | G_PARAM_WRITABLE));
+	
+	g_object_class_install_property (object_class, PROP_DATA_LAYOUT,
+					 g_param_spec_pointer ("data_layout", 
+							       _("Pointer to an XML data layout specification"), NULL,
+							       G_PARAM_WRITABLE));
 	g_object_class_install_property (object_class, PROP_INFO_CELL_VISIBLE,
                                          g_param_spec_boolean ("info_cell_visible", NULL, _("Info cell visible"), FALSE,
                                                                G_PARAM_READABLE | G_PARAM_WRITABLE));
@@ -358,6 +369,339 @@
 }
 
 static void
+load_xml_data_layout_item (GnomeDbRawGrid  *grid,
+			   xmlNodePtr       node,
+			   gpointer         data)
+{
+	g_print ("%s:\n", __func__);
+	g_return_if_fail (grid && GNOME_DB_IS_RAW_GRID (grid));
+
+	gchar *name = NULL;
+	gint sequence = 0;
+	gboolean editable = FALSE;
+	gboolean sort_ascending = FALSE;
+
+	xmlChar *str;
+	str = xmlGetProp (node, "name");
+	if (str) {
+		name = g_strdup (str);
+		g_print ("name: %s\n", str);
+		xmlFree (str);
+	}
+
+	/* str = xmlGetProp (node, "relationship"); */
+	/* if (str) { */
+	/* 	g_print ("relationship: %s\n", str); */
+	/* 	xmlFree (str); */
+	/* } */
+
+	/* str = xmlGetProp (node, "related_relationship"); */
+	/* if (str) { */
+	/* 	g_print ("related_relationship: %s\n", str); */
+	/* 	xmlFree (str); */
+	/* } */
+
+	str = xmlGetProp (node, "sequence");
+	if (str) {
+		sequence = atoi (str);
+		g_print ("sequence: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "editable");
+	if (str) {
+		editable = (*str == 't' || *str == 'T') ? TRUE : FALSE;
+		g_print ("editable: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "sort_ascending");
+	if (str) {
+		sort_ascending = (*str == 't' || *str == 'T') ? TRUE : FALSE;
+		g_print ("sort_ascending: %s\n", str);
+		xmlFree (str);
+	}
+
+	/* GSList *slist = grid->priv->set->holders; */
+	/* while (slist != NULL) { */
+	/* 	GdaHolder *holder = slist->data; */
+	/* 	g_print ("SET HOLDER=%s\n", gda_holder_get_id (holder)); */
+	/* 	slist = g_slist_next (slist); */
+	/* } */
+
+	//GdaHolder *holder = gda_set_get_holder (grid->priv->set, name);
+	GdaHolder *holder = gda_set_get_holder (GDA_SET(grid->priv->iter), name);
+	g_return_if_fail (holder != NULL);
+
+	gint index = g_slist_index (GDA_SET(grid->priv->iter)->holders, holder);
+
+	grid->priv->reordered_indexes = g_slist_insert (grid->priv->reordered_indexes,
+						     GINT_TO_POINTER(index),
+						     sequence - 1);
+
+        GdaSetGroup *group = gda_set_get_group (GDA_SET(grid->priv->iter), holder);
+        g_return_if_fail (group);
+
+        ColumnData *column_data = get_column_data (grid, group);
+        g_return_if_fail (column_data);
+
+        column_data->tooltip_text = g_strdup ((const gchar *) data);
+        //g_print ("*** %s\n", column_data->tooltip_text);
+
+	gint position = g_slist_index (GDA_SET(grid->priv->iter)->holders, holder);
+	GtkTreeViewColumn *column = gtk_tree_view_get_column (GTK_TREE_VIEW(grid), position);
+	g_return_if_fail (column != NULL);
+
+	// ((GdaDataSelect *) model)->prep_stmt
+	GdaDataModel *model = grid->priv->data_model;
+
+	const gchar *text;
+	text = gda_utility_data_model_find_column_description (model, name);
+	if (text == NULL)
+		text = gda_holder_get_id (holder);
+
+	gtk_tree_view_column_set_title (column, text);
+
+	xmlNodePtr child;
+	for (child = node->children; child != NULL; child = child->next) {
+
+		/* if (child->type == XML_ELEMENT_NODE && */
+		/*     !xmlStrcmp (child->name, (const xmlChar *) "formatting")) { */
+		/* } */
+
+		/* if (child->type == XML_ELEMENT_NODE && */
+		/*     !xmlStrcmp (child->name, (const xmlChar *) "title_custom")) { */
+		/* } */
+	}
+
+}
+
+static void
+load_xml_data_layout_group (GnomeDbRawGrid  *grid,
+			    xmlNodePtr       node,
+			    gpointer         data)
+{
+	g_print ("%s:\n", __func__);
+	g_return_if_fail (grid && GNOME_DB_IS_RAW_GRID (grid));
+
+	gchar *name = NULL;
+	gint sequence = 0;
+	gint columns_count = 1;
+	gchar *title = NULL;
+
+	xmlChar *str;
+	str = xmlGetProp (node, "name");
+	if (str) {
+		name = g_strdup (str);
+		g_print ("name: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "sequence");
+	if (str) {
+		sequence = atoi (str);
+		g_print ("sequence: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "columns_count");
+	if (str) {
+		columns_count = atoi (str);
+		g_print ("columns_count: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "title");
+	if (str) {
+		title = g_strdup (str);
+		g_print ("title: %s\n", str);
+		xmlFree (str);
+	}
+
+	xmlNodePtr child;
+	for (child = node->children; child != NULL; child = child->next) {
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_group")) {
+			load_xml_data_layout_group (grid, child, data);
+		}
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_item")) {
+			load_xml_data_layout_item (grid, child, /* data *//* table */ title);
+		}
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_portal")) {
+		}
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_notebook")) {
+		}
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "trans_set")) {
+			/* load_xml_trans_set (grid, child, data); */
+		}
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_button")) {
+		}
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_item_groupby")) {
+		}
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_item_header")) {
+		}
+	}
+
+	g_free (name);
+	g_free (title);
+}
+
+static void
+load_xml_data_layout_groups (GnomeDbRawGrid  *grid,
+			     xmlNodePtr       node,
+			     gpointer         data)
+{
+	g_print ("%s:\n", __func__);
+	g_return_if_fail (grid && GNOME_DB_IS_RAW_GRID (grid));
+
+	xmlNodePtr child;
+	for (child = node->children; child != NULL; child = child->next) {
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_group")) {
+			load_xml_data_layout_group (grid, child, /* data */ NULL);
+		}
+	}
+
+}
+
+static void
+load_xml_data_layout (GnomeDbRawGrid  *grid,
+		      xmlNodePtr       node,
+		      gpointer         data)
+{
+	g_print ("%s:\n", __func__);
+	g_return_if_fail (grid && GNOME_DB_IS_RAW_GRID (grid));
+
+	gchar *parent_table = NULL;
+	gchar *name = NULL;
+
+	xmlChar *str;
+	str = xmlGetProp (node, "parent_table");
+	if (str) {
+		parent_table = g_strdup (str);
+		g_print ("parent_table: %s\n", str);
+		xmlFree (str);
+	}
+
+	str = xmlGetProp (node, "name");
+	if (str) {
+		name = g_strdup (str);
+		g_print ("name: %s\n", str);
+		xmlFree (str);
+	}
+
+	// Don't recurse unnecessarily
+	gboolean retval = FALSE;
+	if (strcmp ((const gchar *) data, parent_table) != 0 ||
+	    strcmp ("list", name) != 0) {
+		retval = TRUE;
+	}
+	g_free (parent_table);
+	g_free (name);
+	if (retval)
+		return;
+
+	xmlNodePtr child;
+	for (child = node->children; child != NULL; child = child->next) {
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_groups")) {
+			load_xml_data_layout_groups (grid, child, data);
+		}
+	}
+
+}
+
+static void
+load_xml_data_layouts (GnomeDbRawGrid  *grid,
+		       xmlNodePtr       node,
+		       gpointer         data)
+{
+	g_print ("%s:\n", __func__);
+	g_return_if_fail (grid && GNOME_DB_IS_RAW_GRID (grid));
+
+	xmlNodePtr child;
+	for (child = node->children; child != NULL; child = child->next) {
+
+		if (child->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (child->name, (const xmlChar *) "data_layout")) {
+			load_xml_data_layout (grid, child, data);
+		}
+
+	}
+
+}
+
+static gboolean
+gnome_db_raw_grid_query_tooltip (GtkWidget   *widget,
+				 gint         x,
+				 gint         y,
+				 gboolean     keyboard_tip,
+				 GtkTooltip  *tooltip,
+				 gpointer     data)
+{
+	GtkTreeIter iter;
+	GtkTreeView *tree_view = GTK_TREE_VIEW(widget);
+
+	if (!gtk_tree_view_get_tooltip_context (tree_view, &x, &y,
+						keyboard_tip,
+						NULL, NULL, NULL))
+		return FALSE;
+
+	gint position = 0;
+	guint col_x = 0;
+	GList *columns = gtk_tree_view_get_columns (tree_view), *list = columns;
+	while (list != NULL) {
+		GtkTreeViewColumn *column = list->data;
+		if (x >= col_x && x < (col_x + column->width)) {
+			break;
+		} else
+			col_x += column->width;
+		++position;
+		list = g_list_next (list);
+	}
+	if (list == NULL)
+		return FALSE;
+
+	GnomeDbRawGrid *grid = GNOME_DB_RAW_GRID(tree_view);
+	ColumnData *column_data = (ColumnData *)
+		(g_slist_nth (grid->priv->columns_data, position)->data);
+	g_return_val_if_fail (column_data, FALSE);
+
+	g_list_free (columns);
+
+	if (column_data->tooltip_text == NULL)
+		return FALSE;
+
+	gchar *markup = g_strdup_printf ("<i>%s</i> <b>%s</b>",
+					 _("Group:"), column_data->tooltip_text);
+	gtk_tooltip_set_markup (tooltip, markup);
+	g_free (markup);
+        /* GSList *slist = grid->priv->columns_data; */
+        /* while (slist) { */
+        /*         g_print ("--- %s\n", COLUMN_DATA (slist->data)->tooltip_text); */
+        /*         slist = g_slist_next (slist); */
+        /* } */
+
+	return TRUE;
+}
+
+static void
 gnome_db_raw_grid_set_property (GObject *object,
 				guint param_id,
 				const GValue *value,
@@ -413,6 +757,74 @@
 				break;
 			}
 				
+		case PROP_DATA_LAYOUT:
+			{
+				xmlNodePtr node = g_value_get_pointer (value);
+
+				xmlNodePtr child;
+				for (child = node->children; child != NULL; child = child->next) {
+
+					if (child->type == XML_ELEMENT_NODE &&
+					    !xmlStrcmp (child->name, (const xmlChar *) "data_layout_groups")) {
+						load_xml_data_layout_groups (grid, child, NULL);
+					}
+				}
+
+				if (grid->priv->reordered_indexes != NULL) {
+					g_print ("Loaded XML file, reinit interface\n");
+
+					GList *columns = gtk_tree_view_get_columns (GTK_TREE_VIEW(grid));
+
+					GtkTreeViewColumn *prev_column = NULL;
+					GSList *columns_data = NULL;
+
+					GSList *reordered_indexes = grid->priv->reordered_indexes;
+					while (reordered_indexes != NULL) {
+						gint position = GPOINTER_TO_INT(reordered_indexes->data);
+
+						GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN
+							(g_list_nth (columns, position)->data);
+
+						gtk_tree_view_move_column_after (GTK_TREE_VIEW(grid),
+										 column, prev_column);
+						prev_column = column;
+
+						// Data columns are handled
+						ColumnData *column_data = (ColumnData *)
+							(g_slist_nth (grid->priv->columns_data, position)->data);
+						columns_data = g_slist_append (columns_data, column_data);
+
+						reordered_indexes = g_slist_next (reordered_indexes);
+					}
+					g_list_free (columns);
+
+					g_slist_free (grid->priv->columns_data);
+					grid->priv->columns_data = columns_data;
+
+					// Remove unnecessary columns according layout
+					columns = gtk_tree_view_get_columns (GTK_TREE_VIEW(grid));
+
+					gint num_columns = g_list_length (columns);
+					gint num_reordered_indexes = g_slist_length (grid->priv->reordered_indexes);
+					if (num_reordered_indexes < num_columns) {
+						gint i;
+						for (i = num_reordered_indexes; i < num_columns; ++i) {
+							GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN
+								(g_list_nth (columns, i)->data);
+							gtk_tree_view_remove_column (GTK_TREE_VIEW(grid), column);
+						}
+					}
+					g_list_free (columns);
+
+					g_object_set (G_OBJECT(grid), "has-tooltip", TRUE, NULL);
+					g_signal_connect (G_OBJECT(grid), "query-tooltip",
+							  G_CALLBACK(gnome_db_raw_grid_query_tooltip), NULL);
+				}
+
+			}
+
+			break;
+				
 		case PROP_INFO_CELL_VISIBLE: 
 			{
 				GSList *list = grid->priv->columns_data;
@@ -576,6 +988,7 @@
 			column_data->group = group;
 			column_data->info_shown = grid->priv->default_show_info_cell;
 			column_data->data_locked = FALSE;
+			column_data->tooltip_text = NULL;
 			grid->priv->columns_data = g_slist_append (grid->priv->columns_data, column_data);
 		}
 
@@ -2095,6 +2508,7 @@
 	if (grid->priv->columns_data) {
 		GSList *list = grid->priv->columns_data;
 		while (list) {
+                        g_free (((ColumnData *) (list->data))->tooltip_text);
 			g_free (list->data);
 			list = g_slist_next (list);
 		}
@@ -2283,6 +2697,7 @@
 	if (grid->priv->columns_data) {
 		GSList *list = grid->priv->columns_data;
 		while (list) {
+                        g_free (((ColumnData *) (list->data))->tooltip_text);
 			g_free (list->data);
 			list = g_slist_next (list);
 		}
@@ -2354,3 +2769,16 @@
 
 	return grid->priv->write_mode;
 }
+
+static void
+gnome_db_raw_grid_set_data_layout (GnomeDbDataWidget  *iface, gpointer  data)
+{
+	GnomeDbRawGrid *raw_grid;
+	
+	g_return_if_fail (GNOME_DB_IS_RAW_GRID (iface));
+	raw_grid = GNOME_DB_RAW_GRID (iface);
+	g_return_if_fail (raw_grid->priv);
+
+	g_object_set (G_OBJECT (raw_grid), "data_layout", data, NULL);
+}
+

Modified: trunk/libgnomedb/utility.c
==============================================================================
--- trunk/libgnomedb/utility.c	(original)
+++ trunk/libgnomedb/utility.c	Mon Jan  5 20:07:43 2009
@@ -25,6 +25,7 @@
 #include <glib/gi18n-lib.h>
 #include "gnome-db-data-entry.h"
 #include "gnome-db-decl.h"
+#include "libgnomedb.h"
 
 /**
  * gnome_db_utility_entry_build_actions_menu
@@ -501,3 +502,80 @@
 	gtk_dialog_run (GTK_DIALOG (dlg));
 	gtk_widget_destroy (dlg);
 }
+
+/**
+ * gnome_db_utility_set_data_layout_from_file
+ * @data_widget:
+ * @file_name: XML data layout file
+ *
+ * Set a data layout to @data_widget according specifications in @file_name
+ */
+void
+gnome_db_utility_set_data_layout_from_file (GnomeDbDataWidget  *data_widget, const gchar  *file_name, const gchar  *parent_table)
+{
+	g_return_if_fail (file_name != NULL);
+	g_return_if_fail (parent_table != NULL);
+
+	xmlDocPtr doc;
+	doc = xmlParseFile (file_name);
+	if (doc == NULL) {
+		g_warning (_("'%s' Document not parsed successfully\n"), file_name);
+		return;
+	}
+
+	/* xmlDtdPtr dtd; */
+	/* dtd = xmlParseDTD (NULL, "data_layouts.dtd"); */
+	/* if (dtd == NULL) { */
+	/* 	g_warning (_("DTD not parsed successfully\n")); */
+	/* 	return; */
+	/* } */
+
+	/* Get the root element node */
+	xmlNodePtr root_node = NULL;
+	root_node = xmlDocGetRootElement (doc);
+
+	/* Must have root element, a name and the name must be "data_layouts" */
+	if (!root_node ||
+	    !root_node->name ||
+	    xmlStrcmp (root_node->name, "data_layouts")) {
+		xmlFreeDoc (doc);
+		return;
+	}
+
+	xmlNodePtr node, child;
+	for (node = root_node->children; node != NULL; node = node->next) {
+
+		if (node->type == XML_ELEMENT_NODE &&
+		    !xmlStrcmp (node->name, (const xmlChar *) "data_layout")) {
+			gboolean retval = FALSE;
+			xmlChar *str;
+
+			str = xmlGetProp (node, "parent_table");
+			if (str) {
+				if (strcmp (str, parent_table) == 0)
+					retval = TRUE;
+				//g_print ("parent_table: %s\n", str);
+				xmlFree (str);
+			}
+
+			str = xmlGetProp (node, "name");
+			if (str) {
+				if (retval == TRUE &&
+				    ((GNOME_DB_IS_RAW_GRID(data_widget) &&
+				      strcmp (str, "list") == 0) ||
+				     (GNOME_DB_IS_RAW_FORM(data_widget) &&
+				      strcmp (str, "details") == 0)))  // Now proceed
+					gnome_db_data_widget_set_data_layout (data_widget, node);
+				//g_print ("name: %s\n", str);
+				xmlFree (str);
+			}
+		}
+	}
+
+	/* Free the document */
+	xmlFreeDoc (doc);
+
+	/* Free the global variables that may
+	 * have been allocated by the parser */
+	xmlCleanupParser ();
+}

Modified: trunk/libgnomedb/utility.h
==============================================================================
--- trunk/libgnomedb/utility.h	(original)
+++ trunk/libgnomedb/utility.h	Mon Jan  5 20:07:43 2009
@@ -50,3 +50,4 @@
  */
 gboolean   gnome_db_utility_display_error_with_keep_or_discard_choice (GnomeDbDataWidget *form, GError *filled_error);
 void       gnome_db_utility_display_error                             (GnomeDbDataWidget *form, gboolean can_discard, GError *filled_error);
+void       gnome_db_utility_set_data_layout_from_file (GnomeDbDataWidget  *data_widget, const gchar  *file_name,  const gchar  *parent_table);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]