Sophie

Sophie

distrib > Mandriva > 9.2 > i586 > by-pkgid > 0453bcaf7bb5ad036996f9b24ca9fa16 > files > 97

gaby-2.0.2-4mdk.i586.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML
><HEAD
><TITLE
>Views</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK
REL="HOME"
TITLE="Gaby's documentation"
HREF="index.html"><LINK
REL="UP"
TITLE="Gaby Developers' Guide"
HREF="p489.html"><LINK
REL="PREVIOUS"
TITLE="Structures"
HREF="x570.html"><LINK
REL="NEXT"
TITLE="Actions"
HREF="c782.html"></HEAD
><BODY
CLASS="CHAPTER"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Gaby's documentation</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x570.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="c782.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="CHAPTER"
><H1
><A
NAME="PLUGIN-VIEW"
></A
>Chapter 9. Views</H1
><DIV
CLASS="IMPORTANT"
><P
></P
><TABLE
CLASS="IMPORTANT"
WIDTH="100%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/important.gif"
HSPACE="5"
ALT="Important"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>I changed the view plug-in API recently and you should skip
this chapter waiting I rewrote it</P
></TD
></TR
></TABLE
></DIV
><P
>There is a sample plugin logically called 'hello' which is a minimal
implementation of a classic (it only shows one record at the same time) plugin.</P
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="AEN684"
>9.1. Initialization</A
></H1
><P
>When Gaby starts it reads the description of the database to be used (which is
guess from the name you used to invoke Gaby or from the --as flags). I'll not
talk about this file here but somewhere it will have a line like this :
<B
CLASS="COMMAND"
>viewable as form,list,xlist.</B
>
from which Gaby "guess" it has to load form, list and xlist plugins. The first
step is to initialize those plugins <A
NAME="AEN688"
HREF="#FTN.AEN688"
><SPAN
CLASS="footnote"
>[1]</SPAN
></A
> which is done looking for a function like this in the plugin :</P
><DIV
CLASS="FUNCSYNOPSIS"
><P
></P
><A
NAME="AEN690"
></A
><PRE
CLASS="FUNCSYNOPSISINFO"
>#include &lt;gaby.h&gt;</PRE
><CODE
CLASS="FUNCDEF"
>int init_view_plugin</CODE
>(ViewPluginData *vpd);<P
></P
></DIV
><DIV
CLASS="IMPORTANT"
><P
></P
><TABLE
CLASS="IMPORTANT"
WIDTH="100%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/important.gif"
HSPACE="5"
ALT="Important"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>If you want your plug-in to support being part of the huge
binary produced when configuring with <SPAN
CLASS="QUOTE"
>"Miguel wishes"</SPAN
> you'll have
to enclose the function in a 
<VAR
CLASS="LITERAL"
>#ifndef FOLLOW_MIGUEL</VAR
>.</P
></TD
></TR
></TABLE
></DIV
><P
>The ViewPluginData structure is defined in <TT
CLASS="FILENAME"
>gaby.h</TT
> (like
all structures used in Gaby) :


<PRE
CLASS="PROGRAMLISTING"
>typedef struct _ViewPluginData ViewPluginData;

struct _ViewPluginData {
        GModule *handle;
        int     (*init_plugin)  ( ViewPluginData *vpd );

        void    (*view_create)  (gabywindow *win, gboolean first);

        void    (*view_fill)    (gabywindow *win);
        void    (*view_save)    (gabywindow *win);
#ifndef NO_GTK
        GtkWidget* (*configure) (ViewPluginData *vpd);
#endif

        gchar *name;
        gchar *i18n_name;
        enum {
                ALL_RECORDS = 1 &lt;&lt; 0,
                ONE_RECORD = 1 &lt;&lt; 1,
                FILTER = 1 &lt;&lt; 2
        } type;
        enum {
                NONE = 0,
                EDITABLE = 1 &lt;&lt; 0,
                FILTERABLE = 1 &lt;&lt; 1,
        } capabilities;
};</PRE
>&#13;</P
><P
>I believe you already have a good picture of what will have its place in
<CODE
CLASS="FUNCTION"
>init_view_plugin</CODE
>. To confirm :

<DIV
CLASS="EXAMPLE"
><A
NAME="AEN705"
></A
><P
><B
>Example 9-1. Initializing a view plug-in</B
></P
><PRE
CLASS="PROGRAMLISTING"
>int init_view_plugin(ViewPluginData *vpd)
{
        vpd-&gt;view_create = hello_create;
        vpd-&gt;view_fill = hello_fill;
        vpd-&gt;configure = NULL;

        vpd-&gt;name = "hello";
        vpd-&gt;i18n_name = _("Hello");
        vpd-&gt;type = ONE_RECORD;
        vpd-&gt;capabilities = NONE;

        return 0;
}</PRE
></DIV
>&#13;</P
><P
><SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>FIXME</I
></SPAN
>: a few comments would be welcomed.</P
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="AEN710"
>9.1. View creation</A
></H1
><P
>It is the <B
CLASS="COMMAND"
>vpd-&#62;view_create = hello_create;</B
> with 
<B
CLASS="COMMAND"
>hello_create</B
>
being a function defined like this :

