Chapter 4
Better Tools

Visual FoxPro has a long tradition of providing developers with tools that increase productivity so you can bring applications to market quicker. Visual FoxPro 9 continues this tradition in grand style.

The overhaul of the Report Designer seems to be the central focus for most developers in VFP 9. The Report Designer is the tool that garnered the biggest share of resources and definitely has a big impact for developers from a productivity viewpoint, and for end-user applications. However, it is not the only tool in Visual FoxPro that is better than in previous versions. This chapter focuses on the changes to the other IDE components, and shows you some of the changes we think will have a big impact on your productivity and the day-to-day development experience with Visual FoxPro.

Changes to Options dialog

Microsoft adds new settings to the Options dialog in each new version of Visual FoxPro, and Visual FoxPro 9 is no different.

The View page now has the setting to control the IntelliSense dropdown list count (formerly on the Editor page). You can use List display count to increase or decrease this setting from the default of 15 as low as 5 or as high as 200.

The File Locations page has new entries for the Menu Designer, Report Builder, Report Output, and Report Preview. These settings are related to the new _MENUDESIGNER hook for the Menu Designer discussed in detail later in this chapter, and the new Report System features hooked in by the _REPORTBUILDER, _REPORTOUTPUT, and _REPORTPREVIEW system variables (discussed in Chapter 5, “Enhancements in the Reporting System,” Chapter 6, “Extending the Reporting System at Design Time,” and Chapter 7, “Extending the Reporting System at Run Time”).

The IDE page has one simple change, the new option of selecting Project from the Specify file/window dropdown (Figure 1). We discuss additional options for setting the Project Manager font in Chapter 1, “Project Manager Improvements.”

The Reports page (Figure 2) is where Microsoft made the most changes to the Options dialog. All the changes to this page of the dialog reflect the new report system functionality. The Report Engine behavior dropdown allows you to configure the SET REPORTBEHAVIOR command to 80 for report functionality compatible with VFP 8 and earlier, or 90, which uses the object-assisted features included with Visual FoxPro 9. The impact of this new command is discussed in Chapter 7, “Extending the Reporting System at Run Time.”

Figure 1. The IDE page of the VFP Options dialog is where you set the font for
all projects.


Figure 2. The Reports page of the Options dialog is where Microsoft made the most changes, specifically to support the new Reporting System.

Redirect Options dialog output

One of the little known tricks we often demonstrate to Visual FoxPro developers is the ability to send the Option dialog settings to code. The code is only generated if you hold down the Shift key when you click the OK button on the Options dialog. Prior to Visual FoxPro 9, this output was created in the Command Window. The output is now redirected to the Debug Output window if it is open. If the Debug Output window is not open, the code is not generated. The advantage of this new output location is simply not adding extra code to the Command Window because the code is retained between VFP sessions. Also, it’s easy to save the contents of the Debug Output window to a file. The shortcut menu has a “Save As,” so you don’t have to cut and paste.

View and Query Designers

Microsoft made significant improvements to the View and Query designers in Visual FoxPro 8. The Visual FoxPro 9 upgrade includes one important enhancement and one major change
in behavior.

Spaces in table and view names in FROM clause

The one enhancement to the View/Query designer centers on creating SQL Selects with spaces in either the base table or the base view name. Here is an example of a remote view to the SQL Server Northwind database using the “Current Product List” view.

SELECT Current_product_list.ProductID, ;

       Current_product_list.ProductName ;

   FROM dbo."Current Product List" Current_product_list ;

   WHERE  Current_product_list.ProductName LIKE ?vp_ProductName ;

   ORDER BY Current_product_list.ProductName

You must have an alias for the base table/view and the alias cannot have spaces in
the name.

Visual FoxPro 8 allows you to create a local and remote view with spaces in the base table/view name. Error 36, “Command contains unrecognized phrase/keyword”, occurs
when the view is reopened in the designer and you attempt to save the view again. The
View Designer now opens without an error and does not trigger the error when the view
is saved again.

Macro expansion based SQL clauses

