<?xml version="1.0" encoding='ISO-8859-1'?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" 
  "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
  <!ENTITY % cartoweb SYSTEM "../../cartoweb.ent" >
  %cartoweb;
  ]>
<!-- $Id: special.xml,v 1.15 2007-07-26 12:18:15 ochriste Exp $ -->
<sect1 id="dev.newplugin.special">
  <title><indexterm><primary>Special plugins</primary></indexterm>Special 
    Plugins</title>
  <sect2 id="dev.newplugin.special.export">
    <title><indexterm><primary>Export plugins</primary></indexterm>Export 
      Plugins</title>
    <para>Export plugins allow to export maps and data. Concepts described 
      below provide tools to help writing such plugins.</para>
    <para>In brief, export plugins follow these steps in order to generate an 
      output:</para>
    <itemizedlist>
      <listitem>
        <para>Retrieve last request that was sent to server</para>
      </listitem>
      <listitem>
        <para>Call all plugins to ask for request modification (eg. map 
          resolution changes, keymap generation enabled/disabled, etc.)</para>
      </listitem>
      <listitem>
        <para>Call server to get a new modified result</para>
      </listitem>
      <listitem>
        <para>Use the result to generate output</para>
      </listitem>
      <listitem>
        <para>Return output in a standardized form</para>
      </listitem>
    </itemizedlist>
    <sect3 id="dev.newplugin.special.export.naming">
     <title>Export Plugin Naming Convention</title>
     <para>
     <warning>
      <para>Export plugins MUST have names that begin with the string 
      "export", for instance <filename>exportPdf</filename>, 
      <filename>exportCsv</filename> or <filename>exportHtml</filename>.</para>
      <para>This rule does not apply to extended plugins since only the original plugin name is detected.</para>
     </warning>
     </para>
    </sect3>
    <sect3 id="dev.newplugin.special.export.exportplugin">
      <title>
        <classname>ExportPlugin</classname>
      </title>
      <para>Class <classname>ExportPlugin</classname> implements a special type 
        of client plugin, with some specific functionnalities for export. It 
        implements interface <classname>GuiProvider</classname> so child 
        classes must implement corresponding methods. Class methods are:</para>
      <itemizedlist>
        <listitem>
          <para><function>getLastMapRequest</function>: returns last used 
            request object. This is useful to prepare a new call to server in 
            order to obtain data specific to export. This call is done in 
            method <function>getExportResult</function></para>
        </listitem>
        <listitem>
          <para><function>getLastMapResult</function>: This can also be useful 
            in some cases to have the last returned result obect</para>
        </listitem>
        <listitem>
          <para><function>getExportResult</function>: executes call to server 
            in order to obtain a modified result suitable for export 
            generation. Calls all exportable plugins in order to modify request 
            (see <xref linkend="dev.newplugin.special.export.exportable" 
            />)</para>
        </listitem>
        <listitem>
          <para><function>getExport</function> (abstract): contains export 
            generation itself. Should prepare export configuration, call 
            <function>getExportResult</function> and generate export in an 
            <classname>ExportOutput</classname> object </para>
        </listitem>
      </itemizedlist>
    </sect3>
    <sect3 id="dev.newplugin.special.export.exportconfiguration">
      <title>
        <classname>ExportConfiguration</classname>
      </title>
      <para>Export configuration objects contain information on what is needed 
        by export plugin to generate output. For instance, for a CSV export, no 
        images are needed and it would be a waste of time to generate 
        them.</para>
      <para>Configuration is set in method <function>getExport</function>, then 
        passed to method <function>getExportResult</function> in order to get 
        modified result. Configuration is used by plugin to know how to modify 
        request to retrieve useful data.</para>
    </sect3>
    <sect3 id="dev.newplugin.special.export.exportable">
      <title><classname>Exportable</classname> Interface</title>
      <para>Exportable interface declares a method 
        <function>adjustExportMapRequest</function> which modifies a standard 
        map request to a special export request. For instance, plugin Image 
        uses <classname>ExportConfiguration</classname> object to know if maps 
        are needed by export plugin. If not, image request is modified. </para>
    </sect3>
    <sect3 id="dev.newplugin.special.export.example">
      <title>Example</title>
      <para>Plugin <literal>exportCsv</literal> is a good, simple example of 
        export plugin.</para>
        <para>Configuration is filled in method 
          <function>getConfiguration</function>. No images are required 
          to output a CSV file:</para>
          <programlisting><![CDATA[protected function getConfiguration() {
    $config = new ExportConfiguration();
    $config->setRenderMap(false);
    $config->setRenderKeymap(false);
    $config->setRenderScalebar(false);
}]]></programlisting>
      <para>Result rendering is done in method <function>getExport</function>. 
      Note that no calls to methods <function>getLastMapRequest</function> or 
      <function>adjustExportMapRequest</function> are needed, as those calls 
      are handled by method <function>getExportResult</function>:</para>
      <programlisting><![CDATA[protected function getExport() {
    $this->getExportResult($this->getConfiguration());
    
    // ...
    
    $output = new ExportOutput();
    $output->setContents($contents);
    return $output;
}]]></programlisting>
      <para>Final output (headers + content) is done in method 
      <function>output</function>. For instance:</para>
      <programlisting><![CDATA[public function output() {
    header('Content-Type: text/html');
    print $this->getExport()->getContents();
    return '';
}]]></programlisting>
    </sect3>
  </sect2>
  <sect2 id="dev.newplugin.special.filters">
    <title><indexterm><primary>Filters</primary></indexterm>Filters</title>
    <para> Filter plugins can be used to modify parameters transfered from 
      browser to &cartoweb; client. These parameters can be part of a POST 
      request (HTML forms) or a GET request (URL query string).</para>
    <para>Once a new filter plugin has been developed, it can be activated by 
      adding it to the <parameter>loadPlugins</parameter> variable in file 
      <filename>client_conf/client.ini</filename>.</para>
    <sect3 id="dev.newplugin.special.filters.interface">
      <title>Interface and Classes</title>
      <para> Interface FilterProvider declares following methods:</para>
      <itemizedlist>
        <listitem>
          <para><function>filterPostRequest(FilterRequestModifier 
            $request)</function>: modifies parameters transfered via a POST 
            request</para>
        </listitem>
        <listitem>
          <para><function>filterGetRequest(FilterRequestModifier 
            $request)</function>: modifies parameters transfered via a GET 
            request</para>
        </listitem>
      </itemizedlist>
      <para> Class <classname>FilterRequestModifier</classname> is used to get 
        old values from the request and set new ones. It implements two main 
        methods:</para>
      <itemizedlist>
        <listitem>
          <para><function>getValue($key)</function>: retrieves old value </para>
        </listitem>
        <listitem>
          <para><function>setValue($key, $value)</function>: sets new 
            value</para>
        </listitem>
      </itemizedlist>
    </sect3>
    <sect3 id="dev.newplugin.special.filters.parameters">
      <title>Available Parameters</title>
      <para>This is the list of global parameters accepted by &cartoweb; via GET</para>
          <itemizedlist>
            <listitem>
              <para><parameter>reset_session</parameter> : This will reset all 
              session parameters to default value. Useful when you want to go 
              back to the initial stats of the application
              <programlisting><![CDATA[
    http://www.yoursite.org/cartoweb3/htdocs/client.php?reset_session
              ]]></programlisting></para>
            </listitem>
            <listitem>
              <para><parameter>prevent_save_session</parameter> : This will bypass 
              the session save. Useful when you want to performe an action without 
              effect on the actual state of the application. This was added 
              specifically when using the mode=image global parameter
              <programlisting><![CDATA[
    http://www.yoursite.org/cartoweb3/htdocs/client.php?prevent_save_session
              ]]></programlisting>
              </para>
            </listitem>
            <listitem>
              <para><parameter>mode</parameter> : This will define the kind of output of &cartoweb;. By default it will be html. Another possible output is <parameter>image</parameter>. In this case, &cartoweb; will only output an image.
              <programlisting><![CDATA[
    http://www.yoursite.org/cartoweb3/htdocs/client.php?mode=image
              ]]></programlisting>
              The image mode can be used with other plugin specific parameters:
              <programlisting><![CDATA[
    http://www.yoursite.org/cartoweb3/htdocs/client.php?mode=image&recenter_x=300000&recenter_y=5150000&recenter_scale=150000
              ]]></programlisting></para>
            </listitem>
          </itemizedlist>
      <para>This is the list of parameters that can be set in a filter plugin 
        using function <function>setValue()</function> (in php file) or GET request (URL query string):</para>
      <itemizedlist>
        <listitem>
          <para>Images plugin</para>
          <itemizedlist>
            <listitem>
              <para><parameter>mapsize</parameter> - ID of the selected map 
                size (see <xref linkend="user.images.client" />)</para>
            </listitem>
            <listitem>
              <para><parameter>customMapsize</parameter> - this string parameter enables to specify a customized map size using the syntax <parameter>[width]x[height]</parameter>, <parameter>[width]</parameter> and <parameter>[height]</parameter> being positive integers (size in pixels). You may specify dimensions limitations in <filename>client_conf/images.ini</filename> (see <xref linkend="user.images.client" />)</para>
            </listitem>
            <listitem>
              <para><parameter>drawMainmap</parameter> - boolean indicating if the mainmap must be drawn or not.</para>
            </listitem>
            <listitem>
              <para><parameter>drawKeymap</parameter> - boolean indicating if the keymap must be drawn or not.</para>
            </listitem>
            <listitem>
              <para><parameter>drawScalebar</parameter> - boolean indicating if the scalebar must be drawn or not.</para>
            </listitem>
          </itemizedlist>
        </listitem>
        <listitem>
          <para>Location plugin </para>
          <itemizedlist>
            <listitem>
              <para><parameter>recenter_bbox</parameter> - new bounding box, 
                comma-separated coordinates, eg. "10.5,20,15.5,28"</para>
            </listitem>
            <listitem>
              <para><parameter>recenter_x</parameter> - re-centering: new 
                x-coordinate</para>
            </listitem>
            <listitem>
              <para><parameter>recenter_y</parameter> - re-centering: new 
                y-coordinate</para>
            </listitem>
            <listitem>
              <para><parameter>show_crosshair</parameter> - '0' or '1', 
               default '0'. If '1' display a crosshair on (recenter_x, 
               recenter_y).</para>
            </listitem>
            <listitem>
              <para><parameter>recenter_scale</parameter> - new scale</para>
            </listitem>
            <listitem>
              <para><parameter>id_recenter_layer</parameter> - re-centering on 
                objects: layer to look for IDs</para>
            </listitem>
            <listitem>
              <para><parameter>id_recenter_ids</parameter> - re-centering on 
                objects: list of IDs, comma-separated</para>
            </listitem>
            <listitem>
              <para><parameter>shortcut_id</parameter> - ID of the selected map 
                size (see <xref linkend="user.location.server" />)</para>
            </listitem>
          </itemizedlist>
        </listitem>
        <listitem>
          <para>Query plugin</para>
          <itemizedlist>
            <listitem>
              <para><parameter>query_layer</parameter> - layer to look for 
                IDs</para>
            </listitem>
            <listitem>
              <para><parameter>query_select</parameter> - IDs of objects to add 
                to selection</para>
            </listitem>
            <listitem>
              <para><parameter>query_unselect</parameter> - IDs of objects to 
                remove from selection</para>
            </listitem>
            <listitem>
              <para><parameter>query_policy</parameter> - selection policy: 
                'POLICY_XOR', 'POLICY_UNION' or 'POLICY_INTERSECTION', default 
                is 'POLICY_XOR'</para>
            </listitem>
            <listitem>
              <para><parameter>query_maskmode</parameter> - '0' or '1', default 
                is '0'. If '1', will show selection as a mask.</para>
            </listitem>
            <listitem>
              <para><parameter>query_hilight</parameter> - '0' or '1', default 
                is '1'. If '0', won't shows selection hilighted.</para>
            </listitem>
            <listitem>
              <para><parameter>query_return_attributes</parameter> - '0' or 
                '1', default is '1'. If '0', won't return attributes other than 
                IDs.</para>
            </listitem>
            <listitem>
              <para><parameter>query_return_table</parameter> - '0' or '1', 
                default is '1'. If '0', won't return any table results.</para>
            </listitem>
            <listitem>
              <para><parameter>query_clear</parameter> - '0' or '1',
                default is '0'. If '1', previous query results are purged even 
                if they were marked as persistent.</para>  
            </listitem>
          </itemizedlist>
        </listitem>
        <listitem>
          <para>Layers plugin</para>
          <itemizedlist>
            <listitem>
              <para><parameter>switch_id</parameter> - id of the switch to be used when the children switching is activated (see <xref linkend="user.layers.tree.children"/>).</para>
            </listitem>
            <listitem>
              <para><parameter>layer_select</parameter> - comma-separated list of layers or layerGroups id's that must be added into the activated layers list.</para>
            </listitem>
            <listitem>
              <para><parameter>layer_unselect</parameter> - comma-separated list of layers or layerGroups id's that must be removed from the activated layers list. In some cases, layerGroups children might have to be explicitely listed to actually be removed.</para>
            </listitem>
          </itemizedlist>
        </listitem>
      </itemizedlist>
      <warning>
        <para>Note that for Query plugin, display of extended selection must be 
        disabled in client's <filename>query.ini</filename> in order to use 
        above parameters (see <xref linkend="user.query.client" />).</para>
      </warning>
      <tip>
        <para>To make &cartoweb; outputs a map as a raw image file (no HTML generated), you may use the GET parameter <parameter>mode=image</parameter>. For instance:
        <programlisting>http://example.com/cartoweb3/client.php?mode=image&amp;mapsize=2</programlisting></para>
      </tip>
    </sect3>
    <sect3 id="dev.newplugin.special.filters.example">
      <title>Example</title>
      <para>The following class implements a filter which allows to recenter on 
        an object while hilighting it: <programlisting><![CDATA[
class ClientFilterIdrecenter extends ClientPlugin
                             implements FilterProvider {
                       
    public function filterPostRequest(FilterRequestModifier $request) {}
    
    public function filterGetRequest(FilterRequestModifier $request) {
        
        $id = $request->getValue('id');
        if (!is_null($id)) {
            $layer = 'grid_classhilight';
            $request->setValue('query_layer', $layer);
            $request->setValue('query_maskmode', '1');
            $request->setValue('query_select', $id);

            $request->setValue('id_recenter_layer', $layer);        
            $request->setValue('id_recenter_ids', $id);
        }
    }
}]]></programlisting> </para>
    </sect3>
  </sect2>
  <sect2 id="dev.newplugin.special.tables">
    <title><indexterm><primary>Tables</primary></indexterm>Tables</title>
    <para> Tables plugin is responsible for table formatting and display. 
      </para>
    <sect3 id="dev.newplugin.special.tables.structures">
      <title>Tables Structures</title>
      <para>Tables plugin declares several structures to help plugin developer 
        manage tables. These structures are:</para>
      <itemizedlist>
        <listitem>
          <para>Class <classname>Table</classname> which includes in particular 
            a list of rows (class <classname>TableRow</classname>)</para>
        </listitem>
        <listitem>
          <para>Class <classname>TableGroup</classname> which includes in 
            particular a list of tables. Table groups are used for instance to 
            separate table results coming from several plugins</para>
        </listitem>
        <listitem>
          <para>Class <classname>TableFlags</classname> which defines 
            parameters that will be useful for a plugin using tables</para>
        </listitem>
      </itemizedlist>
      <para>Typically, a plugin using table will include a 
        <classname>TableFlags</classname> in its request and a 
        <classname>TableGroup</classname> in its result. This is the case for 
        Query plugin, which is the only core plugin which uses tables.</para>
    </sect3>
    <sect3 id="dev.newplugin.special.tables.setrules">
      <title>Setting Rules</title>
      <para>Tables plugin maintains an object called the registry (one on 
        client and one on server). This object allows to add table rules, which 
        will describes how tables must be displayed.</para>
      <para>It is recommended to add rules in plugin's 
        <function>initialize()</function> method, so they are ready at the 
        earliest stage. To obtain the registry object, first you have to get 
        the Tables plugin object.</para>
      <para>On client:</para>
      <programlisting><![CDATA[
public function initialize() {

    $tablesPlugin = $this->cartoclient->getPluginManager()->tables; 
    $registry = $tablesPlugin->getTableRulesRegistry();
    
    // Add rules here
}
]]></programlisting>
      <para>On server, plugin manager is stored in 
        <classname>ServerContext</classname> object:</para>
      <programlisting><![CDATA[
    // ...
    $tablesPlugin = $this->serverContext->getPluginManager()->tables;        
    // ...
]]></programlisting>
      <para></para>
      <para>Now you are ready to add rules. Next sections describe the 
        different types of rules. Registry's method signature is explained for 
        each type.</para>
      <para>Once rules have been added in registry, they must be executed on 
        tables. See <xref linkend="dev.newplugin.special.tables.execrules" /> 
        for a description of table rules execution.</para>
      <sect4 id="dev.newplugin.special.tables.setrules.columnselector">
        <title>Column Selector</title>
        <programlisting><![CDATA[
public function addColumnSelector($groupId, $tableId, $columnIds)]]> 
          </programlisting>
        <para>Column selector rules allow to keep only a subset of columns from 
          the source table. Parameter <parameter>$columnIds</parameter> should 
          contain an array of column IDs determining which columns to 
          keep.</para>
      </sect4>
      <sect4 id="dev.newplugin.special.tables.setrules.columnunselector">
        <title>Column Unselector</title>
        <programlisting><![CDATA[
public function addColumnUnselector($groupId, $tableId, $columnIds)]]> 
          </programlisting>
        <para>Column unselector rules allow to keep only a subset of columns 
          from the source table, by removing a list of columns. Parameter 
          <parameter>$columnIds</parameter> should contain an array of column 
          IDs determining which columns to remove.</para>
      </sect4>
      <sect4 id="dev.newplugin.special.tables.setrules.groupfilter">
        <title>Group Filter</title>
        <programlisting><![CDATA[
public function addGroupFilter($groupId, $callback)]]></programlisting>
        <para>Group filter rules allow to modify group title. Parameter 
          <parameter>$callback</parameter> should contain a pointer to a 
          callback method with the following signature:</para>
        <programlisting><![CDATA[
static function myCallbackMethod('group_id', 'group_title')
    return 'group_new_title' ]]></programlisting>
      </sect4>
      <sect4 id="dev.newplugin.special.tables.setrules.tablefilter">
        <title>Table Filter</title>
        <programlisting><![CDATA[
public function addTableFilter($groupId, $tableId, $callback)]]> 
          </programlisting>
        <para>Table filter rules allow to modify table title. Parameter 
          <parameter>$callback</parameter> should contain a pointer to a 
          callback method with the following signature:</para>
        <programlisting><![CDATA[
static function myCallbackMethod('table_id', 'table_title')
    return 'table_new_title' ]]></programlisting>
      </sect4>
      <sect4 id="dev.newplugin.special.tables.setrules.columnfilter">
        <title>Column Filter</title>
        <programlisting><![CDATA[
public function addColumnFilter($groupId, $tableId,
                                $columnId, $callback)]]></programlisting>
        <para>Column filter rules allow to modify column title. Parameter 
          <parameter>$callback</parameter> should contain a pointer to a 
          callback method with the following signature:</para>
        <programlisting><![CDATA[
static function myCallbackMethod('table_id', 'column_id', 'column_title')
    return 'column_new_title']]></programlisting>
      </sect4>
      <sect4 id="dev.newplugin.special.tables.setrules.cellfilter">
        <title>Cell Filter</title>
        <programlisting><![CDATA[
public function addCellFilter($groupId, $tableId, $columnId,
                              $inputColumnIds, $callback)]]></programlisting>
        <para>Cell filter rules allow to modify content of a cell. Values of 
          columns given in parameter <parameter>$inputColumnIds</parameter> 
          will be transfered to the callback method for cell content 
          calculation. Parameter <parameter>$callback</parameter> should 
          contain a pointer to a callback method with the following 
          signature:</para>
        <programlisting><![CDATA[
static function myCallbackMethod('table_id', 'column_id',
                                 array ('column_1' => 'value_1',
                                        'column_2' => 'value_2'))
    return 'cell_value']]></programlisting>
        <para>
            <note><para>
                To return all column's data to the callback function, you can
                use <emphasis>NULL</emphasis>.
        <programlisting><![CDATA[
        $registry->addCellFilter('query', 'table_name', '*', NULL,
                   array('TableRulesClassName', 'callbackFunctionName'));        
        ]]></programlisting>
        This will apply the <emphasis>callbackFunctionName</emphasis> function to all 
        column of table <emphasis>table_name</emphasis> and the callback function 
        will receive an array containing the values of all columns.
            </para></note>    
        </para>
      </sect4>
      <sect4 id="dev.newplugin.special.tables.setrules.cellfilterbatch">
        <title>Cell Filter (Batch)</title>
        <programlisting><![CDATA[
public function addCellFilterBatch($groupId, $tableId, $columnId,
                                   $inputColumnIds, $callback)]]> 
          </programlisting>
        <para>Cell filter rules used in batch mode allow to modify content of 
          all cells of a given column. Values of columns given in parameter 
          <parameter>$inputColumnIds</parameter> will be transfered to the 
          callback method for cells content calculation. Values for all rows 
          are transfered at the same time. Parameter 
          <parameter>$callback</parameter> should contain a pointer to a 
          callback method with the following signature:</para>
        <programlisting><![CDATA[
static function myCallbackMethod('table_id', 'column_id',
                                 array (
                                 '0' => array (
                                        'column_1' => 'value_1_row_1',
                                        'column_2' => 'value_2_row_1'),
                                 '1' => array (
                                        'column_1' => 'value_1_row_2',
                                        'column_2' => 'value_2_row_2')))
    return array ('0' => 'cell_value_row_1', '1' => 'cell_value_row_2')]]> 
          </programlisting>
      </sect4>
      <sect4 id="dev.newplugin.special.tables.setrules.rowunselector">
        <title>Row Unselector</title>
        <programlisting><![CDATA[
public function addRowUnselector($groupId, $tableId,
                                 $columnId, $rowIds)]]></programlisting>
        <para>Row unselector rules allow to remove some rows from a table. 
          Parameter <parameter>rowIds</parameter> contains IDs of row that must 
          be removed.</para>
      </sect4>
      <sect4 id="dev.newplugin.special.tables.setrules.rowselector">
        <title>Row Selector</title>
        <programlisting><![CDATA[
public function addRowSelector($groupId, $tableId,
                                 $columnId, $rowIds)]]></programlisting>
        <para>Row selector rules allow to keep only some rows from a table. 
          Parameter <parameter>rowIds</parameter> contains IDs of row that must 
          be kept.</para>
      </sect4>
      <sect4 id="dev.newplugin.special.tables.setrules.columnadder">
        <title>ColumnAdder</title>
        <programlisting><![CDATA[
public function addColumnAdder($groupId, $tableId,
                               $columnPosition, $newColumnIds,
                               $inputColumnIds, $callback)]]></programlisting>
        <para>Column adder rules allow to add one or more columns to the table. 
          Parameter <parameter>$newColumnIds</parameter> should contain the 
          list of new column IDs. Values of columns given in parameter 
          <parameter>$inputColumnIds</parameter> will be transfered to the 
          callback method for cell content calculation. Parameter 
          <parameter>$callback</parameter> should contain a pointer to a 
          callback method with the following signature:</para>
        <programlisting><![CDATA[
static function myCallbackMethod('table_id',
                                 array ('column_1' => 'value_1',
                                        'column_2' => 'value_2'))
    return array ('new_column_1' => 'cell_value_1',
                  'new_column_2' => 'cell_value_2')]]></programlisting>
        <para>Parameter <parameter>$columnPosition</parameter> indicates where 
          the new columns must be inserted. It should be an instance of class 
          <classname>ColumnPosition</classname>. Positions can be absolute or 
          relative, with a positive or negative offset:</para>
        <itemizedlist>
          <listitem>
            <para><programlisting><![CDATA[
$position = new ColumnPosition(ColumnPosition::TYPE_ABSOLUTE, 1);]]> 
              </programlisting>The new columns will be added after the first 
              column</para>
          </listitem>
          <listitem>
            <para><programlisting><![CDATA[
$position = new ColumnPosition(ColumnPosition::TYPE_ABSOLUTE, -2);]]> 
              </programlisting>The new columns will be added just before the 
              last column</para>
          </listitem>
          <listitem>
            <para><programlisting><![CDATA[
$position = new ColumnPosition(ColumnPosition::TYPE_RELATIVE,
                               0, 'column_1');]]> </programlisting>The new 
              columns will be added just before column 'column_1'</para>
          </listitem>
          <listitem>
            <para><programlisting><![CDATA[
$position = new ColumnPosition(ColumnPosition::TYPE_RELATIVE,
                               1, 'column_1');]]> </programlisting>The new 
              columns will be added just after column 'column_1'</para>
          </listitem>
        </itemizedlist>
      </sect4>
      <sect4 id="dev.newplugin.special.tables.setrules.columnadderbatch">
        <title>Column Adder (Batch)</title>
        <programlisting><![CDATA[
public function addColumnAdderBatch($groupId, $tableId,
                                    $columnPosition, $newColumnIds,
                                    $inputColumnIds, $callback)]]> 
          </programlisting>
        <para>Column adder rules used in batch mode allow to add one or more 
          columns to the table, while calculating values for all newly added 
          cells. Parameter <parameter>$newColumnIds</parameter> should contain 
          the list of new column IDs. Values of columns given in parameter 
          <parameter>$inputColumnIds</parameter> will be transfered to the 
          callback method for cells content calculation. Values for all rows 
          are transfered at the same time. Parameter 
          <parameter>$callback</parameter> should contain a pointer to a 
          callback method with the following signature:</para>
        <programlisting><![CDATA[
static function myCallbackMethod('table_id',
                                 array (
                                 '0' => array (
                                        'column_1' => 'value_1_row_1',
                                        'column_2' => 'value_2_row_1'),
                                 '1' => array (
                                        'column_1' => 'value_1_row_2',
                                        'column_2' => 'value_2_row_2')))
    return array (
           '0' => array (
                  'new_column_1' => 'cell_value_1_row_1',
                  'new_column_2' => 'cell_value_2_row_1'),
           '1' => array ( 
                  'new_column_1' => 'cell_value_1_row_2',
                  'new_column_2' => 'cell_value_2_row_2')))]]></programlisting>
        <para>See <xref 
          linkend="dev.newplugin.special.tables.setrules.columnadder" /> to 
          know more about parameter 
          <parameter>$columnPosition</parameter>.</para>
      </sect4>

      <sect4 id="dev.newplugin.special.tables.setrules.columnreorder">
        <title><indexterm><primary>Column
        reorder</primary></indexterm>Column reorder</title>
        <programlisting><![CDATA[
public function addColumnReorder($groupId, $tableId, $columnIds)]]>
        </programlisting>
        <para>
        Column reorder rule allow you to reorder the columns and their
        contents. Parameter <parameter>$columnIds</parameter> should
        contain an array of column IDs given the new column's
        order. Note that all the IDs must appear in
        <parameter>$columnIds</parameter> even they don't move. 
        </para>
      </sect4>
   
    </sect3>
    <sect3 id="dev.newplugin.special.tables.precrules">
      <title>Precedence of Rules</title>
      <para>Depending on rule type, rules are set for a group, a table or a 
        column. Parameters (<parameter>$groupId</parameter>, 
        <parameter>$tableId</parameter> or <parameter>$columnId</parameter>) 
        can point to one object or to a group of object, using wildcard 
        '*':</para>
      <itemizedlist>
        <listitem>
          <para>'column_1': rule will be executed on columns called 'column_1' 
            only</para>
        </listitem>
        <listitem>
          <para>'col*': rule will be executed on columns with name starting 
            with 'col'</para>
        </listitem>
        <listitem>
          <para>'*': rule will be executed on any columns</para>
        </listitem>
      </itemizedlist>
      <para>For instance, following rule may be executed on groups with name 
        starting with 'myGr', tables called 'myTable' and all 
        columns:<programlisting><![CDATA[
$registry->addColumnFilter('myGr*', 'myTable', '*',
                                     array($this, 'myCallbackMethod));]]> 
        </programlisting></para>
      <para>Only one rule of each type may be executed on one item. If two or 
        more rules apply, most specific rule will be choosen. In the following 
        rule definition, only the third rule will be executed on a table 
        'myTable' in a group 'myGroup': <programlisting><![CDATA[ 
$registry->addColumnSelector('*', '*', array('column_1', 'column_2'));
$registry->addColumnSelector('myGr*', '*', array('column_1'));
$registry->addColumnSelector('myGr*', 'myTable', array('column_2'));
$registry->addColumnSelector('myGroup', 'toto', array('column_3'));]]> 
        </programlisting> </para>
    </sect3>
    <sect3 id="dev.newplugin.special.tables.execrules">
      <title>Executing Rules</title>
      <sect4 id="dev.newplugin.special.tables.execrules.client">
        <title>On Client</title>
        <para>Each time a table group is created, it must be stored in Tables 
          plugin in order to display it:</para>
        <programlisting><![CDATA[
$tablesPlugin = $this->cartoclient->getPluginManager()->tables;
$tablesPlugin->addTableGroups($newTableGroup);]]></programlisting>
        <para>Tables rules are executed automatically at the same time.</para>
      </sect4>
      <sect4 id="dev.newplugin.special.tables.execrules.server">
        <title>On Server</title>
        <para>Rules execution must be done explicitly on server. A call to 
          Tables plugin <function>applyRules</function> method is needed for 
          each new table group before returning it to client:</para>
        <programlisting><![CDATA[
$tablesPlugin = $this->serverContext->getPluginManager()->tables;
readyForClientTableGroups = $tablesPlugin->applyRules($newTableGroup);]]> 
          </programlisting>
      </sect4>
    </sect3>
  </sect2>
</sect1>