<DIV
CLASS="FUNCSYNOPSIS"
><P
></P
><A
NAME="AEN715"
></A
><CODE
CLASS="FUNCDEF"
>mstatic void* hello_create</CODE
>(gabywindow* window, gboolean first);<P
></P
></DIV
>

<DIV
CLASS="IMPORTANT"
><P
></P
><TABLE
CLASS="IMPORTANT"
WIDTH="100%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/important.gif"
HSPACE="5"
ALT="Important"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
><CODE
CLASS="FUNCTION"
>hello_create</CODE
> is defined as a <SPAN
CLASS="QUOTE"
>"mstatic"</SPAN
>
function, this means that it will be static <SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>excepted</I
></SPAN
> when
compiled with Miguel wishes.</P
></TD
></TR
></TABLE
></DIV
>

Its purpose is to create a widget which will then be put either in the main
window of Gaby either in a separate window. This widget will then be recorded
at <CODE
CLASS="STRUCTNAME"
>window-&#62;widget</CODE
>. This means that the widget has
<SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>not</I
></SPAN
> to be a  window with title bar and the like. It will
 commonly be a <B
CLASS="COMMAND"
>Gtk[V,H]Box</B
> but any GTK container will work.&#13;</P
><P
>Let's have an example :

<DIV
CLASS="EXAMPLE"
><A
NAME="AEN731"
></A
><P
><B
>Example 9-2. Creating a view</B
></P
><PRE
CLASS="PROGRAMLISTING"
>mstatic void hello_create ( gabywindow *window, gboolean first )
{
        GtkWidget *vbox;
        GtkWidget *label;
        GtkWidget *hbb;
        GtkWidget *button;
        int *id = &amp;(window-&gt;id);
        record *r;

        r = table_first(v-&#62;subtable-&#62;table, -1);
        *id = ( r == NULL ? 0 : r-&#62;id );

        r = table_first(window-&#62;view-&#62;subtable-&#62;table, -1);
        *id = ( r == NULL ? 0 : r-&#62;id );

        vbox = gtk_vbox_new(FALSE,0);
        window-&#62;widget = vbox;

        label = gtk_label_new("");
        gtk_widget_show(label);
        gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);

        hbb = gtk_hbutton_box_new();
        gtk_widget_show(hbb);
        gtk_box_pack_start(GTK_BOX(vbox), hbb, FALSE, TRUE, 0);

        button = gtk_button_new_with_label(_("Previous"));
        gtk_widget_show(button);
        gtk_signal_connect(GTK_OBJECT(button), "clicked", \
                                GTK_SIGNAL_FUNC(previous_clicked), window);
        gtk_container_add(GTK_CONTAINER(hbb), button);

        button = gtk_button_new_with_label(_("Next"));
        gtk_widget_show(button);
        gtk_signal_connect(GTK_OBJECT(button), "clicked", \
                                GTK_SIGNAL_FUNC(next_clicked), window);
        gtk_container_add(GTK_CONTAINER(hbb), button);

        gtk_widget_show(vbox);

        return;
}</PRE
></DIV
>

Most lines are typical GTK as described in GTK documentation. The interesting
lines are :

<PRE
CLASS="PROGRAMLISTING"
>        int *id = &amp;(window-&#62;id);
        record *r;
        r = table_first(v-&#62;subtable-&#62;table, -1);
        *id = ( r == NULL ? 0 : r-&#62;id );</PRE
>

This sets the record you're currently on to the first record of the table; or
to 0 if the table is empty.
&#13;</P
><P
>Note that unlike the previous version of the API you don't have to play
with lots of <CODE
CLASS="FUNCTION"
>gtk_object_get_data</CODE
> in your plug-ins, making
them cleaner.</P
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="AEN737"
>9.1. View filling</A
></H1
><P
>As I just said (and as the title says) this is the function which will take
datas from a table to show them in the beautiful widgets you just created.</P
><P
>Here is the code :

<DIV
CLASS="EXAMPLE"
><A
NAME="AEN741"
></A
><P
><B
>Example 9-3. Filling a view</B
></P
><PRE
CLASS="PROGRAMLISTING"
>mstatic void hello_fill ( gabywindow *window )
{
        view *v = window-&#62;view;
        int *id = &amp;(window-&#62;id);
        GtkWidget *label = gtk_object_get_data(GTK_OBJECT(win), "label");
        GString *str;
	
        if ( *id == 0 ) {
                gtk_label_set_text(GTK_LABEL(label), _("Hello, world !"));
                return;
        }

        str = get_subtable_stringed_field_id(v-&#62;subtable, *id, 0 );

        str = g_string_prepend(str, _("Hello, "));
        gtk_label_set_text(GTK_LABEL(label), str-&#62;str);
        g_string_free(str, 1);
}</PRE
></DIV
>

<P
>The first thing is to retrieve the label widget we'll use to show the
information :

<PRE
CLASS="PROGRAMLISTING"
>        GtkWidget *label = gtk_object_get_data(GTK_OBJECT(win), "label");</PRE
>&#13;</P
>

<P
>Then we check if we have a record to show, since record ids start at 1, 0 means
no record to show :

<PRE
CLASS="PROGRAMLISTING"
>        if ( *id == 0 ) {
                gtk_label_set_text(GTK_LABEL(label), _("Hello, world !"));
                return;
        }</PRE
></P
>

<P
>The easy case is done. Now we know that we have a real record to show. Since
this is just an example, we'll just show one field and to be sure it will work
with any tables we'll show the first one.

<PRE
CLASS="PROGRAMLISTING"
>        str = get_subtable_stringed_field_id(v-&#62;subtable, *id, 0 );</PRE
>

It is now easy as adding "Hello" before the string we got and showing it in a
widget :

<PRE
CLASS="PROGRAMLISTING"
>        str = g_string_prepend(str, _("Hello, "));
        gtk_label_set_text(GTK_LABEL(label), str-&#62;str);</PRE
>

It is now finished, we free the string and leave.&#13;</P
>

  <DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="AEN751"
>9.1. Moving between records</A
></H1
><P
>&#13;We have two buttons in our view (namely "Previous" and "Next"),
their purpose is evident, the way it is done also (hem hem).&#13;</P
><P
>&#13;<PRE
CLASS="PROGRAMLISTING"
>static void previous_clicked(GtkWidget *button, gabywindow *window)
{
        record *r;
        view *v = window-&#62;view;
        int *id = &amp;(window-&#62;id);

        r = get_record_no(v-&#62;subtable-&#62;table, *id);
        r = table_prev(v-&#62;subtable-&#62;table, r, -1);
        *id = ( r == NULL ) ? 0 : r-&#62;id;
        hello_fill(win);

        update_bound_windows(window);
}</PRE
>


The interesting is <CODE
CLASS="FUNCTION"
>r = table_prev(v-&#62;subtable-&#62;table, r,
-1);</CODE
>.&#13;</P
><P
><SPAN
CLASS="emphasis"
><I
CLASS="EMPHASIS"
>FIXME</I
></SPAN
>: here is a few notes, they should be moved
in a section with table_{first,last,next,prev} and get_record_no.</P
><P
><CODE
CLASS="FUNCTION"
>table_prev</CODE
> takes 3 arguments :

<P
></P
><UL
><LI
><P
>table which is the table in which the record is,</P
></LI
><LI
><P
>r which is the record we were at,</P
></LI
><LI
><P
>sort_by which is a number explaining with which kind of sorting we want
to move (-1 means no sorting otherwise it is a field number).</P
></LI
></UL
>&#13;</P
><P
>Then we fill again the view and tell gaby about this change so bound windows
are updated (with <CODE
CLASS="FUNCTION"
>update_bound_windows</CODE
>).</P
><P
>&#13;<CODE
CLASS="FUNCTION"
>next_clicked</CODE
> is the same with <CODE
CLASS="FUNCTION"
>table_next</CODE
> instead of
<CODE
CLASS="FUNCTION"
>table_prev</CODE
>. Note that you don't need to check if you're
on the first (or latest) record, it is handled by Gaby (previous when on first
and you'll stay on it, same with next on latest).&#13;</P
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="AEN774"
>9.1. Configuring</A
></H1
><P
>In <CODE
CLASS="FUNCTION"
>init_view_plugin</CODE
> we affected something to
<CODE
CLASS="STRUCTFIELD"
>vpd-&#62;configure</CODE
>.
It is a function defined as :

<CODE
CLASS="FUNCTION"
>mstatic GtkWidget* configure(ViewPluginData *vpd);</CODE
>

It is used in the 'configure' box inside Gaby. Since you don't have anything to
configure you may simply type (or affect <VAR
CLASS="LITERAL"
>NULL</VAR
> to the
variable :

<PRE
CLASS="PROGRAMLISTING"
>mstatic GtkWidget* configure(ViewPluginData *vpd)
{
        return NULL;
}</PRE
>&#13;</P
></DIV
></DIV
></P
></DIV
></DIV
></DIV
></DIV
><H3
CLASS="FOOTNOTES"
>Notes</H3
><TABLE
BORDER="0"
CLASS="FOOTNOTES"
WIDTH="100%"
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN688"
HREF="c679.html#AEN688"
><SPAN
CLASS="footnote"
>[1]</SPAN
></A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>Note that this could be done
only when the user asks for them but since it is not implemented this way ...</P
></TD
></TR
></TABLE
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x570.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="index.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="c782.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Structures</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="p489.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Actions</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>