The behavior change with the View Designer involves views using macro expansion in the SQL Select clauses for local views. Microsoft has changed the way developers need to structure the SQL Select code to include one or more macro expansion variables inside the view. The macro expansion is performed when the view is opened. The design of such views allows developers to use one view for many different conditions (WHERE and HAVING clause for filtering, ORDER BY sorting, GROUP BY aggregation) instead of maintaining one view for every condition on the same set of base tables. It enables developers to create “on-the-fly” queries and still maintain the views in a database container.


Text Box: ¥

Microsoft is on record stating views were not designed to support macro substitution for any clause. Developers have tried this and made it work and have implemented applications relying on this behavior. The View Designer behavior change discussed in this section demonstrates that Microsoft is not responsible for undocumented behavior, and your use of it might break code in your applications.

Text Box: "

The Developer Downloads for this chapter, available from www.hentzenwerke.com, include a database with views that include macro expansion clauses and some programs to create and use the macro expansion views. The database is called ViewDesignerChanges.DBC, and the programs are called CreateMacroSubViews.PRG and TestMacroSubViews.PRG.

The big change with respect to macro expansion in view clauses is the way you store the macro expansion variable inside the DBC. This technique changed with the release of Visual FoxPro 8 and again with Visual FoxPro 9. Prior to Visual FoxPro 8, you had to ensure the macro variable was not declared or in scope when you created the view with code like this:

CREATE SQL VIEW AuthorsWithFlexibleClauses2 AS ;

   SELECT Authors.Authors_Pk, ;

          Authors.cLastName, ;

          Authors.cFirstName, ;

          Authors.cCountry;

      FROM viewdesignerchanges!Authors ;

      WHERE &?lcWhere ;

Note that the macro expansion variable is prefixed in the code with “&?.” In VFP 8, Microsoft changed the rules so developers needed to remove the question mark normally used for view parameters:

CREATE SQL VIEW AuthorsWithFlexibleClauses2 AS ;

   SELECT Authors.Authors_Pk, ;

          Authors.cLastName, ;

          Authors.cFirstName, ;

          Authors.cCountry;

      FROM viewdesignerchanges!Authors ;

      WHERE &lcWhere ;

In Visual FoxPro 9, the rules change again. Macro expansion has reverted to the same style as Visual FoxPro 7 (both the ampersand and question mark). This means all existing views created or saved in Visual FoxPro 8 need the question mark added back in. If you skipped Visual FoxPro 8, you will not have to change a thing if you implemented macro expansion based views.

No matter how you create the views, the first step in Visual FoxPro 9 is to declare memory variables for each of the macro expansions you plan on including in your view. This is completely different from any previous version of Visual FoxPro. If you are using the View Designer or a third-party view editor, you can create PUBLIC memory variables in the Visual FoxPro Command Window. If you create the view programmatically, you can declare the memory variables directly in the code. The variable is a character data type and must contain Visual FoxPro syntax that compiles cleanly. The variable or variables must be in scope when the view is saved.

The View Designer does not support the process of saving a view with macro expansion in a straightforward manner. If you use the View Designer you set up the entire view, skipping any of the normal designer pages associated with the macro expansion clause. Once the view is completely defined, switch to the SQL code editor. Add the macro expansion clauses and remain in the SQL code editor. Save the view by clicking the save button on the Visual FoxPro toolbar or File | Save on the menu. When you close the SQL code editor, you are presented with a syntax error. Click the OK button and another message is displayed (Figure 3) asking if you want the designer to reload the SQL code editor based on content from the View Designer. At this point the view is saved, so answering yes does not harm anything. Make sure when you close the SQL code editor (Figure 4) the second time do not save your changes; otherwise they will overwrite the saved view.

Figure 3. The View Designer will choke on the macro-substitution any time you try to close the SQL code editor window.

You might find it easier to create the views programmatically, or use one of the third-party view editors available. Listing 1 shows how to create the view programmatically, and Listing 2 shows how you can use the macro-substituted views in your applications.

Listing 1. You have to ensure the variables substituted in the view are declared and in scope when the view is created. This code is a shortened version of the view generation code found in CreateMacroSubViews.PRG.

CLOSE DATABASES ALL

OPEN DATABASE ViewDesignerChanges

 

PUBLIC lcWhere

lcWhere = ".T."

 

PUBLIC lcOrderBy

