RuleManager ABC Template Implementation

Top  Previous  Next

 

Three templates support the use of the Rule Manager classes. They are:

The Global Business Rules Manager, which establishes logical connections between business rules and particular table columns, other fields, and controls.

The Local Business Rules Manager, which implements global rules wherever relevant items are populated and allows for the addition of local rules having effect in only one procedure. The Local Business Rules Manager is automatically added to every procedure in any application which contains the Global Business Rules Manager.

A code template, the Error Handler for Business Rules, which provides enhanced functionality where needed.

 

RuleManager Source Files

 

The Rule Manager Classes source code is installed by default to the Clarion \LIBSRC folder. The Rule Manager source code and its respective components are contained in:

ABRULE.INC

Rule Manager Class declarations

ABRULE.CLW

Rule Manager Class method definitions

 

RuleManager Conceptual Example

 

The following example shows a typical sequence of statements to declare, instantiate, initialize, use and terminate a RulesCollection and related Rule objects in a standard ABC Window procedure. This example defines several rules and checks them at critical points. Each rule is bound to a specific control (this is optional) and when the rule is checked and found to be broken, a graphic error indicator is displayed next to the associated control. The OK button is disabled when there are broken rules.

 

Example:

 

  MEMBER('app.clw')             ! This is a MEMBER module

 

 INCLUDE('ABRULES.INC'),ONCE

 

 INCLUDE('ABTOOLBA.INC'),ONCE

 INCLUDE('ABWINDOW.INC'),ONCE

 

 MAP

  INCLUDE('APP001.INC'),ONCE     !Local module procedure declarations

 END

 

 

Main PROCEDURE                    !Generated from procedure template - Window

 

CusName              STRING(20)

CusAddress           STRING(20)

CusPhone             STRING(10)

CustomerRules &RuleManager        !Rule manager for Rules for the customer

Window WINDOW('Example of using RulesManager'),AT(,,169,124), FONT(,,,,CHARSET:ANSI),|

      GRAY,DOUBLE

       SHEET,AT(3,4,159,116),USE(?Sheet1)

        TAB('Customer Info'),USE(?Tab1)

         SHEET,AT(8,26,149,62),USE(?Sheet2)

          TAB('Name'),USE(?Tab3)

           ENTRY(@s20),AT(51,55,60,10),USE(CusName),IMM

           PROMPT('Cus Name:'),AT(13,55),USE(?CusName:Prompt)

          END

          TAB('Address'),USE(?Tab4)

           PROMPT('Cus Address:'),AT(12,53),USE(?CusAddress:Prompt)

           ENTRY(@s20),AT(69,53,60,10),USE(CusAddress),IMM

          END

          TAB('Phone'),USE(?Tab5)

           PROMPT('Cus Phone:'),AT(12,52),USE(?CusPhone:Prompt)

           ENTRY(@s10),AT(69,50,60,10),USE(CusPhone),IMM

          END

         END

        BUTTON('OK'),AT(118,96,32,14),USE(?Button:OK),STD(STD:Close)

        BUTTON('View Customer Broken Rules'),AT(8,95,101,14),USE(?Button:ListAll)

       END

      END

     END

 

ThisWindow           CLASS(WindowManager)

Init                   PROCEDURE(),BYTE,PROC,DERIVED

Kill                   PROCEDURE(),BYTE,PROC,DERIVED

TakeAccepted           PROCEDURE(),BYTE,PROC,DERIVED

TakeFieldEvent         PROCEDURE(),BYTE,PROC,DERIVED

TakeNewSelection       PROCEDURE(),BYTE,PROC,DERIVED

                    END

 

Toolbar              ToolbarClass

 

 CODE

 GlobalResponse = ThisWindow.Run()

 

 

ThisWindow.Init PROCEDURE

 

ReturnValue          BYTE,AUTO

 

 CODE

 GlobalErrors.SetProcedureName('Main')

 SELF.Request = GlobalRequest

 ReturnValue = PARENT.Init()

 

 !Bind the variables used by RulesManager

 BIND('CusName',CusName)                             !RulesManager Hotfield

 BIND('CusAddress',CusAddress)                       !RulesManager Hotfield

 BIND('CusPhone',CusPhone)                           !RulesManager Hotfield

 

 !Define RulesManager

 CustomerRules &= New(RuleManager)

 CustomerRules.SetErrorImage('~SMCROSS.ICO')

 CustomerRules.SetDescription('Rules for the customer')

 

 !Defining rules in RulesManager

 CustomerRules.AddRule|

 ('CusNameReq','Customer name is required','len(clip(CusName))>0',?CusName,3)

 CustomerRules.AddRule|

 ('Addreq','Customer address is required','len(Clip(CusAddress))',?CusAddress,3)

 CustomerRules.AddRule('PhoneReq','Phone is required','Len(Clip(CusPhone))>0',?CusPhone,3)

 

 IF ReturnValue THEN RETURN ReturnValue.

 SELF.FirstField = ?CusName

 SELF.VCRRequest &= VCRRequest

 SELF.Errors &= GlobalErrors

 SELF.AddItem(Toolbar)

 CLEAR(GlobalRequest)

 CLEAR(GlobalResponse)

 OPEN(Window)

 SELF.Opened=True

 !Check all Rules in RulesManager and show error indicators

 CustomerRules.CheckAllRules(1)                    

 

 SELF.SetAlerts()

 RETURN ReturnValue

 

 

ThisWindow.Kill PROCEDURE

 

