How to: Replace the Report Builder's Expression Builder Dialog Box
The Report Builder architecture defines a framework into which you can plug your own classes to handle specific builder actions, such as responding to report designer events. Additionally, the report builder also allows you to replace the Expression Builder dialog box with your own implementation, by registering a class in the report builder's event handler registry table.
This topic describes the process of plugging in your own class to replace the expression builder dialog box, and also gives a more comprehensive example class that demonstrates how to create a Data Environment-aware expression builder.
Note
If you have not already done so, create an editable copy of the report builder's internal event handler registry table, as described in How to: Add Your Own Handler to the Report Builder's Registry.
Note
This topic assumes that the _REPORTBUILDER system variable is set to the default Report Builder application. If it is empty, or has been set to a third-party report builder, then the procedures described below probably will not apply. For more information, see _REPORTBUILDER System Variable.
To create a GetExpression wrapper class
Create or edit a programmatic class library:
MODIFY COMMAND c:\temp\mylibrary.prg
Define a class that implements the GetExpression wrapper API, as documented in Report Builder Event Handler Registry Table. You can use the simple example shown here as a template. This example replaces the label caption editor with a simple input box.
Save your changes.
DEFINE CLASS MyGetExpressionWrapper AS Custom
PROCEDURE GetExpression( cDefaultExpr, cDataType, ;
cCalledFrom, oEvent )
LOCAL cNewValue
* Switch to the designer datasession, where tables
* may be open:
SET DATASESSION TO (oEvent.DefaultSessionID)
DO CASE
CASE m.cCalledFrom = "LabelCaption"
* Specify special handling for label captions:
cNewValue = INPUTBOX("Enter the label caption")
OTHERWISE
* All other expression builders will use the default:
GETEXPR "Enter the label caption" TO cNewValue ;
TYPE cDataType DEFAULT cDefaultExpr
ENDCASE
* Restore to the private builder datasession:
SET DATASESSION TO (oEvent.FrxSessionID)
RETURN cNewValue
ENDPROC
ENDDEFINE
To register your class as in the handler registry table
Open the Report Builder Options dialog box:
DO (_REPORTBUILDER)
Click Explore Registry.
Locate the record with Type = "G".
Edit the record so that Class = "MyGetExpressionWrapper" and Library= "c:\temp\mylibrary.prg"
Click OK to save your changes.
To test your changes
Open a report or label layout in the designer.
Double-click on a label control to display the Properties dialog box.
Click on the ellipsis (…) next to the label caption text box to invoke the custom expression builder provided by your class.
Example
By design and by default, the Expression Builder dialog box invoked by ReportBuilder.App does not show tables that are not open in the designer's data session. Tables and cursors included in the report layout's data environment are not available. This is a change from how the designer's Expression Builder behaved in earlier versions (and still does when _REPORTBUILDER = "").
This example shows how you can define an alternative wrapper class that inspects the data environment, opens the tables in a private data session and then invokes the standard GETEXPR dialog box, to duplicate the original behavior of the report designer's Expression Builder.
You can save this class to a procedure file, and register it for use in the report builder, as described above.
DEFINE CLASS GetExpressionWithDE AS Session
DataSession = 2 && private
PROCEDURE GetExpression
LPARAMETERS lcDefaultExpr, lcDataType, lcCalledFrom, loEvent
LOCAL lCurSel, lcNewExpr, liPrivateSession
LOCAL liLines, i, iTableCount, lcAlias, lcSource
*----------------------------------------------
* Save this before it changes:
*----------------------------------------------
liPrivateSession = THIS.DataSessionId
*----------------------------------------------
* Scan the data environment and open tables:
*----------------------------------------------
SET DATASESSION TO (loEvent.FrxSessionId)
lCurSel = SELECT()
iTableCount = 0
SELECT expr FROM frx WHERE objtype = 26 ;
INTO CURSOR environCursors
SELECT environCursors
SCAN
liLines = ALINES(laValuePairs, environCursors.expr )
FOR i = 1 TO liLines
DO CASE
CASE LEFT(UPPER(laValuePairs[i]),5) == "ALIAS"
lcAlias = THIS.GetValue( laValuePairs[i])
CASE LEFT(UPPER(laValuePairs[i]),7) == "CURSORS"
lcSource = THIS.GetValue( laValuePairs[i])
ENDCASE
ENDFOR
lcSource = EVL(lcSource,"")
DO CASE
CASE FILE(lcSource)
CASE FILE(FORCEEXT(lcSource,"DBF"))
lcSource = FORCEEXT(lcSource,"DBF")
CASE FILE(JUSTFNAME(lcSource))
lcSource = JUSTFNAME(lcSource)
CASE FILE(FORCEEXT(JUSTFNAME(lcSource),"DBF"))
lcSource = FORCEEXT(JUSTFNAME(lcSource),"DBF")
ENDCASE
IF FILE(lcSource)
lcAlias = EVL( lcAlias, "Cursor"+TRANSFORM(i))
SET DATASESSION TO (liPrivateSession)
IF NOT USED(lcAlias)
TRY
IF EMPTY(ALIAS())
USE (lcSource) ALIAS (lcAlias) ;
NOUPDATE SHARED
ELSE
USE (lcSource) ALIAS (lcAlias) ;
IN 0 NOUPDATE SHARED
ENDIF
iTableCount = iTableCount+1
CATCH WHEN .T.
ENDTRY
ENDIF
SET DATASESSION TO (loEvent.FrxSessionID)
ENDIF
ENDSCAN
USE IN environCursors
SELECT (lCurSel)
IF iTableCount > 0
SET DATASESSION TO (liPrivateSession)
ELSE
SET DATASESSION TO (loEvent.DefaultSessionID)
ENDIF
*-----------------------------------
* Display the GETEXPR dialog:
*-----------------------------------
GETEXPR TO lcNewExpr TYPE lcDataType DEFAULT lcDefaultExpr
*-----------------------------------
* Clean up and exit:
*-----------------------------------
SET DATASESSION TO (liPrivateSession)
CLOSE DATA
SET DATASESSION TO (loEvent.FrxSessionID)
RETURN lcNewExpr
ENDPROC
PROTECTED PROCEDURE GetValue
LPARAMETER lcValuePair
LOCAL liPos, lcReturn
lcReturn = ""
IF NOT EMPTY(lcValuePair)
liPos = AT("=",lcValuePair)
IF EMPTY(liPos)
RETURN ""
ENDIF
lcReturn =CHRTRAN(ALLTRIM(SUBSTR(lcValuePair,liPos+1)),["'],[])
ENDIF
RETURN lcReturn
ENDPROC
ENDDEFINE
See Also
Tasks
How to: Configure the Report Builder's Event Handling
How to: Specify an Alternate Report Event Handler Table
Concepts
Understanding Report Builder Events
Reference
Event Handler Registry Dialog Box (Report Builder)