lcOrderBy = ".T."

 

CREATE SQL VIEW AuthorsWithFlexibleClauses2 AS ;

   SELECT Authors.Authors_Pk, ;

          Authors.cLastName, ;

          Authors.cFirstName, ;

          Authors.cCountry;

      FROM viewdesignerchanges!Authors ;

      WHERE &?lcWhere ;

      ORDER BY &?lcOrderBy

Figure 4. Add the macro expansion clauses (highlighted) after you set up the rest of the view so you can take advantage of the designer to set all the basic properties.

Opening views that use macro expansion does not change. Declare the variables used in the macro expansion, assign appropriate values to the variables, and open the view. Also remember the memory variables need to be in scope during any REQUERY().

Listing 2. This code sample shows how you can use macro-substitution to have a single view retrieve a completely different set of records from the same base table.

LOCAL lcWhere, ;

      lcOrderBy

 

IF USED("curAuthorsWithSInName")

   USE IN (SELECT("curAuthorsWithSInName"))

ENDIF

 

IF USED("curUsAuthors")

   USE IN (SELECT("curUsAuthors"))

ENDIF

 

IF USED("curCanadianAuthors")

   USE IN (SELECT("curCanadianAuthors"))

ENDIF

 

lcWhere = "cLastName LIKE [S%]"

lcOrderBy = "Authors.cFirstName"

USE ViewDesignerChanges!AuthorsWithFlexibleClauses IN 0 ALIAS curAuthorsWithSInName

SELECT curAuthorsWithSInName

BROWSE NORMAL

 

lcWhere   = "cCountry = [USA]"

lcOrderBy = "Authors.cLastName, Authors.cFirstName"

USE ViewDesignerChanges!AuthorsWithFlexibleClauses IN 0 ALIAS curUsAuthors

SELECT curUsAuthors

BROWSE NORMAL

 

lcWhere   = "cCountry = [CANADA]"

lcOrderBy = "Authors.cLastName, Authors.cFirstName"

USE ViewDesignerChanges!AuthorsMacroedWithVD IN 0 ALIAS curCanadianAuthors

SELECT curCanadianAuthors

BROWSE NORMAL

 

USE IN (SELECT("curAuthorsWithSInName"))

USE IN (SELECT("curUsAuthors"))

USE IN (SELECT("curCanadianAuthors"))

USE IN (SELECT("authors"))

 

RETURN

Text Box: ¥

One technique recommended by developers who deploy macro expansion based views is to adopt a naming convention and consistently name the clauses with the same memory variable. Then declare the variables as part of your VFP startup program if you have one.

If you use the View Designer to make changes, a syntax error is displayed when you open the view each time and the view is opened in the SQL code editor. You can make changes and save the changes, but only in the code.

Class Designer and Form Designer changes

The Class and Form Designers might just be the tools most often used by Visual FoxPro developers. Any changes that enhance the usability or increase productivity with these designers usually have a big impact.

Class/Form Designer Tab Order selection

There have been two different ways to change the tab order of controls in the Form and Class Designers since VFP 3.0. Some developers prefer By List, some developers prefer the Interactive method, and some of you prefer to use one under certain circumstances and the other under different circumstances. If you like to change frequently, you might find toggling between the two styles a tedious task. Prior to Visual FoxPro 9, there were two ways to toggle your tab order method; you could either use the Options dialog, or write some code to toggle the Windows Registry entry.

Visual FoxPro 9 extends the Tab Order menu option found on the View pad (Figure 5). Your selection in the Visual FoxPro Options dialog no longer toggles the menu option, and you have to select which one you want to use each time you set the tab order.

Figure 5. The Form Designer and Class Designer allow you to select which style of Tab Ordering you want from the View Menu.

If you use the Form Designer Toolbar, the button for Tab Order on the toolbar respects the current setting of the Tab Order selected on the Options dialog.

Keyboard shortcuts for adjusting object spacing

Sometimes the simple things in life are the most enjoyable. Visual FoxPro has a number of alignment and object spacing tools included on the Layout toolbar and the Format menu. Specific to Visual FoxPro 9 are some new keystroke combinations (see Table 1) to assist with adjusting the space between objects.

