February 14, 1995Defined in Rule.Def Inherits from Object
Magic Cap rules allow a user to customize the behavior of objects in the system. For example, the in box has rules that describe actions that can be taken when mail is received. The in box also has rules that can collect mail at certain times of day. Some of the rules play sounds when certain kinds of mail arrive. Other rules control how the user interacts with the mail service.
Some rules can be customized. All rules can be enabled and disabled.
Remember that if the documentation and the software (especially the definition files) disagree, always trust the software.
For each rule you create, you'll need instances of classes RuleTemplate, RuleAction or LocalRuleAction, and RuleQualifier or LocalRuleQualifier. This chapter gives you the basic information on using objects of each of these classes. For detailed information on each class, see its chapter.
Class Rule has two subclasses that help you create specialized rules: class ConditionalRule and class ScheduledRule.
Use class ConditionalRule when your rule is meaningful only in certain circumstances. Conditional rules are rules that appear only when a condition condition applies. This condition must be met before the system will display the rule in the RuleView window.
Use class ScheduledRule to perform actions at certain times. This subclass has additional fields for ScheduledTime and TimedEvent objects.
Instantiate: sometimes Subclass: rarely Call its methods: sometimes
You'll probably never create a rule programmatically. Instead, you'll put rule objects and the required ancillary objects into place in your object definition files. The next sections of this chapter describe how you can create rules, install them into your package, and hook them up to system actions.
To add a set of rules to your package, use the rules field of your scene additions object. Here's an example of a scene additions object that includes rules:
Instance SceneAdditions 12; commands: nilObject; rules: (ObjectList "My Rule Lists" 14); tools: nilObject; stamps: nilObject; stampBankNames: nilObject; stampBankContents: nilObject; End Instance;
For more information on scene additions, see the chapter on class SceneAddition.
You should include two lists of rules in your scene additions. The first list is the set of rules available to users who aren't in construction mode. The second list is the set of rules available to users who've turned on construction mode. The "My Rule Lists" list would contain two other lists, like this:
Instance ObjectList "My Rule Lists" 14; length: 2; entry1: (DenseObjectList 15); // Standard mode rules entry2: (DenseObjectList 16); // Authoring mode rules End Instance;
These two lists of rules must be dense object lists. They almost always have several rules in common. The construction mode list usually adds some rules tailored for expert users. Here are two sample lists:
Instance DenseObjectList 15; //normal mode list length: 4; entry1: (Rule 17); entry2: (Rule 30); entry3: (ConditionalRule 40); entry4: (ScheduledRule 54); End Instance; Instance DenseObjectList 16; //authoring mode list length: 5; entry1: (Rule 17); entry2: (Rule 30); entry3: (ConditionalRule 40); entry4: (ScheduledRule 54); entry5: (Rule `Expert Feature' 64); End Instance;
In order for your rules to have an effect, you must usually trigger them in the appropriate circumstances. (Some rules take effect when the user enables them, and do nothing otherwise. Those rules don't need to be triggered.) To trigger your rules, you use a trigger object.
Trigger objects contain a list of rules that should be invoked when PostTrigger is called. Rules that appear in this list should point their ruleTrigger field back to the Trigger object that contains them. Do this so that when the user makes a copy of the rule, the new copy can be added to the correct Trigger.
Use trigger lists to invoke rules. Don't invoke rules directly. If you invoke rules without using trigger lists, you won't reap the benefits of the rule framework. If your users make copies of your rules, the copies won't ever be invoked.
Trigger lists are just object lists. The entries in the list should be the rules you want to take effect when this trigger is "pulled." For convenience, you might want to make package indexicals for your trigger list objects.
Here's an example of a trigger object:
Instance Trigger 16; // iNewCardInOutboxTrigger length: 2; entry: (Rule 17); entry: (Rule 30); End Instance;
When a new card arrives in the outbox, the rules in this trigger list should be triggered in the order they appear in this list. Order sometimes matters! It's your responsibility to trigger your new rules in your code. You can take advantage of triggers the system posts by adding your rules to existing trigger lists. (Sometimes you have to post even those triggers yourself. For example, anybody who puts a card into the out box is responsible for posting the out box trigger.) See the the section onSystem Triggers later in this chapter for a list of trigger indexicals defined by Magic Cap.
Version note: Class Trigger is a small class. It inherits its interface from class ObjectList. It defines just one method of its own, the PostTrigger method. This version of this document omits complete documentation of class Trigger.
If you're triggering your rules yourself, call PostTrigger on the trigger list. To use the trigger list in the example, your code would look like this:
PostTrigger(iNewCardInOutboxTrigger, newCard);
PostTrigger calls InvokeRule on each rule in the trigger list. Each rule therefore has a chance to decide if it applies to the new card in the outbox. Rules that have qualifiers call QualifyRule as part of their decision process. In the out box example, QualifyRule would be called like this:
qualified = QualifyRule(qualifier, newCard, rule);
QualifyRule returns true if a rule qualifies and false if it doesn't. If a rule decides it applies, it calls PerformRule on its action, like this:
PerformRule(action, newCard, rule);
You don't have to call QualifyRule and PerformRule yourself; they're called by the rules framework.
Class Rule defines the following methods:
Method | Description |
---|---|
CopyData | Copy information from one rule to another; called by system when rules are copied |
ControlList | Get the template's control list, if this rule has a template |
InvokeRule | Perform the rule's action if the rule passes its qualification test |
UpdateText | Update the rule's text description using the rule template, if the rule has a template |
Finalize | Overridden to remove the rule from its trigger list |
ConditionPasses | Return true; subclass ConditionalRule overrides this method to impose a condition on the rule |
Class Rule defines the following attributes:
Attribute | Type | Description |
---|---|---|
CanCopy | Boolean | Test whether this rule can be copied by the user |
CanDelete | Boolean | Test whether object can be thrown away |
Description | Object | The getter and setter for the description field |
Enabled | Boolean | Test whether rule is currently in force |
RuleAction | RuleAction | The getter and setter for the RuleAction field |
RuleQualifier | RuleQualifier | The getter and setter for the RuleQualifier field |
Class Rule defines the following fields:
Field | Type | Description |
---|---|---|
ruleFlags | Unsigned | Flags that control various aspects of rule behavior |
ruleTemplate | Object | An object containing the generic rule text and the controls to edit the rule |
ruleTrigger | Object | The trigger object that lists this rule |
description | Object | The text description of the rule, as displayed to the user |
ruleAction | RuleAction | Action to perform when the rule is enabled |
ruleQualifier | RuleQualifier | An extra condition that must be met before a rule action is performed |
The ruleFlags describe how the rule responds to user actions, among other things. See the section on rule flags later in the chapter for a list of available flags.
The other fields are described in detail in the sections immediately following this one.
Rules have three major components: a description, an action, and a qualifier. Editable rules have an additional template component.
The rule's description is the text the user sees in the rule view window. You'll use a text object to contain the description.
The RuleAction is the action the rule performs. The rule action object specifies the type of the action, the object to act on, and the operation to call on that object. See the chapter on class LocalRuleAction for details on creating the common action types.
The RuleQualifier specifies a condition that must be met before the action will be taken. See the chapter on class LocalRuleQualifier for details on creating the common qualifier objects.
The next sections give you examples of each of these pieces and show you how to construct rules from them.
Simple rules aren't editable. The user just taps their text to turn them on and off. These rules are the easiest to construct. To make simple rules, you need only four pieces:
You don't need rule templates for simple rules, since templates describe how rules are edited.
Here's the rule that sends everything in the outbox as soon as the outbox contains an urgent message:
Instance Rule 17; ruleFlags: 0x40400000; ruleTemplate: nilObject; ruleTrigger: iNewCardInOutboxTrigger; description: (Text 18); ruleAction: (LocalRuleAction 19); ruleQualifier: (LocalRuleQualifier 20); End Instance; Instance Text 18; text: 'Send everything in the out box as soon \ as it contains an urgent message.'; End Instance; Instance LocalRuleAction 19; actionType: 7; // actionDoOperation actionObject: iOutBoxStack; actionData: operation_AddToSendQueue; End Instance; Instance LocalRuleQualifier 20; qualifierType: 2; // qualifyMailAttribute qualifierObject: (MailAttribute 'urgent' 3651); qualifierData: 0; End Instance;
The rule trigger is the trigger that's posted when a new card is put in the outbox. (Anybody who puts a card in the out box is responsible for calling PostTrigger on the trigger list.) If the rule is enabled, it's checked to see if it meets its qualifier condition. The qualifier object for this rule checks the card's mail attributes. In this case, the card is checked to see if it's urgent. If the card is urgent, it's added to the send queue and immediately mailed.
Editable rules have one, two, or three pieces that can be customized by the user. For example, they might play a sound chosen by the user when a certain action takes place. You can edit these pieces of your rule:
The rule template tells the system how to use controls to edit your rule and how to construct a text object that describes the current state of your rule.
To make editable rules, you need
Here's the rule that sends everything in the out box as soon as it contains a certain number of messages:
Instance Rule 30; ruleFlags: 0x40400000; ruleTemplate: (RuleTemplate 31); ruleTrigger: iNewCardInOutboxTrigger; description: (Text 32); ruleAction: (LocalRuleAction 35); ruleQualifier: (LocalRuleQualifier 37); End Instance; Instance RuleTemplate 31; ruleFlags: 0x80000000; ruleTemplate: nilObject; ruleTrigger: nilObject; description: (Text 33); ruleAction: nilObject; ruleQualifier: nilObject; controlList: (ObjectList 34); mapping: (TextMapping 38); numQualifierControls: 0; End Instance; Instance Text 32; // the complete rule text text: 'Send everything in the out box as soon as it contains at least 1 item(s).'; End Instance; Instance Text 33; // template text text: 'Send everything in the out box as soon as it contains at least /number/ item(s).'; End Instance; Instance ObjectList 34; // template controls length: 1; entry: (Meter 'number of items' 36); End Instance; Instance LocalRuleAction 35; actionType: 7; actionObject: iOutBoxStack; actionData: operation_AddToSendQueue; End Instance; Instance Meter 'number of items' 36; // meter definition goes here (elided for brevity) End Instance; Instance LocalRuleQualifier 37; qualifierType: 7; qualifierObject: iOutBoxStack; qualifierData: 1; End Instance;
The description field contains a text object holding the text the user sees when the Rule icon in the magic lamp window is tapped. For Rule objects, this will be the specific text for the rule. In the example, this text is "Send everything in the out box as soon as it contains at least 1 item(s)." The text field of a RuleTemplate object contains the more generic description of the rule, used with the text mapping object. In the example, this text is "Send everything in the out box as soon as it contains at least /number/ item(s)." The chapter on class RuleTemplate describes text mappings in detail.
Your template's control list should list one control for every aspect of the rule that can be changed. You should also have one text mapping piece for every editable aspect.
For a complete description of rule templates, see the chapter on class RuleTemplate.
You might want to add your rule to one of the system trigger lists instead of using your own trigger list. The system defines these indexicals for its trigger lists:
Trigger | When triggered |
---|---|
iMessageArrivedTrigger | A new card arrives in the inbox (for example, would trigger rules that play sounds, file automatically, or delete automatically) |
iMessageSentTrigger | A message is sent |
iTaskAlarmTrigger | A task alarm goes off (usually triggers rules that control how the alarm is signalled to the user) |
iIncomingCallTrigger | The phone rings |
iPhoneLineConnectedTrigger | The user has plugged a phone line into the Magic Cap device |
iEmptyTrashTrigger | The trash is emptied (only pulled if an object was actually deleted) |
iNewCardInOutboxTrigger | A new card has just been put into the outbox (often triggers rules that decide when to send the contents of the outbox) |
iPurgeFileCabinetTrigger | The File Cabinet has items more than a week old (used to prompt the user to delete the old items) |
iPurgeDatebookTrigger | The Datebook has items more than a week old (used to prompt the user to delete the old items) |
iPurgePhoneLogTrigger | The Phone Log has items more than a week old (used to prompt the user to delete the old items. |
Add your own rule to one of these trigger lists the same way you add any object to an object list: with a call to AddTo. Your call might look like this:
AddTo(iEmptyTrashTrigger, myTrashRule);
Remember that order matters. It would matter particularly for this trigger. Your rule might only get its chance to act after other trash rules have deleted the trigger object!
Class Rule defines a number of flags you can set in your rule's ruleFlags field. This section describes those flags.
#define isTemplateMask 0x80000000
This flag is reserved by the system. Please don't use it.
#define isEnabledMask 0x40000000
The system sets this flag for rules that are enabled. Set this flag if you want your rule to be enabled by default.
The Enabled and SetEnabled methods check and set this flag. The InvokeRule method checks this flag, and only performs the rule's action if it's set. Many other methods also check this flag.
#define actionOnTapMask 0x20000000
Set this flag if you'd like your rule's action to take place when the user taps your rule in the rule view. You'd set this flag for rules that are customization options. For example, the rule in the datebook that shows the moon phases in the monthly calendar sets this flag. The moons should be shown or hidden at the same time the user enables or disables the rule. Another example is the rule that turns daylight savings time on. This rule should take effect (and change the time) when the user enables it.
#define hasAttributeMask 0x10000000
Set this flag for rules that use the action type actionSetAttribute. This flag is checked by UpdateEnabled when it's updating rules that might have changed outside the rules interface.
#define sceneAttributeMask 0x08000000
Set this flag to change the way the action type actionSetAttribute works. If this flag is set, the rule's action will set an attribute of the current scene to the value of your rule's action object. If this flag isn't set, the action sets an attribute of the action object to the value of the action data. For details, see the description of the actionSetAttribute action type in the chapter on class LocalRuleAction.
#define isDirtyMask 0x04000000
The system sets the isDirty flag for cloud rules the user has changed. Rules that set this flag will be included in the next message informing the cloud of changes to cloud rules. You shouldn't set this flag for your rules.
#define isCloudMask 0x02000000
Set this flag if your rule is a cloud rule; that is, if your rule is the Magic Cap interface to a rule that affects the user's account in a Telescript mail service. You won't need this flag unless you're a Telescript developer.
#define intrinsicUseActionObjMask 0x01000000
Set this flag to change the way the action type actionDoIntrinsicOperation works. If this flag is set, the system passes the action object to IntrinsicByNumber. If this flag isn't set, the system passes the trigger data. For details, see the description of the actionDoIntrinsicOperation action type in the chapter on class LocalRuleAction.
#define performWhenChangedMask 0x00800000
Set this flag if your rule action should be performed when the rule is changed by the user. If this flag is set, the system will call PerformRule when the user taps the accept button after changing the rule.
#define ruleNoCopyMask 0x00400000 #define ruleNoCopyBit 22
Set this flag for rules that you don't want the user to copy.
The CanCopy and SetCanCopy methods check and set this flag. RuleView_SetEditMode hides the rule view's copy button if the current rule can't be copied.
#define ruleInitiallyEnabledMask 0x00200000
The system keeps track of which rules were intially enabled using this flag. Please don't set it yourself.
#define ruleNoTextUpdateMask 0x00100000
This rule is set for certain cloud rules. If this flag isn't set, class RuleView will call UpdateText on a rule when displaying the rule. Don't set this flag unless you're writing a cloud rule.
#define ruleCanDeleteMask 0x00080000 #define ruleCanDeleteBit 19
Set this flag if your rule can be deleted by the user. The CanDelete and SetCanDelete methods check and set this flag.
#define ruleActionOnConditionListMask 0x00080000
This flag is reserved by the system. Please don't set it.
operation InvokeRule(triggerData: Unsigned) Call: sometimes Override: rarely
The system calls InvokeRule on each rule in a trigger list when PostTrigger is called on the list. InvokeRule performs the rule's action if the rule passes its qualifier test.
If the rule doesn't have a qualifier, the rule automatically qualifies. Otherwise, InvokeRule calls QualifyRule to check if the rule meets its qualification. If the rule qualifies, InvokeRule calls PerformRule like this:
PerformRule(Field(self, ruleAction), triggerData, self);
operation ConditionPasses(): Boolean; Call: rarely Override: rarely
The RuleView class calls ConditionPasses from its FilterConditionalRules method. If the rule's condition passes, the rule view includes the rule in its display list. Otherwise, the rule doesn't appear.
Rule_ConditionPasses returns true by default. Class ConditionalRule overrides this method to pass along the ConditionPasses call to the rule's condition. For more information on conditional rules, see the section on Related Classes earlier in this chapter.
operation UpdateText() Call: rarely Override: rarely
The system calls UpdateText when the user has edited the rule or when it changes the rule programmatically. UpdateText creates a current text description for editable rules, which have descriptions that might change. UpdateText does nothing if the rule doesn't have a template or a text mapping.
If the rule does have a template and a text mapping, UpdateText calls ComputeRuleText on both the rule's qualifier object and its action object, to give both a chance to map text appropriately. See the description of text mappings in the chapter on class RuleTemplate for details on how the text description is created.