Updating the DatawindowDebugMachine

I recently figured out that I never published my last updates on this utility.

I removed all references to PBNI to make it easier to integrate in a PowerBuilder project.

The native treeview is replaced by a treedatawindow to make filter faster, and filter is split into two SLE inputs so we can filter on object names and attributes separately.

I realized that it was possible to optimize the window loading significantly: the “w_genidwdm_dwdebugger.of_cache_attributes()” function is loading all attributes for all objects. That’s fine because we may need to filter them, but the way I load these attributes was not optimum. It was aksing for all attributes and parsing them every time, but the attributes list is the same for a given object type!

string ls_data
string ls_controls, ls_control, ls_properties, ls_property, ls_type
ls_controls = trim(idw_obj.describe( "datawindow.objects" ),true) + "~tdatawindow~t"
long ll_pos_start = 1, ll_pos_end, ll_prop_start, ll_prop_end, ll_col_id
long row= 1
do
	ll_pos_end = pos( ls_controls, "~t", ll_pos_start + 1 )
	if ll_pos_end <> 0 then
		ls_control = mid( ls_controls, ll_pos_start, ll_pos_end - ll_pos_start )
		ll_pos_start = ll_pos_end + 1
		ls_properties = trim(idw_obj.describe(ls_control+".attributes"),true)+"~t"
		ll_prop_start = 1
		ll_col_id = 0
		if ls_control = 'datawindow' then 
			ls_type = 'datawindow'
		else
			ls_type = idw_obj.describe(ls_control+".type")
			if ls_type = 'column' then
				ll_col_id = long( idw_obj.describe( ls_control+".id" ) )
			end if
		end if
		do
			ll_prop_end = pos( ls_properties, "~t", ll_prop_start + 1 )
			if ll_prop_end <> 0 then
				ls_property = mid( ls_properties, ll_prop_start, ll_prop_end - ll_prop_start )
				ll_prop_start = ll_prop_end + 1
				ls_data += ls_type + "~t" + ls_control + "~t" + ls_property + "~t" + string(ll_col_id) + "~t"+string(row)+"~r~n"
				row ++
			end if	
		loop while ll_prop_end > 0
	end if
loop while ll_pos_end > 0
dw_attributes.importstring( Text!, ls_data)

So, it is possible to get attributes once and reuse them to speed up the loading phase.

string ls_data
string ls_controls, ls_control, ls_properties, ls_property, ls_type
ls_controls = trim(idw_obj.describe( "datawindow.objects" ),true) + "~tdatawindow~t"
long ll_pos_start = 1, ll_pos_end, ll_prop_start, ll_prop_end, ll_col_id
long row= 1, ll_cache_begin, ll_cache_end, ll_rows = 0, i
//used to fast insert attributes
string ls_types[], ls_control_names[], ls_empty[], ls_cache_types[]
long ll_uids[], ll_column_ids[], ll_empty[], ll_cache_begins[], ll_cache_ends[]
do
	ll_pos_end = pos( ls_controls, "~t", ll_pos_start + 1 )
	if ll_pos_end <> 0 then
		ls_control = mid( ls_controls, ll_pos_start, ll_pos_end - ll_pos_start )
		ll_pos_start = ll_pos_end + 1
		ll_prop_start = 1
		ll_col_id = 0
		if ls_control = 'datawindow' then 
			ls_type = 'datawindow'
		else
			ls_type = idw_obj.describe(ls_control+".type")
			if ls_type = 'column' then
				ll_col_id = long( idw_obj.describe( ls_control+".id" ) )
			end if
		end if
		for i = 1 to upperbound(ls_cache_types[])
			if ls_cache_types[i] = ls_type then
				ll_cache_begin = ll_cache_begins[i]
				ll_cache_end = ll_cache_ends[i]
				exit
			end if
		next
		if ll_cache_begin > 0 then
			dw_attributes.rowscopy( ll_cache_begin, ll_cache_end, primary!, dw_attributes, ll_rows + 1, primary!)
			ls_control_names[] = ls_empty[]
			ls_types[] = ls_empty[]
			ll_column_ids[] = ll_empty[]
			ll_uids[] = ll_empty[]
			for i = 1 to ll_cache_end - ll_cache_begin + 1
				ls_control_names[i] = ls_control
				ls_types[i] = ls_type
				ll_column_ids[i] = ll_col_id
				ll_uids[i] = ll_rows + i
			next
			ll_cache_end += ll_rows + 1 - ll_cache_begin
			ll_cache_begin = ll_rows + 1
			dw_attributes.object.control_name[ll_cache_begin, ll_cache_end] = ls_control_names[]
			dw_attributes.object.control_type[ll_cache_begin, ll_cache_end] = ls_types[]
			dw_attributes.object.column_id[ll_cache_begin, ll_cache_end] = ll_column_ids[]
			dw_attributes.object.uid[ll_cache_begin, ll_cache_end] = ll_uids[]			
			ll_rows = dw_attributes.rowcount( )
		else
			ls_properties = trim(idw_obj.describe(ls_control+".attributes"),true)+"~t"
			ll_cache_begin = ll_rows + 1
			do
				ll_prop_end = pos( ls_properties, "~t", ll_prop_start + 1 )
				if ll_prop_end <> 0 then
					ls_property = mid( ls_properties, ll_prop_start, ll_prop_end - ll_prop_start )
					ll_prop_start = ll_prop_end + 1
					ls_data += ls_type + "~t" + ls_control + "~t" + ls_property + "~t" + string(ll_col_id) + "~t"+string(row)+"~r~n"
					row ++
				end if	
			loop while ll_prop_end > 0
			dw_attributes.importstring( Text!, ls_data)
			ll_rows = dw_attributes.rowcount( )
			ll_cache_end = ll_rows
			ls_cache_types[upperbound(ls_cache_types[])+1] = ls_type
			ll_cache_begins[upperbound(ll_cache_begins[])+1] = ll_cache_begin
			ll_cache_ends[upperbound(ll_cache_ends[])+1] = ll_cache_end
			ls_data = ""
		end if
	end if
loop while ll_pos_end > 0

The previous code takes about 183 ms to cache the sample dataobject and the new code takes 15 ms, it is now more than 10 times faster. It looks like to be only 160ms but when working a huge dataobject it makes a big difference!

The new version improves controls and attributes filtering but there are missing features:

context menu, show/hide control by types

Also optimizing the auto_resizer object to use less classdefinition call.

So working on that context menu before releasing the first public release.

Stay tuned!

Leave a Reply