Table 1. There are two new keyboard combinations to adjust the space between the objects.

Keystroke

Adjustment

Alt+Arrow Key

Adjusts the space in the direction of the arrow key between the objects by one pixel.

Alt+Ctrl+Arrow Key

Adjusts the space between the selected objects by one grid scale in the direction of the arrow key. This is similar to snap-to-grid movement.

 

Data Environment changes

One small, but helpful change to the Data Environment Designer is the display of the database container (DBC) and the full path to the database container in the Visual FoxPro status bar (Figure 6) when you add a table or view to the data environment. The trick to displaying the database container is to drop down the Database combobox. Obviously you need SET STATUS BAR ON to observe this functionality.

Figure 6. The database container (highlighted) is displayed in the VFP status bar when the Database dropdown is opened.

Enhancements to title bar descriptions

If you have several classes or forms open in the designer and want to add a new property or method, or want to work with the Edit Property/Method, how do you tell what class or form you are working with when you open one of the various dialogs associated with the designer? You hope you can see the front most designer, but often it is hidden under several code windows. Visual FoxPro 9 adds the form file name (if working with a form) or the class library and class name (if working with a class) to the title bar of the dialog box. These four dialogs have this addition:

·         New Property

·         New Method

·         Edit Property/Method

·         Class Info

Enhancements to Document View

The Fox Team listened to a common request from developers with respect to the Document View (Figure 7). You can now sort the list by name (object name / member name) in addition to the default sort by location. Previously, the Sort By Name was only available when you worked with programs (PRG).

Figure 7. In VFP 9, more sort options are enabled in Document View (seen on
the right).

Builder behavior changes

Builders registered in the Builder.DBF file and marked deleted respect the current setting of SET DELETED. If you have SET DELETED OFF, the Builder Selection dialog operates like previous versions of VFP (displaying builders deleted in the registration table). The behavior change is more apparent if you have SET DELETED ON. If you have one builder registered for an object type, and it’s deleted, no builder runs for that object type; if you have multiple builders registered for the same object type, any builders marked deleted do not show up in the Builder list. This means developers can remove builders without the need to PACK the builder registration table.

Integrate your own menu designer

The Menu Designer has been slightly enhanced over the years to add icons to the menu and let you move menu items from one pad to another, but the basic interface has not changed dramatically. Developers have asked for enhancements to the designer to make it easier to use. Instead of dedicating the resources to overhaul the Menu Designer, Microsoft decided to expose a hook to allow developers to run their own customized designer. We do not anticipate the majority of developers will go out and write a menu designer taking advantage of this functionality, but we know of at least one and expect other third-party developers to create menu designers that do take advantage of this feature.

The hook is centered on a new system variable called _MENUDESIGNER. This system variable should be set to the program, application, or executable you want run instead of the standard Menu Designer. You set this in the Visual FoxPro Options dialog (Figure 8) on the File Locations page, or by programmatically setting the _MENUDESIGNER system variable via the Config.FPW, during the execution of your start up program or directly in the Command Window.

_MENUDESIGNER = "d:\WLCProjects\DevTools\MenuDesigner\MenuDesigner.exe"

The advantage of this implementation is the ability to switch between a custom menu designer and the native designer. If you specify a custom menu designer, none of the native features are available until you reset the system variable to the null string.

_MENUDESIGNER = SPACE(0)

Obviously you can toggle the setting between your custom menu designer and the native menu designer by setting the _MENUDESIGNER system variable. This way, if your custom designer does not provide all the features of the native designer, it is simple to use the designer with the functionality you need. If several third-party tool providers ship products you literally can use all of them, just one at a time.

Figure 8. The _MENUDESIGNER system variable is set on the File Locations page of the Options dialog.

Once the new system variable is set, you open the customized menu designer the same way you open the native Visual FoxPro Menu Designer:

·         MODIFY MENU

·         CREATE MENU

·         Modify a menu via the Project Manager.

·         Create a new menu via the Project Manager.

·         Select Menu from the New dialog presented after picking File | New on the menu or clicking the New button on the standard toolbar.

·         Use the EDITSOURCE() function to open the source code of a menu.

·         Use the Files Object Modify method to edit a menu.

