Help with Attribute Triggers

Hi, I am new to using triggers and I am hoping that I can get help in this forum with the following:

 1. prevent user entries for attribute1 if a certain values of attribute2 (Enumerated) are selected.

 Approach:

 1. Create an attribute trigger that would fire when those certain values for attribute2 are selected.

2. disable (grey out) attribue1 if those values for attribute2 are selected and display a warning message to the user.  

 

I am also not sure where the trigger code needs to be stored for it to fire.

 

Thanks a lot!

 

~ Hanna Yaldo


hyaldo - Tue Jun 11 10:26:39 EDT 2013

Re: Help with Attribute Triggers
llandale - Tue Jun 11 12:43:16 EDT 2013

I think it ill-advised to attempt to adjust access rights dyanamically with any DXL especially triggers.

Understand that a

  • "post" event trigger fires AFTER the event, such as opening  a module.
  • "pre" event trigger fires BEFORE the event, such as opening a module, but also can PREVENT the event by setting a "failed" status.

Notice that a "pre" open module trigger denies you access to the "Module", since it is not yet open.  Ditto for a "post" close module trigger.

In your case I think you want a "pre-attr-save" trigger for Attr1.  Its outline would be:

  • v1 = value of Attr1 that the user is tryiing to set, the "proposed" value
  • v2 = value of Attr2 for this object
  • if (v1 and v2 are compatible)//
  • then allow the event, user change to Attr1 happens
  • else prevent the event; user change to Attr1 is ignored.

Here is some sample trigger code that I think helps:

  •  set(trigPreConPass)   // ALLOW By Default, when there are errors
  •  Trigger trg = current;     if (null trg) halt() // Error?
  •  AttrDef ad  = attrdef(trg); if (null ad)  halt() // Error?
  •  Object  obj = object(trg);  if (null obj) halt() // Error?
  •  Module  mod = module(obj);  if (null mod) halt() // Error?
  •  bool    Dxl = ad.dxl;     if (Dxl)  halt() // Allow Attr DXL modifications
  • string NameProposed = ad.name,   // Attr name being modified
  • if (NameProposed is not the attr I want to protect) then halt()
  • ValuProposed = value(trg),   // Value being proposed
  • if (ValueProposed is illegal) then set(trigPreConFail) //when we want to deny the change.

-Louie

Re: Help with Attribute Triggers
llandale - Tue Jun 11 12:46:29 EDT 2013

Your approach would prevent the user from even trying to modify Attr1.  That is sound but I don't think actually realistic.  My approach lets him try but it fails when he's done.

Years ago I stumbled upon an "in-place-editor" restriction (user cannot edit the attribute), but it didn't stop DXL from changing the value.

-Louie

Re: Help with Attribute Triggers
hyaldo - Tue Jun 11 14:29:07 EDT 2013

llandale - Tue Jun 11 12:46:29 EDT 2013

Your approach would prevent the user from even trying to modify Attr1.  That is sound but I don't think actually realistic.  My approach lets him try but it fails when he's done.

Years ago I stumbled upon an "in-place-editor" restriction (user cannot edit the attribute), but it didn't stop DXL from changing the value.

-Louie

Thank you so much, this is very helpful. I'll give this code a try.

Now my other question was how do you fire the trigger? Where do I need to save the code, is there a specific path where triggers need to be saved? I am using DOORS 9.3.

Thanks a ton!

~ Hanna

 

 

Re: Help with Attribute Triggers
llandale - Tue Jun 11 16:20:07 EDT 2013

hyaldo - Tue Jun 11 14:29:07 EDT 2013

Thank you so much, this is very helpful. I'll give this code a try.

Now my other question was how do you fire the trigger? Where do I need to save the code, is there a specific path where triggers need to be saved? I am using DOORS 9.3.

Thanks a ton!

~ Hanna

 

 

Not sure it appropriate to try to present a course on Triggers.  Triggers are not for the feint of heart.  That includes folks not very comfortable with DXL and folks squeamish about erasing lots of data by mistake and getting fired.  A test database in a safe padded-walled room where nobody can hear you scream is recomended.\

