Topic
IC4NOTICE: developerWorks Community will be offline May 29-30, 2015 while we upgrade to the latest version of IBM Connections. For more information, read our upgrade FAQ.
24 replies Latest Post - ‏2012-12-11T19:21:50Z by llandale
homer_3
homer_3
11 Posts
ACCEPTED ANSWER

Pinned topic Triggers

‏2011-02-06T17:06:43Z |
Am I missing something, or is the only way to create triggers is by a DXL script? If that's the case, ok. But I can't find documentation of any other way to create a trigger. There also doesn't seem to be any way of managing persistent triggers. You'd think there'd be an option from one of the drop down menus on a module that told you what triggers were attached to the current module. Do I have to write a script to do my own trigger management as well?
Updated on 2012-12-11T19:21:50Z at 2012-12-11T19:21:50Z by llandale
  • SystemAdmin
    SystemAdmin
    3180 Posts
    ACCEPTED ANSWER

    Re: Triggers

    ‏2011-02-06T21:30:00Z  in response to homer_3

    ...Am I missing something... - No

    ...or is the only way to create triggers is by a DXL script... - Yep

    It's crazy but it's true, DOORS does not provide any client GUI level assistance with triggers, they have to be created and managed via DXL. Triggers can remain hidden and forgotten about resulting in contention & performance problems as triggers pile up and potentially conflict eachother.

    There are some folk on this forum who have some great experience with triggers - I recall seeing a nifty DXL dialogue box that someone developed to help to see a listing of what triggers were active - I think it was Peter Albert - may have been Louie Landale - my brain hurts and can't recall who it was, but I'm sure these guys will respond.

    My DXL contribution below is a simple example that lists what triggers are active against formal modules within a project. A note of caution - if you're using the "DOORS Analyst" add-on, special triggers are added by this feature to maintain synchronisation between DOORS and the UML graphical editor, don't delete these, it will break this feature.

     

     

    Module m
    Trigger t = null 
    Item i
    string itemType
    string modName, fullModName
     
    for i in current Project do
        {
     
            itemType = type i
     
            if( itemType == "Formal")
                    {
     
                    fullModName = fullName(i)
                    modName = name(i)
                    
                    m = read(fullModName,false)
                    for t in m do { 
                            print path(i) "/" modName " : " name t "\n" 
                            } 
                    close(m)
                    }
            }
    

     

     

     

     


    Paul Miller
    Melbourne, Australia

     

     

    Updated on 2013-12-20T20:04:42Z at 2013-12-20T20:04:42Z by JAntley
  • homer_3
    homer_3
    11 Posts
    ACCEPTED ANSWER

    Re: Triggers

    ‏2011-02-07T06:34:21Z  in response to homer_3
    Thanks. Odd that there's no built in way to manage triggers.
    • Peter_Albert
      Peter_Albert
      250 Posts
      ACCEPTED ANSWER

      Re: Triggers

      ‏2011-02-07T08:38:38Z  in response to homer_3
      Attached is the script for the little trigger info dialogue box mentioned above.

      Regards,

      Peter
      • Peter_Albert
        Peter_Albert
        250 Posts
        ACCEPTED ANSWER

        Re: Triggers

        ‏2011-02-07T08:42:21Z  in response to Peter_Albert

        Can somebody please tell me why attaching files never works for me? Here is the code

        // Show / delete all triggers
        /*
        This script display a simple dialogue box with information about
        dynamic and persistent triggers in the current module, project and database
        
        
        "List triggers"  : Re-create the list of triggers
        "Delete triggers": Button: For each trigger found, displays a 
                           Yes/No/Cancel dialogue for trigger deletion
        "Delete triggers": Text field: Copy / paste the name of one trigger and hit
                           <Return> to delete this trigger
        */
        DB           baseDB
        DBE          infoDBE
        const int    TEXT_WIDTH  = 200
        const int    TEXT_HEIGHT = 300
        const int    FIELD_WIDTH = 20
        Buffer       disp        = create
        Skip         triggerList = createString()
        DBE          deleteDBE   = null
        const string options[]   = {"Yes", "No", "Cancel"}
        // ----------------------------------------------------------------------
        void triggerInfo(Trigger t, bool deleteIt, &exitLoop)
        {
          if (null t){disp += "\n null trigger!\n"; return}
          if (kind(t) == "builtin"){return}
          if (!put(triggerList, name(t) "", t)){return}
          disp += "\n"
          disp += "Name: " name(t) "\n"
          disp += "Kind: " kind(t) "\n"
          disp += "DXL: " dxl(t) "\n"
          disp += "Level: " stringOf(level(t)) "\n"
          disp += "Type: " stringOf(type(t)) "\n"
          disp += "Event: " stringOf(event(t)) "\n"
          disp += "Stored in: " stored(t) "\n"
          Module m = module t
          int queryResult
          if (!null m){disp += "Module: " fullName(m) "\n"}
          if (deleteIt)
          {
            queryResult = query("Delete Trigger " (name t) "?", options)
            if (queryResult == 0)
            {
              string del = delete(t)
              disp += "Deleted: " del "\n"
            }
            else if (queryResult == 2){exitLoop = true}
          }
        }
        // ----------------------------------------------------------------------
        void triggerList(bool deleteIt)
        {
          bool exitLoop = false
          delete triggerList; triggerList = createString()
          Trigger t
          disp = "{\\b Module}"
          Module m = current
          if (!null m)
          {
            disp += ": " name(m) ""
            for t in m do 
            {
              if (exitLoop){continue}
              triggerInfo(t, deleteIt, exitLoop)
            }
          }
          else {disp += ": no current module"}
          disp += "\n\n{\\b Project}"
          Project p = current
          if (!null p){for t in p do 
            {
              if (exitLoop){continue}
            triggerInfo(t, deleteIt, exitLoop)}
          }
          else {disp += ": no current project"}
          disp += "{\n\n\\b Database}"
          for t in database do 
          {
            if (exitLoop){continue}
            triggerInfo(t, deleteIt, exitLoop)
          }
          set(infoDBE, stringOf(disp))
        }
        // ----------------------------------------------------------------------
        void listTriggers(DB db){triggerList(false)}
        // ----------------------------------------------------------------------
        void deleteTriggers(DB db){triggerList(true); triggerList(false)}
        // ----------------------------------------------------------------------
        void deleteTrigger(DBE dbe)
        {
          string selectedTrigger = get(deleteDBE)
          Trigger t
          string del
          if (find(triggerList, selectedTrigger, t))
          {
            del = delete(t)
            if (!null del){ack "Error deleting trigger:\n\n" del ""}
            else {set(deleteDBE, ""); triggerList(false)}
          }
          else {set(deleteDBE, "No such trigger (" selectedTrigger ")")}
        }
        // ----------------------------------------------------------------------
        void displayHelp(DB db)
        {
          Buffer disp = create
          disp = "{\\b Trigger list}\n\n"
          disp += "{\\b List triggers}: "
          disp += "List all triggers in module, project and database\n"
          disp += "{\\b Delete triggers} (button): "
          disp += "Delete all triggers in module, project and database\n"
          disp += "{\\b Delete trigger} (field): "
          disp += "Delete one trigger: "
          disp += "type (copy/paste) trigger name and hit <return> "
          set(infoDBE, stringOf(disp))
          delete disp
        }
        // ----------------------------------------------------------------------
        void closeDB(DB db)
        {delete disp; delete triggerList; hide db; destroy db; db = null}
        // ----------------------------------------------------------------------
        // ----------------------------------------------------------------------
        // Create DB
        baseDB = create("Trigger info / deletion")
        infoDBE = richText(baseDB, "", "", TEXT_WIDTH, TEXT_HEIGHT, true)
        deleteDBE = field(baseDB, "Delete trigger", "", FIELD_WIDTH, false)
        set(deleteDBE, deleteTrigger)
        apply(baseDB, "List triggers", listTriggers)
        apply(baseDB, "Delete triggers", deleteTriggers)
        apply(baseDB, "Help", displayHelp)
        close(baseDB, true, closeDB)
        realize(baseDB)
        setExtraHeightShare(infoDBE, 1.0)
        triggerList(false)
        show(baseDB)
        
        Updated on 2013-12-20T20:05:24Z at 2013-12-20T20:05:24Z by JAntley
        • llandale
          llandale
          2952 Posts
          ACCEPTED ANSWER

          Re: Triggers

          ‏2011-02-07T19:09:44Z  in response to Peter_Albert
          Didn't read the code, but when I did this I was unable to assign and store a Trigger variable. t1 = t2 does not assign a trigger value, it makes an alias. Thus this doesn't work:
          for trg in module do
          { if I care about this trigger then trgStore = trg
          }
          deal with trgStore

          trgStore ends up with the value of the LAST trigger in the module, if any were found.

          It could work if you added a break after the assignment, but then you don't check other triggers.

          Thus, my "delete" trigger script just looks for them and pauses, with a modal dialog box, the option to delete THIS one, user can cancel the script, but yes or no results in finding and displaying the next trigger. Knowing what I know now I could code around that, but its awkward.

          • Louie
  • Mathias Mamsch
    Mathias Mamsch
    1954 Posts
    ACCEPTED ANSWER

    Re: Triggers

    ‏2011-02-07T10:56:42Z  in response to homer_3
    There is a nice script "Delete Persistent Triggers" from galactic solutions, which (although not completly bug free) will allow you to see and I (am not sure, but) believe change the triggers in a database / project / module. Find it on:
    http://galactic-solutions.com/GalacticDownloadsMain.htm

    Regards, Mathias

    Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS
  • llandale
    llandale
    2952 Posts
    ACCEPTED ANSWER

    Re: Triggers

    ‏2011-02-07T19:12:52Z  in response to homer_3
    Again, be a 3 year old and accept this as it is.

    Your deploy trigger script should have a machanism for removing the trigger, which you need to do before deploying it anyway:

    if (confirm("Delete trigger " Name "??")) delete (Name, module->attribute,pre, save, 5)
    if (confirm("Deploy trigger " Name "??")) trigger(Name, module->attribute,pre, save, 5, DXL)

    • Louie
  • homer_3
    homer_3
    11 Posts
    ACCEPTED ANSWER

    Re: Triggers

    ‏2011-02-07T19:27:01Z  in response to homer_3
    Does anyone have any idea what type 'e' and 't' are in 'Trigger trigger(string name, l, t, e, int p, string dxl)'?
    • SystemAdmin
      SystemAdmin
      3180 Posts
      ACCEPTED ANSWER

      Re: Triggers

      ‏2011-02-07T20:28:19Z  in response to homer_3
      Trigger trigger(string name, l, t, e, int p, string dxl)
      

       


      As per the function declaration above, the string type argument given to 'name' also extends to 'l', 't' and 'e'.

       

       

       


      Paul Miller
      Melbourne, Australia

       

       

      Updated on 2013-12-20T20:05:51Z at 2013-12-20T20:05:51Z by JAntley
      • homer_3
        homer_3
        11 Posts
        ACCEPTED ANSWER

        Re: Triggers

        ‏2011-02-07T21:19:18Z  in response to SystemAdmin

        That's what I thought, until I tried
         

        string s = open
        trigger("foo", object, post, s, 1, dxlCode)
        

         


        This complains about invalid args to trigger

        Where

         

         

        trigger("foo", object, post, open, 1, dxlCode)
        



        is fine. So it appears like e isn't a string.



         

        Updated on 2013-12-20T20:06:39Z at 2013-12-20T20:06:39Z by JAntley
        • homer_3
          homer_3
          11 Posts
          ACCEPTED ANSWER

          Re: Triggers

          ‏2011-02-07T21:33:26Z  in response to homer_3

          No edit? This fails with invalid return type as well.

          string foo(){
          return open
          }
          

           

           

          trigger("foo", object, post, "", 1, dxlCode)
          


          Fails with incorrect arg to trigger as well.

           

           

          Updated on 2013-12-20T20:07:20Z at 2013-12-20T20:07:20Z by JAntley
        • SystemAdmin
          SystemAdmin
          3180 Posts
          ACCEPTED ANSWER

          Re: Triggers

          ‏2011-02-07T22:21:31Z  in response to homer_3

          I've only ever used the trigger string constants for 'l', 't' and 'e'. Whilst the theory would suggest that a string variable should work, I'm assuming that DXL may have type cast 'l', 't' and 'e' so that they will only work with the string constants - but I'm only guessing.

          Your example code below...

          string s = open
          trigger("foo", object, post, s, 1, dxlCode)
          


          ....should have failed on the first line anyway as "open" is a predefined constant - the error I get is 'incorrect context for binary op (=)'.

          Is there a reason why you would not want to use the trigger string constants as they are?

           

           


          Paul Miller
          Melbourne, Australia

           

           

          Updated on 2013-12-20T20:07:48Z at 2013-12-20T20:07:48Z by JAntley
          • homer_3
            homer_3
            11 Posts
            ACCEPTED ANSWER

            Re: Triggers

            ‏2011-02-07T23:11:33Z  in response to SystemAdmin

            Yea, that 1st line was more psuedocode. I set s to open using a skip list.
             

            Is there a reason why you would not want to use the trigger string constants as they are?
            

             


            I'd like to be able to pass it as a parameter to a function that creates the trigger. I'm using tertiary statements right now to get around it. But that's ugly.

             

            Updated on 2013-12-20T20:08:10Z at 2013-12-20T20:08:10Z by JAntley
    • llandale
      llandale
      2952 Posts
      ACCEPTED ANSWER

      Re: Triggers

      ‏2011-02-08T01:56:28Z  in response to homer_3
      "t" is the Type, either "pre" or "post". "e" is the Event, "open", "close", "sync" and a few others. Says so in the Help.

      • Louie
      • homer_3
        homer_3
        11 Posts
        ACCEPTED ANSWER

        Re: Triggers

        ‏2011-02-08T20:12:30Z  in response to llandale
        lol louie, those are values, not types. If I want to store pre, post, open, close, etc into a variable, there doesn't seem to be a way to do that.
        • Mathias Mamsch
          Mathias Mamsch
          1954 Posts
          ACCEPTED ANSWER

          Re: Triggers

          ‏2011-02-08T20:23:08Z  in response to homer_3

          Why not? Without trying the following should work fine, regards, Mathias

          trigType_ type = pre
          type = post
          trigEvent_ event = save
          trigEvent_ event = close
          // etc...
          

           


          Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

           

          Updated on 2013-12-20T20:08:39Z at 2013-12-20T20:08:39Z by JAntley
          • SystemAdmin
            SystemAdmin
            3180 Posts
            ACCEPTED ANSWER

            Re: Triggers

            ‏2011-02-08T22:30:50Z  in response to Mathias Mamsch

            Mathias - excellent - gave it a try and it worked (code used is shown below) - I'm interested to know more about how this works. From my simple understanding, 'l', 't' and 'e' are declared as string types and it seems that you cannot substitute these with a string variable and must use pre defined string constants, so how does your substitution of trigEvent_ & trigType_ manage to work?
             

            Trigger TestTrig
            string DXLTrig = "ack \"A message when the module opens\""
            trigEvent_ event = open
            trigType_ type = pre
             
            TestTrig = trigger("triggertest", module, type, event, 10, DXLTrig)
            

             

             


            Paul Miller
            Melbourne, Australia

             

             

            Updated on 2013-12-20T20:09:06Z at 2013-12-20T20:09:06Z by JAntley
            • Mathias Mamsch
              Mathias Mamsch
              1954 Posts
              ACCEPTED ANSWER

              Re: Triggers

              ‏2011-02-09T20:19:43Z  in response to SystemAdmin

              I guess I should upload the "undocumented perms" lists, should I? I will create a separate post for that. The principle behind this is pretty easy. You declare your own type and a few constants. Example:
               

              struct RequirementType{}
               
              const RequirementType Hardware = addr_ 0 
              const RequirementType Software = addr_ 1
              const RequirementType Firmware = addr_ 2
               
              string myFunction (RequirementType x) {
                  if (x == Hardware) return "Its a hardware Requirement!"
                  if (x == Software) return "Its a software Requirement!"
                  if (x == Firmware) return "Its a firmware Requirement!"
              }
               
              RequirementType myType = Hardware
              print (myFunction myType) "\n"
              

               


              It is basically the same for the trigger stuff. So no strings, but also nothing really magical. Since there is no function that will create/return a RequirementType for you, you need to settle with the declared constants. Kind of like an enumeration in DXL. There is lots of those types in DXL (Trigger Stuff, 'Permission', 'ConfType', ...)

              Regards, Mathias

               

               


              Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

               

              Updated on 2013-12-20T20:10:11Z at 2013-12-20T20:10:11Z by JAntley
              • SystemAdmin
                SystemAdmin
                3180 Posts
                ACCEPTED ANSWER

                Re: Triggers

                ‏2012-12-06T14:19:06Z  in response to Mathias Mamsch

                Hi,
                Any idea on how can an "assembled trigger level" be assigned to a variable of type trigLevel_?
                The following does not work:
                 

                trigLevel_ tlevel  = module->"MySRD"->attribute ->"Val_Correct"
                

                 


                while a "simple" level seems to work:

                 

                 

                 

                trigLevel_ tlevel = module;
                



                Thanks and regards.

                Pigi



                 

                 

                Updated on 2013-12-20T20:11:41Z at 2013-12-20T20:11:41Z by JAntley
                • llandale
                  llandale
                  2952 Posts
                  ACCEPTED ANSWER

                  Re: Triggers

                  ‏2012-12-06T15:20:07Z  in response to SystemAdmin
                  Unfortunately...
                  • An assembled "Trigger Level" is actually a variable of type "trigLevelDesc_".
                  • the "trigger()" and "delete()" functions have overloaded versions, one taking a variable of type "trigLevel_" another of type "trigLevelDesc_".

                  I conclude that if you are writing generic library functions to manage your triggers you will need to either..
                  1. convert all "trigLevel_" to "trigLevelDesc_" like this:
                    • trigLevelDesc_ tld = tLevel->tLevel e.g. tld = module->module (I did not test this)
                  2. write parellel functions, one with "trigLevel_" the other with "trigLevelDesc_".
                  3. write only functions using "trigLevelDesc_" and force calling programs to convert their "Level" to "LevelDesc", e.g.
                    • trigLevelDesc_ tld = module->NameModFull
                    • trigLevelDesc_ tld = module->module
                    • trigLevelDesc_ tld = module->object
                    • trigLevelDesc_ tld = project->NameProjFull

                  -Louie

                  Unfortunately, I wrote library functions using only trigLevel_ since I tested only with simple triggers.
                  • SystemAdmin
                    SystemAdmin
                    3180 Posts
                    ACCEPTED ANSWER

                    Re: Triggers

                    ‏2012-12-11T08:04:20Z  in response to llandale

                    Hi Louie,
                    I tried to define the trigLevDesc_ variable, and it is assigned without problems.
                    But when I pass it to the trigger() function, I get an EXCEPTION_ACCESS_VIOLATION (I'm using DOORS 8.3.0.1).
                    And that is strange, because the delete() function with the same parameter works...

                    In other words:
                     

                    string         tname   = "MyTrigger";
                    string         tlmod   = "MyModule";
                    string         tlattr  = "MyAttribute";
                    trigLevelDesc_ tld = module->tlmod->attribute->tlattr;
                     
                    delete(tname, tld, post, save, 8); // This works
                    t = trigger(tname, tld, post, save, 8, "infoBox(\"It works!\")"); //This gives an exception
                    t = trigger(tname, module->tlmod->attribute->tlattr, post, save, 8, "infoBox(\"It works!\")"); //This works
                    

                     


                    Anyway, the last working line is enough for me.
                    Thanks a lot for the hints!

                    Pigi

                     

                    Updated on 2013-12-20T20:13:21Z at 2013-12-20T20:13:21Z by JAntley
                    • llandale
                      llandale
                      2952 Posts
                      ACCEPTED ANSWER

                      Re: Triggers

                      ‏2012-12-11T19:21:50Z  in response to SystemAdmin
                      Couldn't make it work either. It appears perhaps "trigLevelDesc_" is one of those constructs that is auto-deleted once it is used. That makes a clever generic Trigger script far harder to code.

                      -Louie
          • homer_3
            homer_3
            11 Posts
            ACCEPTED ANSWER

            Re: Triggers

            ‏2011-02-08T22:45:37Z  in response to Mathias Mamsch
            Thanks Mathias. Where are trigType_ and trigEvent_ documented? They don't appear in the DXL reference manual.
            • llandale
              llandale
              2952 Posts
              ACCEPTED ANSWER

              Re: Triggers

              ‏2011-02-09T17:34:08Z  in response to homer_3

              They are not in the DXL manual, and in fact there are loads of so-called 'internal' data types not advertised there. There is a lot of good things to be gleaned out of the doors.exe file. Here are the trigger data types:

              struct    Trigger {};
              struct  trigLevel_ {};
              struct  trigLevelMod_ {};
              struct  trigLevelDesc_ {};
              struct  trigType_ {} ; 
              struct  trigEvent_ {} ;
              struct  TriggerStatus {};
              


              So with that info you can write your own define-trigger form, display "pre" and translate that into trigType_ tp = pre

              having said that, I had some difficulty manipulating these variables but don't recall exactly, perhaps "tp1 = tp2" makes an alias and not an assignment.

               

               

              • Louie

               

               

              Updated on 2013-12-20T20:10:52Z at 2013-12-20T20:10:52Z by JAntley