If you use the CREATE MENU ?, MODIFY MENU ?, or MODIFY MENU commands, or click the Add button on the Project Manager, the Open File dialog is presented. If you pick a menu file or provide the file name, you continue to the custom menu designer, just as you would with the native Menu Designer. If you cancel the Open File dialog, the custom menu designer is not called at all.

If you CREATE MENU, click the New button on the Project Manager, or select the File | New menu option or New button on the Standard toolbar, you are presented with the New Menu dialog to select a regular menu or a shortcut menu. Selecting one of the two menu styles starts the designer; canceling indicates to Visual FoxPro the designer should not be started.

Text Box: ¥

The Files collection’s Add method does not initiate the custom menu designer, just as it does not execute the native Menu Designer.

Text Box: ¥

If you open the menu via the EDITSOURCE() function, it behaves as if you executed a MODIFY MENU NOWAIT.

Your customized menu designer can do anything you want, but it has to conform to some fundamental specifications.

Text Box: ¥

Your customized menu designer must return a logical value. If the customized menu designer returns False, the native Visual FoxPro Menu Designer is opened; otherwise Visual FoxPro assumes the customized menu designer handled the call. This is a terrific design because third-party products that intentionally do not support specific functionality can gracefully not load and the native Menu Designer will function as it normally does.

The entry point into the designer code must accept three parameters. The parameters help you determine how the menu designer was called, important items like the menu file name, and the different clauses used in the MODIFY/CREATE MENU commands. The contents of the parameters differ depending on how the menu was called.

The first parameter is the file name. This parameter is a fully qualified path and file name (with MNX extension) when you specify a menu file or pick one via the Open dialog. When you do not provide the file, the file name is a generic file without the path and extension. In this case the parameter is “Menu” followed by an auto-incrementing number.

The second parameter is a numeric value indicating how the menu designer was started. Table 2 lists the valid parameter values and what they mean.

Table 2. Valid settings for the second menu designer parameter and the meaning of each of the values.

nCommandType

Meaning

1

A standard system menu was selected using the New Menu dialog.

2

A shortcut menu was selected using the New Menu dialog.

3

The menu designer was started by MODIFY MENU.

 

The last parameter is an array with additional information about how the menu designer was called; if there’s no additional information to pass in, this parameter receives False. If the menu is new via the Project Manager’s New button, the array is has one row and is populated with “PROJECT” in the first column, and the project name with fully qualified path in the second column.

The other scenario causing an array to be passed in for the third parameter is to execute a CREATE MENU or MODIFY MENU command (in code or in the Command Window) with the optional IN, NOWAIT, SAVE, or WINDOW clause. The resulting array has one row for each of the clauses used in the command. If you do not use any of the clauses, there is no array. The clause is in the first column of the array. If you use the NOWAIT or SAVE clause, the second column always contains True. The IN clause has the name of the window or “SCREEN” in the second column. If you use the WINDOW clause, the name of the window is put in the second column of the array.

If neither of the two scenarios applies, the third parameter is passed as False. If you check PCOUNT(), you will see all three parameters are passed, so the third parameter is deliberately passed as .F., and is not just an optional parameter.

So the implementation is as simple as creating a program that accepts three parameters and deals with them appropriately, and assigning this program (with path if necessary) to the _MENUDESIGNER system variable. That is the easy part. If you are going to keep compatibility with the MNX file structure and allow the GenMenu process to run, you need to do a little research on how Visual FoxPro stores the menu source code in the MNX metadata file, and get your head around the GenMenu process. These are not difficult tasks, just something to consider before you start coding.

Text Box: ¥

The menu metadata source code files (MNX/MNT) are documented in the 60Spec.PJX  project found in the Tools\Filespec\ under the Visual FoxPro root directory.

So you have the implementation requirements, what are some practical implementation ideas? Here is a short list we considered since we learned about this functionality:

1)       Write a menu designer just to edit prompts, results, or address a specific weakness of the native designer so your menu editing is less painful.

2)       Write a menu designer that pre-processes the MNX file to add standard security, SKIP FOR logic, set the hot keys, or order the items on the menu pad to your preferences.

3)       Write a menu designer that supports custom object menus you created over the years. There is nothing saying you need to conform to or support the MNX structure.

