18 Replies Latest reply on Jan 5, 2011 1:12 AM by mlavie

    How To Prevent Recursive (Vicious Circle) Events

    mlavie Level 1

      I am using the IDScriptingEventAdapter to capture the movement of PageItem's on the page, as follows:

       

          var adapter:IDScriptingEventAdapter = IDScriptingEventAdapter.getInstance();
          adapter.addEventListener(com.adobe.indesign.Event.AFTER_SELECTION_ATTRIBUTE_CHANGED, listener);
          adapter.addEventListener(com.adobe.indesign.Event.AFTER_SELECTION_CHANGED, listener);

       

      The problem is that the listener() method contains commands which themselves move PageItem's - thereby firing itself recursively in a vicuous circle - thus causing stack overflow.

       

      I tried this, but it doesn't help:

       

         public function listener(event:*):void
         {
          RemoveEventListeners(); // Removes the listener which fired the event
          MoveArounfPageItems(); // Move around PgaeItem's
          AddEventListeners(); // Put the listeners back
         }

       

      I thought that removing the listeners would help, but apparently they are put back BEFORE the moved PageItem's fire their events.

       

      What can I do?

       

      TIA,

      mlavie

        • 1. Re: How To Prevent Recursive (Vicious Circle) Events
          Bob Stucky Adobe Employee

          This one would probably be better posted to the CS5 SDK forum!

           

          The events you're listening for are somewhat generic - AFTER_SELECTION_ATTRIBUTE_CHANGED, for example, is fired for all sorts of things, not just the movement of a PageItem.

           

          In your listener you'll have to put some conditions that check to see if you actually want to respond to the event. Now, if a page item moves, and then your listener moves it, you'll have a circular event loop no matter what. To solve that, you'll need to save some state information in the object itself, say with a label. Something like this should do it (not tested in any way).

           

          public function listener( event: * ): void

               // decide if the event it something we want to handle   

               if ( event.target is TextFrame ) {

                    var tf: TextFrame = event.target as TextFrame;

                    var state: String = tf.extractLabel( "myMoveState" );

                    // check to see if we moved it or the user did...

                    if ( state == "WeMovedIt" ) {

                         tf.insertLabel( "myMoveState", "WeDidNotMoveIt" );

                    } else {

                         tf.insertLabel( "myMoveState", "WeMovedIt" );

                         functionThatMovesTheFrame( tf );

               }

          }

          • 2. Re: How To Prevent Recursive (Vicious Circle) Events
            mlavie Level 1

            Bob,

             

            Thanks for ther swift response.

             

            The problem with your sugestion is, that in ActionScript (at least) only the application-level events fire (addListenerToObject() almsot never works - Harbs already pointed this out to me yesterday in a previous post). Thus - the event traget is always the app or the LayoutWindows. Also, I could find no more specifc an event than AFTER_SELECTION_ATTRIBUTE_CHANGED.

             

            Actually - I do not re-move the same PageItem, but rather move another PageItem based on the movement in the first PageItem - but that second PageItem ends up firing the event, too.

             

            Any ideas?

             

            TIA - mlavie

            • 4. Re: How To Prevent Recursive (Vicious Circle) Events
              Bob Stucky Adobe Employee

              APID is workable.

               

              But...

               

               

              public function listener( event: * ): void

                   // decide if the event it something we want to handle  

                   if ( event.target is TextFrame ) {

                        var tf: TextFrame = event.target as TextFrame;

                        var state: String = tf.extractLabel( "myMoveState" );

                        // check to see if we moved it or the user did...

                        if ( state == "WeMovedIt" ) {

                             tf.insertLabel( "myMoveState", "WeDidNotMoveIt" );

                        } else {

                             // a function that determines which frame I have to move...

                             var tf2: TextFrame = getFrameIGottaMove( tf );

                             tf2.insertLabel( "myMoveState", "WeMovedIt" );

                             functionThatMovesTheFrame( tf2 );

                   }

              }

               

              That should work... It shouldn't matter which frame you move, you just want to make sure that if you moved it, when the event fires, you don't move it (or a linked page item) again.

               

              Bob

              • 5. Re: How To Prevent Recursive (Vicious Circle) Events
                mlavie Level 1

                Could calls to JavaScript somehow help?

                • 6. Re: How To Prevent Recursive (Vicious Circle) Events
                  Marc Autret Level 4

                  Hi Bob,

                   

                  Newbie's question: using the ActionScript wrapper, can event.target be a TextFrame when the handler reacts to AFTER_SELECTION_ATT RIBUTE_CHANGED?

                   

                  @+

                  Marc

                  • 7. Re: How To Prevent Recursive (Vicious Circle) Events
                    mlavie Level 1

                    Bob,

                     

                    It is my understanding that only an App or LayoutWIndow is returned as a target, and not a PageItem, despite what the documentatation says. Am I wrong? And if I am wrong, I'd really appreciate an example of how to write the "addListener()" method for such a case.

                     

                    Thanks - mlavie

                    • 8. Re: How To Prevent Recursive (Vicious Circle) Events
                      Harbs. Level 6

                      Yeah.

                       

                      The function does what you need, but the real problem is it's not possible to attach this to specific page items (which as I understand it is mlavie's problem). If you need it to work with ALL page items (and all that that means in terms of overhead), this should work. But to work with specific page items, I think your still gonna need APID...

                       

                      Harbs

                      • 9. Re: How To Prevent Recursive (Vicious Circle) Events
                        Harbs. Level 6

                        Marc,

                         

                        ActionScript adds no functionality here. If it doesn't work in ES, it won't work in AS...

                         

                        Harbs

                        • 10. Re: How To Prevent Recursive (Vicious Circle) Events
                          Bob Stucky Adobe Employee

                          Sorry, I should have been more deliberate in working

                          that example.

                           

                          You can get other objects than just App or LayoutWindow (such as Document, Image, Link, ToolBox (really!) ).

                           

                          In a bit, I'll post a utility that I wrote and use for figuring out what ID events fire when, and what kinds of objects are the targets.

                           

                          Bob

                          • 11. Re: How To Prevent Recursive (Vicious Circle) Events
                            Harbs. Level 6

                            Bob Stucky wrote:

                            ...ToolBox (really!) ).

                            Now, that's interesting... I really have to find the time to play with this stuff...

                             

                            Harbs

                            • 12. Re: How To Prevent Recursive (Vicious Circle) Events
                              Bob Stucky Adobe Employee

                              I've attached a zxp installer to this post (EventWatcher.zxp).

                               

                              This is a utility I use to see what events are being fired by InDesign when and by whom.

                               

                              Double click the file to install.

                               

                              You can add events to App, documents, and pageitems. Granted they don't mean anything in some cases. I have not done an exhaustive test to see all of the possible events that each type of object can fire.

                               

                              Install it and play with it. You'll see some interesting stuff.

                               

                              Bob

                              • 13. Re: How To Prevent Recursive (Vicious Circle) Events
                                Marc Autret Level 4

                                Thanks, Bob.

                                 

                                So all we're talking about here can be directly tested in ExtendScript —that reassures me!

                                 

                                Like mlavie, I'm looking to experiment the mechanism of the CS5 events, and what I experienced so far is that an event handler which is attached to AFTER_SELECTION_ATTRIBUTE_CHANGED generally receives a LayoutWindow as the event.target, at least in usual layout context. I concluded that the DOM event system can report any selection or selection's attribute change, but that it cannot specify which page item or attribute is concerned. Wrong?

                                 

                                In fact, it doesn't seem difficult to identify which object is undergoing a change, since this object should belong to the app.selection array, right?

                                 

                                On the other hand, how can we discover what property of that object (geometricBounds, appliedParagraphStyle, etc.) has just changed? The event message provides no information about it, does it?

                                 

                                AFAIK, the AFTER_SELECTION_ATTRIBUTE_CHANGED event is only supported by Application, LayoutWindow or similar high level objects. So we need to use sth like:

                                 

                                app.addEventListener(Application.AFTER_SELECTION_ATTRIBUTE_CHANGED, myEventHandler);

                                 

                                ToolBox has an AFTER_ATTRIBUTE_CHANGED event which is dispatched when a property changes within the ToolBox itself. Also, the Link object features a number of promising events, including AFTER_ATTRIBUTE_CHANGED. But basic page items such as TextFrame, Rectangle, Group, etc., only offer the canonical BEFORE_PLACE and AFTER_PLACE event types, and nothing more.

                                 

                                Thanks for opening our eyes on advanced event secrets!

                                 

                                @+

                                Marc

                                • 14. Re: How To Prevent Recursive (Vicious Circle) Events
                                  Harbs. Level 6

                                  Marc Autret wrote:

                                   

                                  Thanks, Bob.

                                   

                                  But basic page items such as TextFrame, Rectangle, Group, etc., only offer the canonical BEFORE_PLACE and AFTER_PLACE event types, and nothing more.

                                   

                                  I believe that's correct. IIRC, the engineer who implemented it, told me that the event architecture in CS5 was never totally finished... (any inaccuracies are mine...)

                                   

                                  Harbs

                                  • 15. Re: How To Prevent Recursive (Vicious Circle) Events
                                    Harbs. Level 6

                                    Marc Autret wrote:

                                     

                                    On the other hand, how can we discover what property of that object (geometricBounds, appliedParagraphStyle, etc.) has just changed? The event message provides no information about it, does it?

                                     

                                    I think the events just expose some of what's available on the C++ level. AFAIK, notifications on the C++ level are not as fine grained as that. You can get notification when an object is changed, but not (easily) specifically what about it changed...

                                     

                                    Harbs

                                    • 16. Re: How To Prevent Recursive (Vicious Circle) Events
                                      Marc Autret Level 4

                                      Well, the conclusion is that a script cannot actually spy on attribute changes in themselves, unless permanently saving the whole state of every object and comparing the before/after property values. Exhausting!

                                       

                                      @+

                                      Marc

                                      • 17. Re: How To Prevent Recursive (Vicious Circle) Events
                                        Marijan Tompa [tomaxxi] Level 4

                                        Harbs. wrote:

                                         

                                        I believe that's correct. IIRC, the engineer who implemented it, told me that the event architecture in CS5 was never totally finished... (any inaccuracies are mine...)

                                         

                                        Harbs

                                         

                                        OK, this explains lack of events for BackgroundTasks... I just couldn't find event that is fired when BackgroundTask finishes. OR?

                                         

                                        --

                                        tomaxxi

                                        http://indisnip.wordpress.com/

                                        http://inditip.wordpress.com/

                                        • 18. Re: How To Prevent Recursive (Vicious Circle) Events
                                          mlavie Level 1

                                          Thanks Bob for your efforts. I guess that although the events are all esse

                                          ntially at the App/LayoutWindow/Doc level (and NOT PageItem), I could check the app.Selected array as someone here suggested.

                                           

                                          Bob - do you know if/when Adobe plans to support PageItem-level events (aside from BEFORE/AFTER_PLACE which already works)?

                                           

                                          AGain - thanks,

                                           

                                          mlavie