################################################################################
# TSL-LIBRARY: EMOS_FRM_TBL_Lib
################################################################################
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# For further information please contact:
#
# Dean Rajovic
# mailto:drajovic@gmx.de
# http://sourceforge.net/projects/emos-framework
#
################################################################################
# $Revision: 1.8 $
# $Author: drajovic $
# $Date: 2005/01/28 11:18:43 $
# $Source: C:/Archive/FRAMEWORK/EMOS_GPL/FRM/emos_frm_tbl_lib/script,v $
# $NoKeywords: $
################################################################################
#/***
#* This libary provides a family of functions for support of table GUI objects.
#* GUI objects in table format are known for being difficult to handle for
#* many reasons. First of all, although a single object a tables can
#* potentialy carry huge amounts of data. Depending on the testing objectives
#* we sometimes need to handle only a handfull of cells and in other cases big
#* portions of it if not the whole table. Programatic interfaces to tables are
#* usually handle individual table cells and the navigation through table.
#* More complicated actions on larger parts of table data are left to test
#* programmers to be designed from the basic table operations.<br>
#* Secondly, tables are often very dynamic objects (i.e. their content and their
#* strucure sometimes changes within a single test session). A robust test design
#* should provide for easy location of data (e.g. dynamcally determining the
#* appropriate row/column) which is not a trivial task.<br>
#* Finally, individual table cells can in fact contain various sorts of other
#* GUI objects such as edit fields, drop-down lists, combo boxes, radio buttons,
#* check buttons and other. Sometimes it seems as if vendors of GUI toolkits
#* simply had to invent something that would distinguish their tables from all
#* the other ones.
#* <p>
#* WinRunner's tbl interface does a fairly good job in making these various
#* tables appear similar. However, there are plenty of situations where this is
#* not the case. Here only individual solutions can help. Our table interface
#* builds upon the strengths of WinRunner tbl-interface and is therefore able to
#* handle many different tables. Still, due to mentioned difficulties, the
#* interface is limited in some aspects and will need to be tuned for certain
#* environments. Our code should work well with HTML tables and with tables
#* with well-working tbl-interface (tbl_set_cell_data/tbl_get_cell_data).
#* We hope also, that our code provides enough design ideas which will help you
#* handle exotic cells such as edit fields, combo-boxes, etc.
#* <p>
#* Our table support has been specially designed for use in EMOS Framework tables.
#* Pay special attention to functions FRM_TBL_set_data() and FRM_TBL_set_data_block().
#* The former implements an interface for handing individual table cells.
#* The later implements an interface for handing bigger portions of tables.
#*
#* @author drajovic
#*/
#/**
#* Performs operations on single table cells for the whole test block (i.e.
#* loops through all cells of a particular test block until an empty cell
#* or the last cell is reached.
#*
#* @param table (in) table index
#* @param test (in) test name
#* @param obj (in) logical name or phisical description of the table object
#* @param desc (in) [optional] physical description of an edit object that is
#* located in the particular table cell (attempt only if such object really
#* appears in the cell; we had to fight one tweeked VB table once with this;
#* hopefulla you'll never need it; see FRM_TBL_cell_aktion() for more)
#* @param list (in) [optional] physical description of a list object that is
#* located in the particular table cell (attempt only if such object really
#* appears in the cell, see code of FRM_TBL_cell_aktion function)
#* @return E_OK if successful, else error
#*/
public function FRM_TBL_set_data ( in table, in test, in obj, in desc, in list )
{
auto val, mode, rc;
auto rc2 = E_OK;
# loop through test block until an empty cell or last cell is reached
while( ( rc = FRM_get_next( table, test, val )) == E_OK )
{
wrlog_prim_start();
FRM_log_frm_info( table, test, val );
mode = FRM_get_mode( table );
switch( mode )
{
case FRM_SET_MODE:
case FRM_CHK_MODE:
rc2+=FRM_TBL_cell_action( obj, val, mode, desc, list );
break;
case FRM_ATR_MODE:
case FRM_GEN_MODE:
# to be implemented
break;
}
wrlog_prim_stop( rc2 );
}
if ( rc == E_FRM_SKIP || rc == E_OUT_OF_RANGE ) # empty or EOF
rc = E_OK;
# if one or the other rc variable <> 0, return error
if ( rc2 != E_OK )
return FRM_rc2( rc2, "FRM_TBL_cell_action" );
return FRM_rc2( rc, "FRM_TBL_set_data" );
}
#/**
#* Performs an action(s) on a block of table cells.
#*
#* @param tid1 (in) id of the table where the instructins come from
#* @param test (in) name of the test to run (as named in column "Name")
#* @param obj (in) table object where actions are to be performed
#*/
public function FRM_TBL_set_data_block ( in tid1, in test, in obj )
{
auto rc, row, name, val, table2, tid2, dir, file, mode;
rc+=FRM_get_current_row( tid1, row );
while( rc == E_OK || rc == E_FRM_SKIP )
{
row++;
rc = FRM_get( tid1, FRM_COL_NAME, name, row );
if ( rc == E_FRM_SKIP )
{
rc = E_OK;
break;
}
if ( rc != E_OK )
{
FRM_log_frm_info( tid1, test, obj );
return FRM_rc2( rc, "FRM_TBL_set_data_block-> cannot retrieve cell: Name=["&name&"], row=["&row&"], rc=["&rc&"]" );
}
if ( match(name,"<<[Ee][Nn][Dd][Ee]*>>") )
break;
rc = FRM_get( tid1, test, val, row );
if ( rc == E_FRM_SKIP ) continue;
if ( rc != E_OK ) return rc;
split_path( FRM_get_name( tid1 ), dir, file, "\\" );
table2 = join_path( dir, name, "\\" );
if ( !FRM_is_open( table2 ) )
{
# open table2 and load all columns
rc = FRM_open( table2, "<<ALL>>", tid2 );
if ( rc != E_OK )
{
FRM_log_frm_info( table2, tid2, obj );
return FRM_rc2( rc, "FRM_TBL_set_data_block-> cannot open FRM table: Table=["&table2&"], RC=["&rc&"]" );
}
# table2 inherits the mode from table1
rc = FRM_set_mode( tid2, FRM_get_mode( tid1 ) );
}
mode = FRM_get_mode( tid2 );
switch( mode )
{
case FRM_SET_MODE:
case FRM_CHK_MODE:
rc = FRM_TBL_process_data_block( tid2, val, obj );
break;
case FRM_ATR_MODE:
case FRM_GEN_MODE:
#not implemented
break;
}
}
return rc;
}
#/**
#* Process 2-dimensional table block
#*/
static function FRM_TBL_process_data_block ( in tid, in block, in obj )
{
auto rc;
auto x, y, data[];
auto i, j;
auto mode, val;
auto sep, tmp[], cols[], count;
auto action;
auto msg;
rc = FRM_get_block( tid, block, x, y, data );
if ( rc != E_OK )
return rc;
mode = FRM_get_mode( tid );
# parse column headers (they define separator, action, column name and, optionally, object description)
for( i=1; i<x; i++ )
{
sep = substr( data[0,i], 1, 1 );
count = split( data[0,i], tmp, sep );
if ( count < 3 )
{
msg = sprintf( "%s: invalid format expected <sep>action<sep>column[<sep>object[<sep>exact]]", data[0,i] );
FRM_log_frm_info( tid, block, msg );
FRM_log_obj_info( obj );
return E_ILLEGAL_PARAMETER;
}
cols[i,"sep"] = sep;
cols[i,"act"] = tmp[2];
cols[i,"col"] = tmp[3];
# 'obj' & 'exact' are optional; will be set to "" automatically
cols[i,"obj"] = tmp[4];
cols[i,"exact"] = tmp[5];
}
# for all rows
for( i=1; i<y; i++ )
{
# for all columns
for( j=1; j<x; j++ )
{
val = data[i,j];
if ( FRM_parse_val( tid, val ) == E_FRM_SKIP )
{
continue;
}
sep = cols[j,"sep"];
action = sprintf( "%s%s%s%s%s%s%s%s%s%s%s%s",
sep, cols[j,"act"],
sep, data[i,0],
sep, cols[j,"col"],
sep, val,
sep, cols[j,"obj"],
sep, cols[j,"exact"] );
rc+=FRM_TBL_cell_action( obj, action, mode );
}
}
return rc;
}
######################################################################
# low-level interface
######################################################################
#/**
#* Holds the adjustment amount for the tbl_get_rows_count() function.
#* @see FRM_TBL_set_rows_count_adjustment()
#*/
static aut_tbl_rows_count_adjustment = 0;
#/**
#* Function tbl_get_rows_count() sometimes returns count that is less than the
#* physical number of rows. If present, the headings row is typically not counted.
#* So the returned count is one less than the physical count. For our search
#* functions (e.g. FRM_TBL_find_cell()) we need to access the headings row to
#* search them. Increase the count_adjustment if you notice that our functions
#* do not seem to find the value in the last row.
#*
#* @param amount (in) amount to adjust
#*/
public function FRM_TBL_set_rows_count_adjustment ( in amount )
{
aut_tbl_rows_count_adjustment = amount;
}
#/**
#* Function tbl_get_rows_count() sometimes returns count that is less than the
#* physical number of rows. If present, the headings row is typically not counted.
#* So the returned count is one less than the physical count. For our search
#* functions (e.g. FRM_TBL_find_cell()) we need to access the headings row to
#* search them. Increase the count_adjustment if you notice that our functions
#* do not seem to find the value in the last row.
#*
#* @return the row adjustment amount
#*/
public function FRM_TBL_get_rows_count_adjustment ( )
{
return aut_tbl_rows_count_adjustment;
}
#/**
#* Holds the adjustment amount for the tbl_get_cols_count() function.
#* @see FRM_TBL_set_cols_count_adjustment()
#*/
static aut_tbl_cols_count_adjustment = 0;
#/**
#* Function tbl_get_cols_count() sometimes returns count that is less than the
#* physical number of columns. If present, the headings column is typically not
#* counted. So the returned count is one less than the physical count. For our
#* search functions (e.g. FRM_TBL_find_cell()) we need to access the headings
#* column to search for them. Increase the count_adjustment if you notice that
#* our functions do not seem to find the value in the last column.
#*
#* @param amount (in) amount to adjust
#*/
public function FRM_TBL_set_cols_count_adjustment ( in amount )
{
aut_tbl_cols_count_adjustment = amount;
}
#/**
#* Function tbl_get_cols_count() sometimes returns count that is less than the
#* physical number of columns. If present, the headings column is typically not
#* counted. So the returned count is one less than the physical count. For our
#* search functions (e.g. FRM_TBL_find_cell()) we need to access the headings
#* column to search for them. Increase the count_adjustment if you notice that
#* our functions do not seem to find the value in the last column.
#*
#* @return the row adjustment amount
#*/
public function FRM_TBL_get_cols_count_adjustment ( )
{
return aut_tbl_cols_count_adjustment;
}
#/**
#* Performs the action on a table cell as specified by the command <code>cmd</code>.
#* There are four types of actions you can perform on a table cell:
#* <ul>
#* <li>S = <b>s</b>elect the cell (i.e. tbl_set_selected_cell/tbl_activate_cell)</li>
#* <li>E = <b>e</b>nter the value in a cell box of type edit (i.e. edit_set)</li>
#* <li>P = <b>p</b>ick the value from a list (i.e. list_select_item)</li>
#* <li>T = <b>t</b>ype into the cell (i.e. type)</li>
#* <li>D = enter <b>d</b>ata using tbl functions such as tbl_set_cell_data() or
#* tbl_get_cell_data()</li>
#* </ul>
#*<p>
#* All actions can be specified by a generic syntax:
#* <p>
#* <pre>~action~[row]~[col][~val[~obj[~exact]]]</pre>
#* <p>
#* where<br>
#* <ul>
#* <li>~ = any character that occurs only at specified positions (separator)</li>
#* <li>action = one of the following: S|E|P|T|D, action can be prefixed with . or :
#* (e.g. .S) where . means selection (tbl_set_selected_cell) and : means
#* activation (tbl_activate_cell, i.e. double-click) [default: selection]</li>
#* <li>row = row specification either as
#* <ul>
#* <li>index (e.g. <code>#1</code>)</li>
#* <li>search expression in form <code>col1=val1[;coln=valn]...</code>
#* where col1 ist the name of the column containing val1, etc. the
#* separator ; (semicolon) is interpreted as logical AND</li>
#* <li><code><LAST></code> in which case the last valid row spec is
#* reused (no search is performed for preformance reasons)</li>
#* <li>name (e.g. <code>Par1</code>) it is assumed that col #0 contains row
#* names [obsolete; replaced by <code>#0=val</code>] </li>
#* <li>in case of Selection row can be left empty (assuming col and val are
#* filled in) where val is searched for in col #0 [obsolete, replaced
#* by construct <code>#0=val</code>]</li>
#* </ul>
#* <li>col = column specification either as
#* <ul>
#* <li>index (e.g. <code>#1</code>)</li>
#* <li>name (e.g. <code>Col1</code>)</li>
#* <li>search expression in form <code>row1=val1[;rown=valn]...</code>
#* where row1 ist the name of the row containing val1, etc. the
#* separator ; (semicolon) is interpreted as logical AND</li>
#* <li><code><LAST></code> in which case the last valid column spec is
#* reused (no search is performed for preformance reasons)</li>
#* <li>in case of Selection col can be left empty (assuming row and val are
#* filled in) where val is searched for in row #0 [obsolete, replaced
#* by construct <code>#0=val</code>]</li>
#* </ul>
#* <li>val = value which can be interpreted two-fold<br>
#* in case of Selection val can specify the content of the cell which is to be selected<br>
#* in other cases val represents the value for the E|P|T|D operations</li>
#* <li>obj = a phisical description of the object to be actioned upon</li>
#* <li>exact = indicats whether exact or tollerant matching [default] is to be performed</li>
#* </ul>
#* <p>
#* A few examples:
#* <ul>
#* <li>~S~#1~#2<br>
#* selects cell indexed by row=#1, col=#2<br><br></li>
#* <li>~.S~AnzahlH~Wert<br>
#* selects cell in a row named "AnzahlH" and a column named "Wert"<br><br></li>
#* <li>~:S~~Wert~xxx<br>
#* activates cell in a column "Wert" that contains "xxx"<br><br></li>
#* <li>~S~#1~~xxx<br>
#* activates cell in a row #1 that contains "xxx"<br><br></li>
#* <li>~E~#1~Wert~xxx<br>
#* sets (edit_set) cell in row #1 and column named "Wert" to "xxx"<br><br></li>
#* <li>~E~#1~#2~xxx~{class:edit,index:12}<br>
#* sets (edit_set) object with the given description that appears in cell #1:#2 to "xxx"<br><br></li>
#* <li>~S~aaa~bbb~~~1<br>
#* selects cell named exactly "aaa":"bbb"<br><br></li>
#* <li>~.T~#1~#2~abc<br>
#* types "abc" in cell #1:#2 (after selecting a cell with a single click)<br><br></li>
#* </ul>
#* @param tbl (in) table name
#* @param cmd (in) command to be performed
#* @param frm_mode (in) [optional] FRM mode (FRM_SET_MODE|FRM_CHK_MODE|FRM_ATR_MODE|FRM_GEN_MODE)
#* @param desc (in) [optional] default physical description of the object to be acted upon
#* this description is used unless overridden by the cmd,
#* if you don't provide this argument, "{class:edit}" will be used
#* @param list (in) [optional] a description or a logical name of the combo box
#* containing the obj.
#*/
public function FRM_TBL_cell_action( in tbl, in cmd, in frm_mode, in desc, in list )
{
extern RLENGTH;
auto sep; # separator
auto typ; # query type S=selection, E=edit, P=pick; T=type
auto row; # row# or row name
auto col; # col# or column name
auto val; # value to be set/selected
auto obj; # object where action is to be performed
auto exact; # indicator for exact or tollerant match [default: tollerant]
auto simple_select; # cell selection mechanism [default: double-click]
auto arr[], count, i;
auto r, c;
auto w, h;
auto msg, dummy, rc;
if ( frm_mode == "" )
frm_mode = FRM_SET_MODE;
sep = substr( cmd, 1, 1 );
count = split( cmd, arr, sep );
if ( count < 4 )
return E_ILLEGAL_PARAMETER;
typ = toupper( arr[2] );
row = arr[3];
col = arr[4];
# don't worry for these three (they will be created if not specified)
val = arr[5];
obj = arr[6];
exact = arr[7];
switch ( typ )
{
case "S":
case "D":
case "DCHK":
case "E":
case "B":
case "BCHK":
case "P":
case "T":
case ".S":
case ".D":
case ".DCHK":
case ".E":
case ".B":
case ".BCHK":
case ".P":
case ".T":
simple_select = TRUE; # i.e. use tbl_set_selected_cell()
break;
case ":S":
case ":D":
case ":DCHK":
case ":E":
case ":B":
case ":BCHK":
case ":P":
case ":T":
simple_select = FALSE; # i.e. use tbl_activate_cell()
break;
default:
rc = E_ILLEGAL_PARAMETER;
msg = sprintf( "%s: invalid type, valid options=S|E|P|T|D", typ );
return FRM_rc2( msg, rc );
}
rc = FRM_TBL_determine_row( tbl, row, col, val, r, exact );
if ( rc != E_OK )
return FRM_rc2( rc, sprintf( "%s: could not determine row index", row ) );
rc = FRM_TBL_determine_col( tbl, row, col, val, c, exact );
if ( rc != E_OK )
return FRM_rc2( rc, sprintf( "%s: could not determine column index", col ) );
# watch the trick !!! object is created dynamically!
# there are two ways to identify the object:
# 1. pass the description via parameter
# (this way you define the default object)
# 2. pass the desciption via command
# (i.e. overide the default by anything you want from a data table)
# if you don't specify anything, we'll try with an edit object
if ( arr[6] == "" )
obj = desc;
if ( match( obj, " *web:" ) == 1 )
obj = FRM_TBL_web_get_child_item( tbl, r, c, obj );
if ( obj == "" )
obj = "{class:edit}";
switch ( typ )
{
case "S": # Selection
case ":S":
case ".S":
switch( frm_mode )
{
case FRM_SET_MODE:
case FRM_CHK_MODE:
case FRM_ATR_MODE:
case FRM_GEN_MODE:
rc+=FRM_TBL_select( tbl, r, c, simple_select );
break;
}
break;
case "D": # Data = tbl functions
case ":D":
case ".D":
switch( frm_mode )
{
case FRM_SET_MODE:
rc+=FRM_TBL_SET_data( tbl, r, c, val, simple_select );
break;
case FRM_CHK_MODE:
rc+=FRM_TBL_CHK_data( tbl, r, c, val, simple_select, exact );
break;
case FRM_ATR_MODE:
case FRM_GEN_MODE:
break;
}
break;
case "DCHK": # Data = tbl functions (force check)
case ":DCHK":
case ".DCHK":
switch( frm_mode )
{
case FRM_SET_MODE:
case FRM_CHK_MODE:
rc+=FRM_TBL_CHK_data( tbl, r, c, val, simple_select, exact );
break;
case FRM_ATR_MODE:
case FRM_GEN_MODE:
break;
}
break;
case "E": # Edit = edit field
case ":E":
case ".E":
switch( frm_mode )
{
case FRM_SET_MODE:
rc+=FRM_TBL_SET_edit( tbl, r, c, obj, val, simple_select, exact );
break;
case FRM_CHK_MODE:
rc+=FRM_TBL_CHK_edit( tbl, r, c, obj, val, simple_select, exact );
break;
case FRM_ATR_MODE:
case FRM_GEN_MODE:
break;
}
break;
case "B": # Button = radio button or check box
case ":B":
case ".B":
switch( frm_mode )
{
case FRM_SET_MODE:
rc+=FRM_TBL_SET_button( tbl, r, c, obj, val, simple_select );
break;
case FRM_CHK_MODE:
rc+=FRM_TBL_CHK_button( tbl, r, c, obj, val, simple_select );
break;
case FRM_ATR_MODE:
case FRM_GEN_MODE:
break;
}
break;
case "BCHK": # Button = radio button or check box (force check)
case ":BCHK":
case ".BCHK":
switch( frm_mode )
{
case FRM_SET_MODE:
case FRM_CHK_MODE:
rc+=FRM_TBL_CHK_button( tbl, r, c, obj, val, simple_select );
break;
case FRM_ATR_MODE:
case FRM_GEN_MODE:
break;
}
break;
case "P": # Pick = drop-down list
case ":P":
case ".P":
switch( frm_mode )
{
case FRM_SET_MODE:
rc+=FRM_TBL_SET_pick( tbl, r, c, obj, list, val, simple_select );
break;
case FRM_CHK_MODE:
rc+=FRM_TBL_CHK_pick( tbl, r, c, obj, list, val, simple_select, exact );
break;
case FRM_ATR_MODE:
case FRM_GEN_MODE:
break;
}
break;
case "T": # Type = anything
case ":T":
case ".T":
switch( frm_mode )
{
case FRM_SET_MODE:
rc+=FRM_TBL_type( tbl, r, c, val, simple_select );
break;
case FRM_CHK_MODE:
case FRM_ATR_MODE:
case FRM_GEN_MODE:
break;
}
break;
}
return rc;
}
public function FRM_TBL_CHK_cell_action( in tbl, in cmd, in desc, in list )
{
extern RLENGTH;
auto sep; # separator
auto typ; # query type S=selection, E=edit, P=pick; T=type
auto row; # row# or row name
auto col; # col# or column name
auto val; # value to be set/selected
auto obj; # object where action is to be performed
auto exact; # indicator for exact or tollerant match [default: tollerant]
auto simple_select; # cell selection mechanism [default: double-click]
auto arr[], count, i;
auto r, c;
auto w, h;
auto msg, dummy, rc;
auto val2;
sep = substr( cmd, 1, 1 );
count = split( cmd, arr, sep );
if ( count < 4 )
return E_ILLEGAL_PARAMETER;
typ = toupper( arr[2] );
row = arr[3];
col = arr[4];
# don't worry for these three (they will be created if not specified)
val = arr[5];
obj = arr[6];
exact = arr[7];
rc = FRM_TBL_determine_row( tbl, row, col, val, r, exact );
if ( rc != E_OK )
return rc;
rc = FRM_TBL_determine_col( tbl, row, col, val, c, exact );
if ( rc != E_OK )
return rc;
if ( arr[6] == "" )
{
obj = desc;
}
if ( obj == "" )
{
obj = "{class:edit}";
}
rc+=tbl_set_selected_cell( tbl, r, c );
rc+=tbl_get_cell_data ( tbl, r, c, val2 );
val2=strip_both ( val2, " " );
if ( match( val2, val ) && length(val2) == RLENGTH )
{
FRM_log_obj_info( obj );
tl_step( "FRM_TBL_CHK_cell_action", E_OK, "expected: \""&val&"\" actual: \""&val2&"\"" );
rc = E_OK;
}
else
{
FRM_log_obj_info( obj );
rc = FRM_rc2( E_DIFF, "expected: \""&val&"\" actual: \""&val2&"\"" );
}
return rc;
}
public function FRM_TBL_select ( in tbl, in row, in col, in simple_select )
{
auto rc;
if ( simple_select )
rc+=tbl_set_selected_cell( tbl, "#"&row, "#"&col );
# if the above does not work, try this
#rc = tbl_click_cell( tbl, row, col );
else
rc = tbl_activate_cell( tbl, row, col );
# some apps resize the grid when a cell gets selected
# with this wait we hope to have stable grid before continuing
#wait( 0, 500 );
return FRM_rc2( rc, sprintf("row=%s, col=%s", row, col) );
}
public function FRM_TBL_GET_data ( in tbl, in row, in col, out val, in simple_select )
{
auto rc;
# rc =FRM_TBL_select ( tbl, row, col, simple_select );
rc =tbl_get_cell_data( tbl, row, col, val);
return FRM_rc2( rc, sprintf("row=%s, col=%s, val=%s", row, col, val) );
}
public function FRM_TBL_SET_data ( in tbl, in row, in col, in val, in simple_select )
{
auto rc;
# rc =FRM_TBL_select ( tbl, row, col, simple_select );
rc =FRM_rc2( tbl_set_cell_data( tbl, row, col, val), sprintf("row=%s, col=%s, val=%s", row, col, val) );
# try the following line if you need to provoke the focus lost event
#type( "<kReturn>" );
return rc;
}
public function FRM_TBL_CHK_data ( in tbl, in row, in col, in val, in simple_select, in operation )
{
extern RLENGTH;
auto data;
auto rc;
# rc =FRM_TBL_select ( tbl, row, col, simple_select );
rc+=FRM_rc2( tbl_get_cell_data( tbl, row, col, data), sprintf("row=%s, col=%s, val=%s", row, col, data) );
if ( rc == E_OK )
{
rc = FRM_TBL_generic_check( data, val, operation );
}
return rc;
}
static function FRM_TBL_generic_check ( in actual, in expected, in operation )
{
extern RLENGTH;
auto msg, rc;
msg = sprintf( "expected=\"%s\", actual=\"%s\", operation=%s", expected, actual, operation );
switch ( toupper(operation) )
{
case "": # wenn nichts spezifiziert wird MATCH als default genommen
case "MATCH":
rc = match( actual, expected );
break;
case "EXACT":
rc = match( actual, expected ) && RLENGTH == length( actual );
break;
case "==":
case "EQ":
rc = ( expected == actual );
break;
case "!=":
case "NE":
rc = ( expected != actual );
break;
case "<":
case "LT":
rc = ( expected > actual );
break;
case "<=":
case "LE":
rc = ( expected >= actual );
break;
case ">":
case "GT":
rc = ( expected < actual );
break;
case ">=":
case "GE":
rc = ( expected <= actual );
break;
default:
return FRM_rc2( E_ILLEGAL_PARAMETER, operation & ": illegal operation" );
}
return FRM_rc2( (rc ? E_OK : E_MISMATCH), msg );
}
# edit
public function FRM_TBL_SET_edit ( in tbl, in row, in col, in obj, in val, in simple_select )
{
auto rc;
FRM_log_obj_info( obj );
rc =FRM_TBL_select ( tbl, row, col, simple_select );
rc+=edit_set( obj, val );
#type( "<kReturn>" );
return FRM_rc2( rc, val );
}
public function FRM_TBL_CHK_edit ( in tbl, in row, in col, in obj, in val, in simple_select, in exact )
{
auto rc;
FRM_log_obj_info( obj );
rc =FRM_TBL_select ( tbl, row, col, simple_select );
rc+=edit_check_text( obj, val, exact );
return FRM_rc2( rc, val );
}
# button (radio button or check box)
public function FRM_TBL_SET_button ( in tbl, in row, in col, in obj, in val, in simple_select )
{
auto rc;
FRM_log_obj_info( obj );
#rc =FRM_TBL_select ( tbl, row, col, simple_select );
rc = button_set( obj, val );
return FRM_rc2( rc, val );
}
public function FRM_TBL_CHK_button ( in tbl, in row, in col, in obj, in val, in simple_select, in exact )
{
auto rc;
FRM_log_obj_info( obj );
#rc =FRM_TBL_select ( tbl, row, col, simple_select );
rc= button_check_state( obj, val );
return FRM_rc2( rc, val );
}
# pick
public function FRM_TBL_SET_pick ( in tbl, in row, in col, in obj, in list, in val, in simple_select )
{
auto rc;
FRM_log_obj_info( list );
rc =FRM_TBL_select ( tbl, row, col, simple_select );
rc+=FRM_TBL_list_select_item( obj, list, val );
return FRM_rc2( rc, val );
}
public function FRM_TBL_CHK_pick ( in tbl, in row, in col, in obj, in list, in val, in simple_select, in exact )
{
auto rc;
FRM_log_obj_info( list );
rc = FRM_TBL_select ( tbl, row, col, simple_select );
# to be implemented
return FRM_rc2( rc, val );
}
# type
public function FRM_TBL_type ( in tbl, in row, in col, in val, in simple_select )
{
auto rc;
rc = FRM_TBL_select ( tbl, row, col, simple_select );
type( val );
return FRM_rc2( rc, val );
}
################################################################################
#/**
#* Conains the value of the last selected row
#* (set/reset by the function FRM_TBL_determine_row())
#*/
static LAST_ROW;
#/**
#* Returns the name/index of the row depending on the specified row/col.
#* If <row> is given (i.e. != ""), the unchanged value is returned.
#* If <row> is not given (i.e. == ""), the row containing the given
#* <val> is searched for in the column specified by <col>.
#* If both <row> and <col> are not given, an error is returned.
#* @param tbl (in) table object
#* @param row (in) row to select (if row does not equal "", no search is
#* performed; if row equals "<LAST>", last valid row determined by this function
#* is returned (no search performed))
#* @param col (in) column where <val> is searched for
#* @param val (in) value to search for in the given column
#* @param out_row (out) the name of the determined row
#* @param exact (in) [optinal] true indicates that an exact match is to be performed
#* @return
#* E_OK: value was found (i.e. out_row contains the name of the row)
#* else: error
#*/
public function FRM_TBL_determine_row ( in tbl, in row, in col, in val, out out_row, in exact )
{
auto c, dummy, rc;
extern RLENGTH;
# ... by searching for the <val> in <col>
if ( row == "" )
{
if ( col == "" )
{
return E_ILLEGAL_PARAMETER; # at least one dimension must be specified
}
# rc = FRM_TBL_find_cell( tbl, val, out_row, dummy, "", col, exact );
rc = FRM_TBL_find_row( tbl, val, out_row );
if ( rc != E_OK )
{
LAST_ROW = "";
return rc;
}
LAST_ROW = out_row;
return E_OK;
}
# ... by index (nothing to search for)
if ( match( row, "#[0-9][0-9]*" ) && RLENGTH == length( row ) )
{
out_row = row;
LAST_ROW = row;
return E_OK;
}
# ... by "<LAST>" (last valid row)
if ( match( row, "<[Ll][Aa][Ss][Tt]>" ) && RLENGTH == length( row ) )
{
debug_msg( "using last row: \"" & LAST_ROW & "\"" );
out_row = LAST_ROW;
return E_OK;
}
# ... by row name (search in column 0)
# rc = FRM_TBL_find_cell( tbl, row, out_row, dummy, "", "#0", exact );
rc = FRM_TBL_find_row( tbl, row, out_row );
if ( rc != E_OK )
{
LAST_ROW = "";
return rc;
}
LAST_ROW = out_row;
return E_OK;
}
#/**
#* Conains the value of the last selected col
#* (set/reset by the function FRM_TBL_determine_col())
#*/
static LAST_COL;
#/**
#* Returns the name/index of the column depending on the specified row/col.
#* If <col> is given (i.e. != ""), the unchanged value is returned.
#* If <col> is not given (i.e. == ""), the column containing the given
#* <val> is searched for in the row specified by <row>.
#* If both <row> and <col> are not given, an error is returned.
#* @param tbl (in) table object
#* @param row (in) row to select (if row does not match "#[0-9][0-9]*", then
#* column #0 is searched for the value <row>
#* @param col (in) column to select (if col does not equal "", no search is
#* performed; if row equals "<LAST>", last valid row determined by this function
#* is returned (no search performed))
#* @param val (in) value to search for in the determined row
#* @param out_col (out) the name of the determined column
#* @param exact (in) [optinal] true indicates that an exact match is to be performed
#* @return
#* E_OK: value was found (i.e. out_col contains the name of the column)
#* else: error
#*/
public function FRM_TBL_determine_col ( in tbl, in row, in col, in val, out out_col, in exact )
{
auto r, dummy, rc;
extern RLENGTH;
# ... by searching for the <val> in <row>
if ( col == "" )
{
if ( row == "" )
{
return E_ILLEGAL_PARAMETER; # at least one dimension must be specified
}
if ( match( row, "#[0-9][0-9]*" ) && RLENGTH == length( row ) )
{
r = row;
}
else
{ # search the <row> by its name in col 0
rc = FRM_TBL_find_cell( tbl, row, r, dummy, "", "#0", exact );
if ( rc != E_OK )
{
LAST_COL = "";
return rc;
}
}
rc = FRM_TBL_find_cell( tbl, val, dummy, out_col, r, "", exact );
if ( rc != E_OK )
{
LAST_COL = "";
return rc;
}
LAST_COL = out_col;
return E_OK;
}
# ... by "<LAST>" (last valid col)
if ( match( col, "<[Ll][Aa][Ss][Tt]>" ) && RLENGTH == length( col ) )
{
debug_msg( "using last col: \"" & LAST_COL & "\"" );
out_col = LAST_COL;
return E_OK;
}
# ... by column index or name (nothing to search for)
out_col = col;
LAST_COL = col;
return E_OK;
}
#/**
#* Searches for a row that contains given data in specified coumns. Note
#* that an exact mtch is always performed.
#* If such row is found (first from top!) the row index is returned otherwise
#* an error is indicated. Cells can be specified using the following syntax:
#* <p>
#* <pre>col=val[;col=val]...</pre>
#* <p>
#* where <code>col</code> is either
#* <ul>
#* <li><b>name</b> such as "Column1" (without quotes!)</li>
#* <li><b>index</b> such as #3</li>
#* </ul>
#* @param tbl(in) table to search
#* @param row_spec (in) formated cell content specification (see above)
#* @param out_row (out) row index (only if retrn == E_OK)
#* @param idx (in) [optional] internal index needed for recursion
#* @return
#* E_OK: row found
#* E_NOT_FOUND: row not found
#* else: other error
#*/
public function FRM_TBL_find_row( in tbl, in row_spec, out out_row, in idx, in row_offset )
{
auto colArr[], colCount;
auto col2Arr[], col2Count;
auto rc, dummy;
colCount = split( row_spec, colArr, ";" );
if ( colCount < 1 )
return E_NOT_FOUND; # no row spec
# initialise offsets (needed for recursion)
if ( idx == "" )
idx = 1;
if ( row_offset == "" )
row_offset = 1;
# everything found! (recursion completed)
if ( idx > colCount )
return E_OK;
col2Count = split( colArr[idx], col2Arr, "=" );
if ( col2Count != 2 )
return E_ILLEGAL_PARAMETER; # invalid row spec
if ( idx == 1 )
{
# vertically search only the first spec
while ( (rc = FRM_TBL_find_cell( tbl, col2Arr[2], out_row, dummy, "", col2Arr[1], TRUE, row_offset ) ) == E_OK )
{ # found the first one, now find the others
row_offset = substr( out_row, 2 );
rc = FRM_TBL_find_row( tbl, row_spec, dummy, ++idx, row_offset );
if ( rc == E_OK )
return rc;
row_offset++;
}
return rc;
}
# recursive part
# search for other colums is limmited only to curent row
rc = FRM_TBL_find_cell( tbl, col2Arr[2], out_row, dummy, "#"&row_offset, col2Arr[1], TRUE, row_offset );
if ( rc == E_OK )
return FRM_TBL_find_row( tbl, row_spec, dummy, ++idx, row_offset);
return rc;
}
#/**
#* Searches for a cell that contains a given <code>regex</code>.
#* You can limit the search to a particular <code>row</code> or a <code>col</code>,
#* by providing their names or indices (#idx).
#*
#* @param tbl (in) table object
#* @param regex (in) text to search for (regular expression)
#* @param out_row (out) row where text was found
#* @param out_col (out) column where text was found
#* @param row (in) [optional] limit the search to this row only
#* @param col (in) [optional] limit the search to this column only
#* @param exact (in) [optional] TRUE=exact match, FALSE=tolerant match [default=FALSE]
#* @param row_offset (in) [optional] row index where the search begins [default=0]
#* @return
#* E_OK: text found
#* E_NOT_FOUND: text not found
#* else: other error
#*/
public function FRM_TBL_find_cell( in tbl, in regex, out out_row, out out_col, in row, in col, in exact, in row_offset )
{
extern RLENGTH;
auto rows, cols;
auto offset = (row_offset == "" ? 1 : row_offset);
auto val;
auto rc;
rc+=tbl_get_rows_count( tbl, rows );
rc+=tbl_get_cols_count( tbl, cols );
if ( rc )
return rc;
rows += FRM_TBL_get_rows_count_adjustment();
cols += FRM_TBL_get_cols_count_adjustment();
if ( int(row) > rows || int(col) > cols )
return E_ILLEGAL_PARAMETER;
# search the whole table (left-to-right, top-to-botom)
if ( row == "" && col == "" )
{
for ( out_row=offset; out_row<rows; out_row++ )
{
for ( out_col=0; out_col<cols; out_col++ )
{
rc = tbl_get_cell_data( tbl, "#"&out_row, "#"&out_col, val );
if ( rc ) return rc;
if ( match( val, regex ) )
{
if ( !exact || RLENGTH == length( val ) )
{
out_row = "#"&out_row;
out_col = "#"&out_col;
return E_OK;
}
}
}
}
return E_NOT_FOUND;
}
# search within a column
if ( row == "" && col != "" )
{
out_col = col;
for ( out_row=offset; out_row<rows; out_row++ )
{
rc = tbl_get_cell_data( tbl, "#"&out_row, out_col, val );
if ( rc ) return rc;
if ( match( val, regex ) )
{
if ( !exact || RLENGTH == length( val ) )
{
out_row = "#"&out_row;
return E_OK;
}
}
}
return E_NOT_FOUND;
}
# search within a row
if ( row != "" && col == "" )
{
out_row = row;
for ( out_col=0; out_col<cols; out_col++ )
{
rc = tbl_get_cell_data( tbl, out_row, "#"&out_col, val );
if ( rc ) return rc;
if ( match( val, regex ) )
{
if ( !exact || RLENGTH == length( val ) )
{
out_col = "#"&out_col;
return E_OK;
}
}
}
return E_NOT_FOUND;
}
# check the single cell
out_row = row;
out_col = col;
rc = tbl_get_cell_data( tbl, out_row, out_col, val );
if ( rc ) return rc;
if ( match( val, regex ) )
{
if ( !exact || RLENGTH == length( val ) )
return E_OK;
}
return E_NOT_FOUND;
}
#/**
#* Selects the cell and opens it's popup menue via the <kAppa> key.
#* @param tbl (in) table object
#* @param row (in) row to select
#* @param col (in) column to select
#*/
public function FRM_TBL_popup_cell_menu( in tbl, in row, in col )
{
auto rc;
rc = FRM_TBL_select_cell( tbl, row, col );
if ( rc != E_OK )
return rc;
# press the popup menu key
return obj_type( tbl ,"<kApps>" );
}
#/**
#* Opens a popup menue at the specified location within the table object
#* or, if not specified, at the top-left corner of the table object.
#* @param tbl (in) table object
#* @param x (in) [optional] x-coordinate to click to [default: 0]
#* @param y (in) [optional] y-coordinate to click to [default: 0]
#*/
public function FRM_TBL_popup_menu( in tbl, in x, in y )
{
return obj_mouse_click( tbl, x*1, y*1, RIGHT );
}
#/**
#* Pops a drop-down list on a Stingray-ComboBox-cell by performing
#* a left-mouse click at some calculated position within the <code>obj</code>.
#*
#* @param obj (in) object to click
#* @param list (in) list object that drops down after the click
#* @param item (in) item to select
#* @return
#* E_OK: success
#* else: failure
#*/
public function FRM_TBL_list_select_item ( in obj, in list, in item )
{
auto rc;
auto w, h;
rc+=FRM_TBL_obj_drop_list( obj );
rc+=list_select_item( list, item );
return rc;
}
#/**
#* Pops a drop-down list on Stingray-ComboBox-cell by performing
#* a left-mouse click at some calculated position within the <code>obj</code>.
#*
#* @param obj (in) object to click
#* @return
#* E_OK: success
#* else: failure
#*/
public function FRM_TBL_obj_drop_list ( in obj )
{
auto rc;
auto x,y, w, h;
#printf( "%s", obj );
rc+=obj_get_info( obj, "abs_x", x );
rc+=obj_get_info( obj, "abs_y", y );
rc+=obj_get_info( obj, "width", w );
rc+=obj_get_info( obj, "height", h );
#printf( "Before Clicking %d", rc );
# rc+=obj_mouse_click( obj, w-11, h/2, LEFT );
rc+=move_locator_abs( x+w+5, y+(h/2) );
rc+=click("Left");
#printf( "After Clicking %d", rc );
return rc;
}
public function FRM_TBL_web_get_child_item( in tbl, in row, in col, in desc )
{
auto object;
auto itemArr[];
auto count;
auto rc;
count = split( desc, itemArr, ":" );
if ( count != 3 )
{
return E_ILLEGAL_PARAMETER;
}
rc = web_obj_get_child_item ( tbl, row, col, itemArr[2], itemArr[3], object );
if ( rc == E_OK )
return object;
else
return rc;
}