4)       Write a menu designer with custom hooks for GenMenuX.

5)       Write a complete replacement for the native Menu Designer with complete compatibility with the existing menu infrastructure.

Text Box: "

The Developer Downloads for this chapter, available from www.hentzenwerke.com, include a test program called TestMenuDesignerParameters.PRG to demonstrate the parameters passed and the values assigned. Assign this program to the _MENUDESIGNER system variable and interact with the various menu designer calls to see what is passed to your custom menu designer.

While it would be great to supply you with a complete replacement for the Menu Designer, we do not have a couple hundred spare hours to do so and finish writing this chapter. Instead, we implement a quick menu designer sample to address the prompt editing and execution code (commands and procedures), Skip For, Message, and Comment properties because we think the native designer does not have enough space on the user interface to be very workable.

Text Box: "

The Developer Downloads for this chapter, available from www.hentzenwerke.com, include a form (RasSimpleMenuDesigner.SCX) and a program (RasSimpleMenuDesignerMain.PRG) that collaborate
and demonstrate how to write a very simple and functional custom
menu designer.

The example provided is not very robust and was created for demonstration purposes only. We recommend you make backups of the menus you want to work with in case something bad happens. The Save button is enabled, but does not actually save any changes. If you want to take the time to make sure the robustness you need is added to this sample code, you can uncomment the TABLEUPDATE command in the form’s Save method.

The main program (see Listing 3) accepts the three parameters passed by Visual FoxPro, checks to see if the menu exists, and calls the form presented as the “Simple Menu Designer.” If the menu file does not exist, which is the case if a new menu is created via the Project Manager New button or a CREATE MENU command, the native Menu Designer is called.

Listing 3. The main program for a simple menu designer.

* Simple Menu Designer - meant to serve as an example, not production solid

LPARAMETERS tcFileName, tnCommandType, taDetail

 

LOCAL loParameter AS Line, ;

      loForm AS Form, ;

      llReturnVal AS Logical 

 

* Consider it default custom designer handled

* the request so native designer does not start

llReturnVal = .T.

 

IF VARTYPE(tcFileName) = "C"

   IF FILE(tcFileName)

      * Good, we have an existing menu, continue

      * Create an object the form can use to pass along parameters

      * which are used before the form Init() fires.

      loParameter = CREATEOBJECT("line")

      loParameter.AddProperty("cFileName", tcFileName)

      _screen.AddProperty("__oRASSimpleMenuParameter", loParameter)

 

      * Start user interface in modal mode

      DO FORM RASSimpleMenuDesigner NAME loForm LINKED NOSHOW

      loForm.Show(1)

 

      _screen.__oRASSimpleMenuParameter = .NULL.


   ELSE

      * Let the native designer fire up and handle request.

      llReturnVal = .F.

   ENDIF

ELSE

   MESSAGEBOX("You need to pass parameters to this program and the file name parameter is not valid", ;

              0 + 16, ;

              "Simple Menu Designer")

ENDIF

 

RETURN llReturnVal

The Simple Menu Designer (see Figure 9) example form reads the property _screen. __oRASSimpleMenuParameter.cFileName, opens the MNX file, filters out records without prompts, and displays the menu information. You can navigate to other menu items using the grid. The command and procedure code displays when you navigate to a menu item with command or procedure code. The Prompt, Skip For, Message, and Comment can be edited for any menu item. The Object Code combobox (display only) tells you what type of menu item is currently available for editing. Take a look at this combobox in the Form Designer so you can see how you can translate the underlying “codes” to something more understandable in your custom designer. There are several items in the menu metadata you will want to translate on your designer.

As we noted earlier in this section, we do not expect every developer to jump on this new feature and create their own menu designer, but we do expect developer tool vendors to take a shot. We know there is a lot of room for improvement over the native Menu Designer. If you do consider creating your own, make sure to consider all the functionality you want to provide and understand that you do not need to write a complete replacement for the native designer. Design and create something that services the pain you feel the most with the native designer and start with this functionality. Think outside of the box and know you can break the mold and even skip the native MNX metadata source code and the GenMenu process of creating the MPR source code. As with other parts of Visual FoxPro 9, Microsoft has removed limitations and in this case has blown the lid off and exposed hooks so you can completely replace the native functionality.

