Gnats 5111: Crash when writing RPL logic
Revised Title: Crash applying edit to selected top-level Rpl Function or Block Execution Constraint.

Edit 10-18-2011 (b) / Phil / CVS Note

The RplFrame class supports the following "applications":

  1. BLOCK_STATEMENTS
  2. BLOCK_EXECUTION_CONSTRAINT
  3. FUNCTION_BODY
  4. FUNCTION_VALUE_CONSTRAINTS
  5. SLOT_EXPRESSION

The selection of the "top-level" object within the RplFrame is supported in all applications except SLOT_EXPRESSION.

It is this sort of selection (i.e. of a "top-level" object) which occurs when clicking just below the <expr> symbol, as described in David's Oct 18 note.

The image to the right shows a top-level selection within a Rpl Function.

  Top Level Item Selection

When operating on the selection, the RplFrame::replaceTokenNoUndo() method gets called. This method supports operations on top-level items ONLY FOR TWO of the RplFrame applications:

Application Top-Level Selection
Implemented
Top-Level item processing implemented in the RplFrame::replaceTokenNoUndo() method / Effect
BLOCK_STATEMENTS YES YES  
BLOCK_EXECUTION_CONSTRAINT YES NO CRASH
FUNCTION_BODY YES NO CRASH
FUNCTION_VALUE_CONSTRAINTS YES YES  
SLOT_EXPRESSION NO NO (does not occur)

Preventing the selection of the top-level object within a Slot Expression RplFrame is implemented with a special provision in the VisualToken::contains(int x, int y) method -- SEE BELOW. Note the exceptions for VisualToken::SLOT_SYMBOL in this method.

The Gnats 5111 crash can be avoided by excluding also FUNCTION_SYMBOL and BLOCK_EXEC_CONSTRAINT_SYMBOL containers.

//----------------------------------------------------------------------------
//+public
//
// METHOD: 
//   VisualToken* VisualToken::contains(int x, int y)
//
// PURPOSE:
//   Returns the deepest token in this token's tree that contains the 
//   given point.
//
// PARAMETERS:
//   (I) x,y - a cartesian point
// 
// RETURN VALUE:
//   The most "junior" VisualToken containing the point x, y.  NULL if no
//   VisualToken contains the point. 
//
//----------------------------------------------------------------------------
VisualToken* VisualToken::contains(int x, int y)
{
   VisualToken *selected = NULL;

   if (_deviceRect.contains (x, y))
   {
      cwIterator  iter;
      VisualToken *child = NULL;
      VisualToken *container = NULL;

      FORALL (iter, *_children)
      {
         child = _children->elem(iter);

         // Don't let the user select the top-level slot expression.
         if (((container = child->contains(x, y)) != NULL) &&
             (!container->isA(VisualToken::SLOT_SYMBOL)) )
         {
            if (!selected || 
                selected->_children->size() > container->_children->size())
            {
               selected = container;
            }
         }
      }
     
      //
      // None of my children (I may not have any) contained the point
      // 
      if (!selected && !isA(VisualToken::SLOT_SYMBOL))
         return this;
   }

   return selected;
}

---