Without a doubt, start off practicing with easy simple benign triggers.

The GUI provided no mechanisms for finding nor deleting triggers.  Search the forums.  Therefore I think it well advised that your "deploy" code also includes a mechanism to "undeploy" the trigger.

There are two separate DXL "programs" associated with Triggers:

  • [1] the trigger code.  This is what runs when the event occurs.
  • [2] the code that deploys and hopefully undeploys the Trigger. You run this on-demand.

The [1] trigger code is often hard coded as a string variable inside the [2] deploy code.  This is easier to config-manage than having the [2] deploy code read a file containing the [1] trigger code, as then there are two files to maintain.  Here is a silly example of that:

  • // Display open baseline version trigger
  • string TrigDXL =                        // *** Trigger code starts on next line   -
  • " int  UnUsed = 0                    
  • Trigger tCurr = current
  •   Module mCurr = module(tCurr, UnUsed)
  • //  if (!null mCurr) infoBox(name(mCurr) \" Visible: \" isVisible(mCurr) \"\")
  •   if (!null mCurr  and isBaseline(mCurr))
  •   {  infoBox(name(mCurr) \" baseline: \" versionString(moduleVersion(mCurr)))
  •   }
  • "     // end string TrigDXL.  ***** Trigger code ends here
  • print TrigDXL "\n"
  • string NameTrig = "openNotice"
  • if (confirm("Remove Trigger '" NameTrig "' ??"))
  •     delete(NameTrig, project->all->module->formal->all, post, open, 10)
  • string ErrorsDXL = checkDXL(TrigDXL)
  • if (!null ErrorsDXL) infoBox("Trigger Errors: " ErrorsDXL)
  • elseif(confirm("Deploy Trigger '" NameTrig "' ??"))
  •     trigger(NameTrig, project->all->module->formal->all, post, open, 10, TrigDXL)

I think that code will display a dialog box every time you open a Baseline.  Pretty sure it would make a terrible permanant trigger.

Things to notice:

  • In order to put a double quote into the string TrigCode, you have to escape it with a backslash.  The "infoBox" line #8 shows that.
  • In order to put a backslah into the string TrigCode, you have to escape it with a backslash. \\.
  • The above two notes makes Triggers dealing with strings hard to read.  printing the code helps immensely.
  • The "delete" and "trigger" statements must have the same parameters, except for the TrigDXL.  Otherwise you end up with a trigger you cannot easily find and delete.
  • the "checkDXL" command at least lets you not deploy trigger code that won't even interpret.

You can write "dynamic" triggers that exist only while the module is open for you on your client.  "dynamic" triggers say they can apply to projects but I think that is no longer true since there is no longer a such thing as "closing a project".  Most "dynamic" triggers are associated with dialog boxes; close the module and the pre-module-close dynamic trigger auto-closes the dialog box as well.  "dynamic" triggers are not stored and there is no way for you to deploy one for some other instance of DOORS.

"Persistent" triggers are stored.  The trigger "scope" determines where the Trigger is stored; which can be a [1] a Module [2] a Project the [3] the Database.  the above trigger has scope starting with "project->all" so it is stored in the Database.  the entire scope above means it applies to all formal modules in the database. 

While there are some database wide triggers, IMO the best place to store a trigger is in the Project.  Such triggers should then get then name of the current module and decide if it really wants to do anything.  However, if you know this trigger will apply only to a single module go ahead and put it in there.

Be mindful of whether the trigger is "post" event or "pre" event.  A post-close-module trigger doesn't make sense since the trigger will fire after the module closes, and the trigger won't be able to figure out which module just closed.  Likewise a pre-open-module trigger.  Generally though a "pre" trigger is used to optionally prevent the event (e.g. pre-attr-save is "Do I want to allow user to make this change?"); a "post" to record the event (e.g. post-attr-save, "If user did this then we need to also do that").

Here are some notes:

  • Nested Projects can cause confusion in scope.
  • Archived/Restored Projects with Triggers usually cause problems ..err.. I mean Problems.
  • Projects containing triggers that are converted to Folders, I think, cause problems.  They are not erased, I don't think they are completely suppressed, and I suspect they are not perfectly restored when the Folder is converted back to a Project.  I destroyed a database once (or more than once), and I think this combined with a Restore was the cause.
  • I can think of no reason at all to attempt to deploy triggers from Attr-DXL or Layouts; and I can think of a host of reasons it would be a disaster.
  • I did come up with a Trigger to deploy another Trigger but that was because I was a twit and had to be "clever".
  • You can prevent triggers from firing by running this dxl: setTriggerState_(false).  This only works for "Database Admins".  This is crutial to find and remove troublesome triggers; such as a post-module-open trigger that closes the module.  Don't laugh, most trigger folks have done that.

-Louie

Re: Help with Attribute Triggers
hyaldo - Tue Jun 11 17:44:31 EDT 2013

llandale - Tue Jun 11 16:20:07 EDT 2013

Not sure it appropriate to try to present a course on Triggers.  Triggers are not for the feint of heart.  That includes folks not very comfortable with DXL and folks squeamish about erasing lots of data by mistake and getting fired.  A test database in a safe padded-walled room where nobody can hear you scream is recomended.\

Without a doubt, start off practicing with easy simple benign triggers.

The GUI provided no mechanisms for finding nor deleting triggers.  Search the forums.  Therefore I think it well advised that your "deploy" code also includes a mechanism to "undeploy" the trigger.

There are two separate DXL "programs" associated with Triggers:

  • [1] the trigger code.  This is what runs when the event occurs.
  • [2] the code that deploys and hopefully undeploys the Trigger. You run this on-demand.

The [1] trigger code is often hard coded as a string variable inside the [2] deploy code.  This is easier to config-manage than having the [2] deploy code read a file containing the [1] trigger code, as then there are two files to maintain.  Here is a silly example of that:

  • // Display open baseline version trigger
  • string TrigDXL =                        // *** Trigger code starts on next line   -
  • " int  UnUsed = 0                    
  • Trigger tCurr = current
  •   Module mCurr = module(tCurr, UnUsed)
  • //  if (!null mCurr) infoBox(name(mCurr) \" Visible: \" isVisible(mCurr) \"\")
  •   if (!null mCurr  and isBaseline(mCurr))
  •   {  infoBox(name(mCurr) \" baseline: \" versionString(moduleVersion(mCurr)))
  •   }
  • "     // end string TrigDXL.  ***** Trigger code ends here
  • print TrigDXL "\n"
  • string NameTrig = "openNotice"
  • if (confirm("Remove Trigger '" NameTrig "' ??"))
  •     delete(NameTrig, project->all->module->formal->all, post, open, 10)
  • string ErrorsDXL = checkDXL(TrigDXL)
  • if (!null ErrorsDXL) infoBox("Trigger Errors: " ErrorsDXL)
  • elseif(confirm("Deploy Trigger '" NameTrig "' ??"))
  •     trigger(NameTrig, project->all->module->formal->all, post, open, 10, TrigDXL)

I think that code will display a dialog box every time you open a Baseline.  Pretty sure it would make a terrible permanant trigger.

Things to notice:

  • In order to put a double quote into the string TrigCode, you have to escape it with a backslash.  The "infoBox" line #8 shows that.
  • In order to put a backslah into the string TrigCode, you have to escape it with a backslash. \\.
  • The above two notes makes Triggers dealing with strings hard to read.  printing the code helps immensely.
  • The "delete" and "trigger" statements must have the same parameters, except for the TrigDXL.  Otherwise you end up with a trigger you cannot easily find and delete.
  • the "checkDXL" command at least lets you not deploy trigger code that won't even interpret.

You can write "dynamic" triggers that exist only while the module is open for you on your client.  "dynamic" triggers say they can apply to projects but I think that is no longer true since there is no longer a such thing as "closing a project".  Most "dynamic" triggers are associated with dialog boxes; close the module and the pre-module-close dynamic trigger auto-closes the dialog box as well.  "dynamic" triggers are not stored and there is no way for you to deploy one for some other instance of DOORS.

"Persistent" triggers are stored.  The trigger "scope" determines where the Trigger is stored; which can be a [1] a Module [2] a Project the [3] the Database.  the above trigger has scope starting with "project->all" so it is stored in the Database.  the entire scope above means it applies to all formal modules in the database. 

While there are some database wide triggers, IMO the best place to store a trigger is in the Project.  Such triggers should then get then name of the current module and decide if it really wants to do anything.  However, if you know this trigger will apply only to a single module go ahead and put it in there.

Be mindful of whether the trigger is "post" event or "pre" event.  A post-close-module trigger doesn't make sense since the trigger will fire after the module closes, and the trigger won't be able to figure out which module just closed.  Likewise a pre-open-module trigger.  Generally though a "pre" trigger is used to optionally prevent the event (e.g. pre-attr-save is "Do I want to allow user to make this change?"); a "post" to record the event (e.g. post-attr-save, "If user did this then we need to also do that").

Here are some notes:

  • Nested Projects can cause confusion in scope.
  • Archived/Restored Projects with Triggers usually cause problems ..err.. I mean Problems.
  • Projects containing triggers that are converted to Folders, I think, cause problems.  They are not erased, I don't think they are completely suppressed, and I suspect they are not perfectly restored when the Folder is converted back to a Project.  I destroyed a database once (or more than once), and I think this combined with a Restore was the cause.
  • I can think of no reason at all to attempt to deploy triggers from Attr-DXL or Layouts; and I can think of a host of reasons it would be a disaster.
  • I did come up with a Trigger to deploy another Trigger but that was because I was a twit and had to be "clever".
  • You can prevent triggers from firing by running this dxl: setTriggerState_(false).  This only works for "Database Admins".  This is crutial to find and remove troublesome triggers; such as a post-module-open trigger that closes the module.  Don't laugh, most trigger folks have done that.

-Louie

I appreciate all the info, this really helps!

~ Hanna

 

Re: Help with Attribute Triggers
sekrbo - Thu Jun 13 05:21:39 EDT 2013

llandale - Tue Jun 11 16:20:07 EDT 2013

Not sure it appropriate to try to present a course on Triggers.  Triggers are not for the feint of heart.  That includes folks not very comfortable with DXL and folks squeamish about erasing lots of data by mistake and getting fired.  A test database in a safe padded-walled room where nobody can hear you scream is recomended.\

Without a doubt, start off practicing with easy simple benign triggers.

The GUI provided no mechanisms for finding nor deleting triggers.  Search the forums.  Therefore I think it well advised that your "deploy" code also includes a mechanism to "undeploy" the trigger.

There are two separate DXL "programs" associated with Triggers:

  • [1] the trigger code.  This is what runs when the event occurs.
  • [2] the code that deploys and hopefully undeploys the Trigger. You run this on-demand.

The [1] trigger code is often hard coded as a string variable inside the [2] deploy code.  This is easier to config-manage than having the [2] deploy code read a file containing the [1] trigger code, as then there are two files to maintain.  Here is a silly example of that:

  • // Display open baseline version trigger
  • string TrigDXL =                        // *** Trigger code starts on next line   -
  • " int  UnUsed = 0                    
  • Trigger tCurr = current
  •   Module mCurr = module(tCurr, UnUsed)
  • //  if (!null mCurr) infoBox(name(mCurr) \" Visible: \" isVisible(mCurr) \"\")
  •   if (!null mCurr  and isBaseline(mCurr))
  •   {  infoBox(name(mCurr) \" baseline: \" versionString(moduleVersion(mCurr)))
  •   }
  • "     // end string TrigDXL.  ***** Trigger code ends here
  • print TrigDXL "\n"
  • string NameTrig = "openNotice"
  • if (confirm("Remove Trigger '" NameTrig "' ??"))
  •     delete(NameTrig, project->all->module->formal->all, post, open, 10)
  • string ErrorsDXL = checkDXL(TrigDXL)
  • if (!null ErrorsDXL) infoBox("Trigger Errors: " ErrorsDXL)
  • elseif(confirm("Deploy Trigger '" NameTrig "' ??"))
  •     trigger(NameTrig, project->all->module->formal->all, post, open, 10, TrigDXL)

I think that code will display a dialog box every time you open a Baseline.  Pretty sure it would make a terrible permanant trigger.

Things to notice:

  • In order to put a double quote into the string TrigCode, you have to escape it with a backslash.  The "infoBox" line #8 shows that.
  • In order to put a backslah into the string TrigCode, you have to escape it with a backslash. \\.
  • The above two notes makes Triggers dealing with strings hard to read.  printing the code helps immensely.
  • The "delete" and "trigger" statements must have the same parameters, except for the TrigDXL.  Otherwise you end up with a trigger you cannot easily find and delete.
  • the "checkDXL" command at least lets you not deploy trigger code that won't even interpret.

You can write "dynamic" triggers that exist only while the module is open for you on your client.  "dynamic" triggers say they can apply to projects but I think that is no longer true since there is no longer a such thing as "closing a project".  Most "dynamic" triggers are associated with dialog boxes; close the module and the pre-module-close dynamic trigger auto-closes the dialog box as well.  "dynamic" triggers are not stored and there is no way for you to deploy one for some other instance of DOORS.

"Persistent" triggers are stored.  The trigger "scope" determines where the Trigger is stored; which can be a [1] a Module [2] a Project the [3] the Database.  the above trigger has scope starting with "project->all" so it is stored in the Database.  the entire scope above means it applies to all formal modules in the database. 

While there are some database wide triggers, IMO the best place to store a trigger is in the Project.  Such triggers should then get then name of the current module and decide if it really wants to do anything.  However, if you know this trigger will apply only to a single module go ahead and put it in there.

Be mindful of whether the trigger is "post" event or "pre" event.  A post-close-module trigger doesn't make sense since the trigger will fire after the module closes, and the trigger won't be able to figure out which module just closed.  Likewise a pre-open-module trigger.  Generally though a "pre" trigger is used to optionally prevent the event (e.g. pre-attr-save is "Do I want to allow user to make this change?"); a "post" to record the event (e.g. post-attr-save, "If user did this then we need to also do that").

Here are some notes:

  • Nested Projects can cause confusion in scope.
  • Archived/Restored Projects with Triggers usually cause problems ..err.. I mean Problems.
  • Projects containing triggers that are converted to Folders, I think, cause problems.  They are not erased, I don't think they are completely suppressed, and I suspect they are not perfectly restored when the Folder is converted back to a Project.  I destroyed a database once (or more than once), and I think this combined with a Restore was the cause.
  • I can think of no reason at all to attempt to deploy triggers from Attr-DXL or Layouts; and I can think of a host of reasons it would be a disaster.
  • I did come up with a Trigger to deploy another Trigger but that was because I was a twit and had to be "clever".
  • You can prevent triggers from firing by running this dxl: setTriggerState_(false).  This only works for "Database Admins".  This is crutial to find and remove troublesome triggers; such as a post-module-open trigger that closes the module.  Don't laugh, most trigger folks have done that.

-Louie

Another way to get past the triggers is by adding the command-line switch "-notriggers" or "-T" to the client, if you are a database manager.

Also note that if you are using Web Access, DWA runns without any triggers! So there will be no limitations on the attribute if you modify it in DWA, which will be a problem if you want to implement some kind of workflow rules using triggers AND want to be able to use DWA to modify the content!

/sekrbo

Re: Help with Attribute Triggers
llandale - Fri Jun 14 16:56:02 EDT 2013

sekrbo - Thu Jun 13 05:21:39 EDT 2013

Another way to get past the triggers is by adding the command-line switch "-notriggers" or "-T" to the client, if you are a database manager.

Also note that if you are using Web Access, DWA runns without any triggers! So there will be no limitations on the attribute if you modify it in DWA, which will be a problem if you want to implement some kind of workflow rules using triggers AND want to be able to use DWA to modify the content!

/sekrbo

As for the trigger setting: the setting is turned off and on for all users, but forStandard users the setting is ignored and Triggers fire.  I tend to write trigger code to check the setting, and if triggers are turned off then my trigger does nothing.  Or in other cases it does something else.  And I hope my users don't catch on about that.

-Louie