Debugger

Microsoft did not place the Debugger high on the Visual FoxPro 9 priority list, but there are some very handy enhancements that should make it easier to figure out why your code does not work as you expect it to.

Constant support in Trace Window

Prior to Visual FoxPro 9, when stepping through code in the Trace window, there was no way to determine the value of a constant other than opening the source code containing the #DEFINE. In Visual FoxPro 9, hover the mouse over the constant and a tooltip appears showing the value, similar to memory variables.

Figure 9. The Simple Menu Designer is an example of how you can use the new _MENUDESIGNER hook to create your own menu designer replacement.

Figure 10. The Trace Window displays the compiled constant values in a tooltip.

There is one issue you need to be aware of with this new debugging feature. The tooltip shows the compiled line as the Visual FoxPro p-code interpreter sees it. If you use several constants together in a calculation, you only see the resulting value. We demonstrate this in Figure 10 with the MESSAGEBOX() function. The dialog box type parameter typically has two or more constants to determine the icon and buttons displayed with the message. Visual FoxPro compiles these together and the Trace Window displays the results.

Watch Window errors

The Watch window literally accepts anything you type into the watch expression textbox and tries to evaluate the expression. If errors occur prior to Visual FoxPro 9, you had no way of knowing it. In VFP 9 the errors display in the Debug Output (Figure 11) window. One example is typing THIS. in the expression and seeing the resulting error message in the Debug Output window.

Figure 11. The Watch window allows you to include almost anything, including code that triggers errors. VFP errors triggered in the Watch window now display in the Debug Output window.

Debug output window is mouse wheel enabled

One debugger oversight the Fox Team fixed in Visual FoxPro 9 is the ability to use the mouse scroll wheel in the Output Window. This is not an earth-shattering fix, but if you are accustomed to using the mouse wheel, it is a nice addition.

Reports can be debugged

Reports have never interacted with the Visual FoxPro debugger prior to Visual FoxPro 9. This presents a problem for developers who have reports with user-defined functions (UDFs) called in report expressions.

Visual FoxPro 8 throws Error 1651, “CANCEL or SUSPEND is not allowed,” if you execute SET STEP ON in a procedure or function called from a report. One of the alternatives you have to debug code is to simulate the call after setting up the data via the Command Window or a program. Alternatively, developers who stage the data using SQL Selects before calling the report call the UDFs in the SQL Select where the debugger is available rather than calling the UDF in the report expression.

The changes to the Report Designer (especially, the new ReportListener object) required the Fox Team to integrate debugging capabilities into reports. The integration is not limited to the ReportListener. You can debug your own UDF code as well, as shown in Figure 12.

Text Box: "

The Developer Downloads for this chapter, available from www.hentzenwerke.com, include a report and a procedure file used to demonstrate how to call the debugger when previewing or printing a report. The report is called AuthorDebugging.FRX, and the program is called AuthorInitials.PRG.

Figure 12. The debugger now works with reports so you can step through code called from a report expression or triggered through a ReportListener.

This enhancement is critical for developers who are writing ReportListener extensions, otherwise you would not have any way to debug your code as the report was executing. See Chapter 7, “Extending the Reporting System at Run Time,” for more details on the ReportListener object. The debugger is called in the same manner with SET STEP ON (or your favorite style of calling the debugger) in your code. The debugger does not interact with report expressions unless they trigger custom code in a ReportListener object, or call code in an object you created (different from a ReportListener), or run a user-defined function in program code.

The example we ship in the downloads is very easy to follow. First we create a report and in one of the report expressions call the AuthorInitials function. The AuthorInitials function takes the first and last name and assembles the initials from the name. In the function we add SET STEP ON. To simplify running the report we add the SET PROCEDURE TO code in the report data environment’s BeforeOpenTables method. The Trace window displays when the report is previewed or printed to a printer using the IDE toolbar buttons or the REPORT FORM command.

The Fox Team also wrote a special ReportListener subclass to help with debugging object assisted reports. This class, DebugListener, is found in the ReportListener.VCX class library in the FFC subdirectory of the VFP home directory. It is very easy to work with. First you instantiate the DebugListener class, and then you pass it to the REPORT FORM command:

