################################################################################ # 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; }