ReturnValue          BYTE,AUTO

 

 CODE

 ReturnValue = PARENT.Kill()

 IF ReturnValue THEN RETURN ReturnValue.

 GlobalErrors.SetProcedureName

 

 !UnBind the variables used by RulesManager

 UNBIND('CusName')                                   !RulesManager Hotfield

 UNBIND('CusAddress')                                !RulesManager Hotfield

 UNBIND('CusPhone')                                  !RulesManager Hotfield

 Dispose(CustomerRules)

 

 RETURN ReturnValue

 

 

ThisWindow.TakeAccepted PROCEDURE

 

ReturnValue          BYTE,AUTO

 

Looped BYTE

 CODE

 !Pass the Accepted control to RulesManager for processing in case

 !the control clicked was an error indicator. If it was an error indicator,

 !a MessageBox containing the description of the broken rule will be displayed

 CustomerRules.TakeAccepted(Accepted())            

 LOOP

   IF Looped

     RETURN Level:Notify

   ELSE

     Looped = 1

   END

 ReturnValue = PARENT.TakeAccepted()

   CASE ACCEPTED()

 

   OF ?Button:ListAll

    ThisWindow.Update

 

!This will Cause a window to popup that contains a list of all broken rules, and if

!the user double clicked one of the rules in the list, the relevant control will be selected.

 

Select(CustomerRules.EnumerateBrokenRules|

(CustomerRules.GetDescription(),CustomerRules.GetErrorImage()))

 

   END

   RETURN ReturnValue

 END

 ReturnValue = Level:Fatal

 RETURN ReturnValue

 

ThisWindow.TakeFieldEvent PROCEDURE

 

ReturnValue          BYTE,AUTO

 

Looped BYTE

 CODE

 LOOP

   IF Looped

     RETURN Level:Notify

   ELSE

     Looped = 1

   END

 

   !Disable the save button if there are any broken rules

   ?Button:OK{Prop:Disable} = CustomerRules.BrokenRuleCount()

 

   !Hide the ListAll button if there are no broken rules

   ?Button:ListAll{Prop:Hide} = Choose(CustomerRules.BrokenRuleCount() = 0)

 

   ReturnValue = PARENT.TakeFieldEvent()

   RETURN ReturnValue

 END

 ReturnValue = Level:Fatal

 RETURN ReturnValue

 

 

ThisWindow.TakeNewSelection PROCEDURE

 

ReturnValue          BYTE,AUTO

 

Looped BYTE

 CODE

 LOOP

   IF Looped

     RETURN Level:Notify

   ELSE

     Looped = 1

   END

   ReturnValue = PARENT.TakeNewSelection()

   CASE FIELD()

 

   OF ?CusName

     UPDATE

     CustomerRules.CheckRule('CusNameReq',1)    !Checking for broken rule in RulesManager

 

   OF ?CusAddress

     UPDATE

     CustomerRules.CheckRule('AddReq',1)        !Checking for broken rule in RulesManager

 

   OF ?CusPhone

     UPDATE

     CustomerRules.CheckRule('PhoneReq',1)      !Checking for broken rule in RulesManager

 

   END

   RETURN ReturnValue

 END

 ReturnValue = Level:Fatal

 RETURN ReturnValue

 

 

Implementation Steps using hand code

 

Although there is a powerful template that is included with Clarion to help you implement the RuleManager, there are times when you may need to hand code its properties and methods into your source. The following are the recommend steps to implementing the RuleManager in your hand coded projects.

 

1. Identify specific rules and assign each rule a name. For example, if Cus:Name is required, call it CusNameReq.

 

2. For each rule, write a line of code that returns the value of TRUE when the rule is unbroken. For example, if Cus:Name is required, the corresponding code will be:

 

LEN(Clip(Cus:Name)) > 0

 

If Cus:Address is required if Cus:Name <> "Unknown", the corresponding code will be

 

Choose(Upper(Clip(Cus:Name))<<>''UNKNOWN'' and len(Clip(Cus:Address))=0,0,1)

 

3. Bind all of the variables used in each expression.

 

BIND('Cus:Name',Cus:Name)

BIND('Cus:Address',Cus:Address)

 

4. Define a RuleManager Object.

 

CustomerRules &RuleManager

 

5. Instantiate the RuleManager Object

 

CustomerRules &= New(RuleManager)

CustomerRules.SetErrorImage('~SMCROSS.ICO')

CustomerRules.SetDescription('Rules for the customer')

 

6. Define the rules for the RulesManager

 

CustomerRules.AddRule('CusNameReq','Customer name is required' ,|

'len(clip(CusName))>0',?CusName,3)

!A small button with the icon SMCROSS.ICO' will be displayed 3 pixels to the left of !?CusName when the expression evaluates to false

 

CustomerRules.AddRule|

('Addreq','Customer address is required if customer name is not "Unknown"',|

'Choose(Upper(Clip(CusName))<<>''UNKNOWN'' and | len(Clip(CusAddress))=0,0,1)',?CusAddress,3)

!A small button with the icon SMCROSS.ICO' will be displayed 3 pixels to the left of !?CusAddress when the expression evaluates to false

 

7. Check the rules.

 

CustomerRules.CheckAllRules(1)  !Checks all the rules

CustomerRules.CheckRule('CusNameReq',1) !Checks specific rule

 

8. Trap a mouseclick on the error indicator button.

 

CustomerRules.TakeAccepted(Accepted())

!If a description is provided with the corresponding error, a message !with the corresponding error will appear

 

9. Count the Broken Rules.

 

?OK{Prop:Disable} = CustomerRules.BrokenRuleCount()

!The ?OK button is disabled when there are broken rules

 

10. View All Broken Rules.

 

Select(CustomerRules.EnumerateBrokenRules|

(CustomerRules.GetDescription(),CustomerRules.GetErrorImage()))

!Call a popup listbox of broken rules, and use the default RulesManager icon as an icon. !If the user double clicks one of the broken rules, the corresponding control will be !selected.