loDebugListener = NEWOBJECT("debuglistener", HOME()+"ffc\_reportlistener.vcx")

REPORT FORM AuthorDebugging PREVIEW OBJECT loDebugListener

The DebugListener class records details about how the report is executed and how the various objects are rendered. Along the way it records various property settings during the different stages of report execution. This class will be extremely handy in determining why a report is not functioning as expected. The report isn’t displayed or printed when the DebugListener is the ReportListener hooked into the report. The report is processed, the different properties are recored, and stored in a text file. This text file (see Figure 13) is displayed after the report is finished. You can review the contents of this report to determine how the report was processed from a ReportListener perspective.

Use the Class Browser for PRG-based classes

The Class Browser has always been able to open VCX files, but many developers prefer to write at least some of their classes in program code (PRG). One of the disadvantages of taking the PRG route was the inability to use the Class Browser to maintain the classes and get a visual representation of the class hierarchy. Visual FoxPro 9 removes this limitation.

The base functionality of the Class Browser (see Figure 14) is available for PRG-based classes, although there are a few differences when working with them. The first is the descriptions for the class library (the program in this case) and the descriptions for the individual classes are not available in the description pane (lower left corner). The second is the member descriptions (normally maintained in the lower right pane) cannot be added or edited. The third difference is you cannot filter out empty members in the member pane (upper right pane).

Figure 13. The DebugListener class records numerous property settings and rendering processes as a report is executed. The findings are saved in a text file and displayed when the report is done.

Figure 14. The Class Browser can open a program and display the classes just like it does for VCX class libraries.

Class Browser is dockable

The Class Browser does not dock by default, but because it is a VFP form and VFP forms are dockable, you can write code to dock the Class Browser. This is accomplished by running an add-in for the Activate event.

Text Box: "

The Developer Downloads for this chapter, available from www.hentzenwerke.com, include a program called CBMakeDockableAddin.PRG, which demonstrates how you can create an add-in to dock the Class Browser.

Listing 4. Code that runs to dock the form when the Class Browser is started.

LPARAMETERS toBrowser

 

LOCAL lcName                           && Name of the Add-in

LOCAL lcComment                        && Comment for the Add-in

 

* Self registration if not called form the Class Browser

IF TYPE("toBrowser")= "L"

   lcName    = "Rick Schummer's Make Class Browser Dockable"

   lcComment = "Developed by RAS for online forum discussion and example"

  

   IF TYPE("_oBrowser")= "O"

      * If Class Browser is running, use Addin() method

      _oBrowser.Addin(lcName, STRTRAN(SYS(16),".FXP",".PRG"), "ACTIVATE", ;

                      , , lcComment)

   ELSE

      * Use the low level access of the Browser registration table

      IF FILE(HOME() + "BROWSER.DBF")

         lcOldSelect = SELECT()

 

         USE (HOME() + "BROWSER") IN 0 AGAIN SHARED ;

             ALIAS curRASClassBrowserAddinReg

         SELECT curRASClassBrowserAddinReg

         LOCATE FOR Type = "ADDIN" AND Name = lcName

         

         IF EOF()

           APPEND BLANK

         ENDIF

        

         * Always replace with the latest information

         REPLACE Platform WITH "WINDOWS", ;

                 Type     WITH "ADDIN", ;

                 Id       WITH "METHOD", ;

                 Name     WITH lcName, ;

                 Method   WITH "ACTIVATE", ;

                 Program  WITH LOWER( STRTRAN( SYS(16), ".FXP", ".PRG")), ;

                 Comment  WITH lcComment

         USE

        

         SELECT (lcOldSelect)


      ELSE

         MESSAGEBOX("Could not find the table " + HOME() + ;

                    "BROWSER.DBF" + ", please make sure it exists.", ;

                    0 + 48, ;

                    _screen.Caption)

      ENDIF

   ENDIF

  

   RETURN

ELSE

   * Check to see if we really got called from the Class Browser

   * and it is valid for VFP 9 and higher.

   IF NOT PEMSTATUS(toBrowser, "Dockable", 5)

     RETURN .F.

   ELSE