| **Navigation:**  [[abc library reference.htm|ABC Library Reference]] > RuleManager >====== RuleManager ABC Template Implementation ====== | [[rulemanager concepts.htm|{{btn_prev_n.gif|Previous page}}]][[abc library reference.htm|{{btn_home_n.gif|Return to chapter overview}}]][[rule class properties.htm|{{btn_next_n.gif|Next page}}]] | | || 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.**