parameters: (self, field, key, REQUEST)
return_statement: return PlanningBoxEditor(field.id, update_dict)
docstring: main method to solve validation
      - rebuild the whole planning structure but do not display it.
        this is needed to be able to get the block positions
      - apply block movements recovered from the java script
      - for each block moved, check the modification (over he primary axis in
        case task association has changed, and also over the lane axis to
        check block movement / resizement).
        Beware : This checking part does not include constraint checking.
      - build a list with the validated blocks and also with the error blocks
        (if any).
      - return a dict of values to update objects in case no errors have been
        found. Otherwise save in the REQUEST the list of error blocks so that
        they can be displayed in a special way.
docstring_summary: main method to solve validation
      - rebuild the whole planning structure but do not display it.
        this is needed to be able to get the block positions
      - apply block movements recovered from the java script
      - for each block moved, check the modification (over he primary axis in
        case task association has changed, and also over the lane axis to
        check block movement / resizement).
        Beware : This checking part does not include constraint checking.
      - build a list with the validated blocks and also with the error blocks
        (if any).
      - return a dict of values to update objects in case no errors have been
        found. Otherwise save in the REQUEST the list of error blocks so that
        they can be displayed in a special way.
docstring_tokens: main method to solve validation - rebuild the whole planning structure but do not display it . this is needed to be able to get the block positions - apply block movements recovered from the java script - for each block moved check the modification ( over he primary axis in case task association has changed and also over the lane axis to check block movement / resizement ) . Beware : This checking part does not include constraint checking . - build a list with the validated blocks and also with the error blocks ( if any ) . - return a dict of values to update objects in case no errors have been found . Otherwise save in the REQUEST the list of error blocks so that they can be displayed in a special way .
function: def validate(self, field, key, REQUEST):
      """
      main method to solve validation
      - rebuild the whole planning structure but do not display it.
        this is needed to be able to get the block positions
      - apply block movements recovered from the java script
      - for each block moved, check the modification (over he primary axis in
        case task association has changed, and also over the lane axis to
        check block movement / resizement).
        Beware : This checking part does not include constraint checking.
      - build a list with the validated blocks and also with the error blocks
        (if any).
      - return a dict of values to update objects in case no errors have been
        found. Otherwise save in the REQUEST the list of error blocks so that
        they can be displayed in a special way.
      """
      # init params
      value = None
      context = getContext(field, REQUEST)
  
      # recover usefull properties
      block_moved_string = REQUEST.get('block_moved','')
      block_previous_string = REQUEST.get('previous_block_moved','')
  
      ############## REBUILD STRUCTURE #################
      # build structure
      basic, planning = PlanningBoxWidgetInstance.render_structure(field=field,
                            REQUEST= REQUEST,
                            context=context)
  
      # getting coordinates script generator
      planning_coordinates_method = getattr(context, 'planning_coordinates')
      # calling script to generate coordinates
      planning_coordinates = planning_coordinates_method(basic=basic,
                                                         planning=planning)
  
      ########## RECOVERING BLOCK MOVED DICTS ##########
      #  converting string to a structure
      block_moved_list = self.getBlockPositionFromString(block_moved_string)
      # block_moved_list now holds a list of structure recovered from the REQUEST
      # and correspondig to the movements done before validating
      block_previous_list =\
                         self.getBlockPositionFromString(block_previous_string)
      # list of previous blocks moved if an error occured during previous
      # validation
  
      # updating block_moved_list using block_previous_list.
      # This is very important not to escape processing blocks that have been
      # moved during a previous validation attempt.
      if block_previous_list != [] and block_moved_list != []:
        for block_previous in block_previous_list:
          # checking if the block has been moved again in this validation attempt
          # if it is the case, the block must be also present in the current
          # block_moved_list
          block_found = {}
          for block_moved in block_moved_list:
            if block_moved['name'] == block_previous['name']:
              block_found = block_moved
              break
          if block_found != {}:
            # block has been moved again, updating its properties in the current
            # list to take into account its previous position. current block is
            # known as 'block_found', and the value to update is the original
            # absolute position used to get relative coordinates
            block_found['old_X'] = block_previous['old_X']
            block_found['old_Y'] = block_previous['old_Y']
          else:
            # block has not been moved again, adding old block information to
            # the current list of block_moved
            block_moved_list.append(block_previous)
      elif block_previous_list != []:
        # block_moved_list is empty but not block_previous_list. This means the
        # user is trying to validate again without any change
        block_moved_list = block_previous_list
      elif block_moved_list != []:
        # block_previous_list is empty, this means this is the first validation
        # attempt. Using the block_moved_list as it is
        pass
      else:
        # the two lists are empty : nothing to validate
        return None
      # block_moved_list is updated
  
      # dict aimed to hold all information about block
      final_block_dict = {}
      # dict holding all the activities that will need an update because at least
      # one of the blocks concerned is moved
      activity_dict = {}
      # list holding all the activities having one of their block not validated
      # in such a case the update process of the activity is canceled
      warning_activity_list = []
      error_block_list = []
      error_info_dict = {}
  
      ########## GETTING BLOCK INFORMATION ############
      # iterating each block_moved element and recovering all usefull properties
      # BEWARE : no update is done here as an activity can be composed of several
      # blocks and so we need first to check all the blocks moved
      for block_moved in block_moved_list:
        final_block = {}
        # recovering the block object from block_moved information
        final_block['block_object'] = self.getBlockObject(block_moved['name'], \
                                                          planning.content)
        # recovering original activity object
        final_block['activity_origin'] = \
             final_block['block_object'].parent_activity
        # recovering original axis_group object
        final_block['group_origin'] = \
             final_block['activity_origin'].parent_axis_element.parent_axis_group
        # recovering relative block information in planning_coordinates
        final_block['block_info'] = \
             planning_coordinates['content'][block_moved['name']]
  
        # calculating delta
        # block_moved holds coordinates recovered from drag&drop script, while
        # block_info has the relative coordinates.
        # In fact the Drag&Drop java script used to get destination coordinates
        # gives them in absolute. so using original block position to get the
        # relative position
        deltaX = block_moved['old_X'] - final_block['block_info']['margin-left']
        deltaY = block_moved['old_Y'] - final_block['block_info']['margin-top']
  
        # calculating new block position:
        # width and height are already in the good format
        block_moved['left'] = block_moved['new_X'] - deltaX
        block_moved['top']  = block_moved['new_Y'] - deltaY
  
        # abstracting axis representation (for generic processing)
        if planning.vertical_view == 0:
          block_moved['report_axis_position'] = block_moved['top']
          block_moved['report_axis_length'] = block_moved['height']
          block_moved['lane_axis_position'] = block_moved['left']
          block_moved['lane_axis_length'] = block_moved['width']
          # used afterwards to get destination group
          group_position = 'margin-top'
          group_length = 'height'
          # used afterwards to get lane axis displacements and modifications
          axis_length = 'width'
        else:
          block_moved['report_axis_position'] = block_moved['left']
          block_moved['report_axis_length'] = block_moved['width']
          block_moved['lane_axis_position'] = block_moved['top']
          block_moved['lane_axis_length'] = block_moved['height']
          group_position = 'margin-left'
          group_length = 'width'
          axis_length = 'height'
  
        # calculating center of block over main axis to check block position
        block_moved['center'] = (block_moved['report_axis_length'] / 2) + \
                                 block_moved['report_axis_position']
  
        # now that block coordinates are recovered as well as planning
        # coordinates, recovering destination group over the main axis to know
        # if the block has been moved from a group to another
        group_destination = self.getDestinationGroup(basic, planning,
                 block_moved,planning_coordinates['report_axis'],
                 group_position, group_length)
  
        if group_destination is None:
          # !! Generate an Error !!
          # block has been moved outside the content area (not in line with any
          # group of the current area).
          # adding current block to error_list
          error_block_list.append(block_moved['name'])
          error_info_dict[block_moved['name']] = 'out of bounds on main axis'
          # adding if necessary current activity to warning_list
          if final_block['activity_origin'].name not in warning_activity_list:
            warning_activity_list.append(final_block['activity_origin'].name)
          lane_axis_positions = [ None , None ]
        else:
          # now that all information about the main axis changes are
          # known, checking modifications over the lane axis.
          lane_axis_positions = self.getDestinationBounds(basic, planning,
                  block_moved, final_block['block_object'],
                  planning_coordinates, axis_length,
                  destination_group = group_destination)
          if lane_axis_positions[2] == 1 :
            # !! Generate an Error !!
            # block has been moved outside the content area (bounds do not match
            # current area limits)
            if block_moved['name'] not in error_block_list:
              error_block_list.append(block_moved['name'])
              error_info_dict[block_moved['name']] = 'out of bounds on sec axis'
              if final_block['activity_origin'].name not in warning_activity_list:
                warning_activity_list.append(final_block['activity_origin'].name)
  
        block_moved['lane_axis_start'] = lane_axis_positions[0]
        block_moved['lane_axis_stop'] = lane_axis_positions[1]
  
        final_block['block_moved'] = block_moved
        final_block['group_destination'] = group_destination
  
        #final_block_dict[block_moved['name']] = final_block
        try:
          activity_dict[final_block['activity_origin'].name].append(final_block)
        except KeyError:
          activity_dict[final_block['activity_origin'].name] = [final_block]
  
  
      # getting object_dict to update object properties once activities are up to
      # date. Activities values will be updated directly on the
      object_dict = self.getObjectDict(basic=basic, planning=planning)
  
      ############# UPDATING ACTIVITIES ################
      # if activity is composed of several blocks, then check if it is needed to
      # update activity itself depending on blocks moved. Beware this part only
      # deals with activities (i.e task object) : an object can be represented by
      # several activities (in case of calendar mode for example).
      # build a dict
      update_list = []
      errors_list = []
      # getting start & stop property names
      start_property = field.get_value('x_start_bloc')
      stop_property = field.get_value('x_stop_bloc')
      # getting round_script if exists
      round_script=getattr(context, field.get_value('round_script'), None)
      # now processing activity updates
      for activity_name in activity_dict.keys():
        # recovering list of moved blocks in the current activity
        activity_block_moved_list = activity_dict[activity_name]
        # recovering activity object from first moved block
        activity_object = activity_block_moved_list[0]['activity_origin']
        # now getting list of blocks related to the activity (moved or not)
        activity_block_list = activity_object.block_list
        if activity_object.name in warning_activity_list:
          # activity contains a block that has not been validated
          # The validation update process is canceled, and the error is reported
          err = ValidationError(StandardError,activity_object)
          errors_list.append(err)
          pass
        else:
          # no error : continue
          # recovering new activity bounds
          (start_value, stop_value) = \
               self.getActivityBounds(activity_object, activity_block_moved_list,
                                      activity_block_list)
  
          # call specific external method to round value
          if round_script is not None:
            start_value = round_script(start_value, axis='begin')
            stop_value = round_script(stop_value, axis='end')
          # adding object name to list of objects to update
          if activity_object.object.getUrl() not in update_list:
            update_list.append(activity_object.object.getUrl())
          # saving updated information in the final dict
          for activity_desc in object_dict[activity_object.object.getUrl()]:
            if activity_desc['activity_name'] == activity_object.name:
              activity_desc['axis_start'] = start_value
              activity_desc['axis_stop'] = stop_value
  
      ############### UPDATING OBJECTS #################
      # using result from updated activities to process update on objects.
      update_dict = {}
      # first building a dict with all information for each object.
      # now processing activity updates
      for object_name in update_list:
        object_info = object_dict[object_name]
        axis_start = None
        axis_stop  = None
        for activity in object_info:
          activity_start_date = activity['axis_start']
          activity_stop_date = activity['axis_stop']
          if activity['activity_name'] == 'update':
            # case current activity is in fact 'fake' activity, just data telling
            # if can update min & max bounds according to global decision toward
            # objects.
            can_update_start = activity_start_date
            can_update_stop  = activity_stop_date
          else:
            if axis_start > activity_start_date or axis_start is None:
              axis_start = activity_start_date
            if axis_stop  < activity_stop_date  or axis_stop  is None:
              axis_stop = activity_stop_date
  
        update_dict[object_name] = {}
        if can_update_start and axis_start is not None:
          update_dict[object_name][start_property] = axis_start
        if can_update_stop  and axis_stop  is not None:
          update_dict[object_name][stop_property]  = axis_stop
  
      # testing if need to raise errors
      if len(errors_list) > 0:
        # need to raise an error
        # rebuilt position string including new values
        block_moved_string = self.setBlockPositionToString(block_moved_list)
        # save the current block_list for repositionning the blocks
        # to their final position
        REQUEST.set('previous_block_moved',block_moved_string)
        # saving blocks not validated as such as the activity they belong to to
        # apply a special treatment.
        REQUEST.set('warning_activity_list',warning_activity_list)
        REQUEST.set('error_block_list',error_block_list)
        REQUEST.set('error_info_dict',error_info_dict)
        # now raise error => automatically called
        # parameters are :
        # - list of errors
        # - dict with error results
        raise FormValidationError(errors_list, {})
  
      # the whole process is now finished,
      # just need to return editor for updating data
      return PlanningBoxEditor(field.id, update_dict)
function_tokens: def validate ( self , field , key , REQUEST ) : # init params value = None context = getContext ( field , REQUEST ) # recover usefull properties block_moved_string = REQUEST . get ( 'block_moved' , '' ) block_previous_string = REQUEST . get ( 'previous_block_moved' , '' ) ############## REBUILD STRUCTURE ################# # build structure basic , planning = PlanningBoxWidgetInstance . render_structure ( field = field , REQUEST = REQUEST , context = context ) # getting coordinates script generator planning_coordinates_method = getattr ( context , 'planning_coordinates' ) # calling script to generate coordinates planning_coordinates = planning_coordinates_method ( basic = basic , planning = planning ) ########## RECOVERING BLOCK MOVED DICTS ########## #  converting string to a structure block_moved_list = self . getBlockPositionFromString ( block_moved_string ) # block_moved_list now holds a list of structure recovered from the REQUEST # and correspondig to the movements done before validating block_previous_list = self . getBlockPositionFromString ( block_previous_string ) # list of previous blocks moved if an error occured during previous # validation # updating block_moved_list using block_previous_list. # This is very important not to escape processing blocks that have been # moved during a previous validation attempt. if block_previous_list != [ ] and block_moved_list != [ ] : for block_previous in block_previous_list : # checking if the block has been moved again in this validation attempt # if it is the case, the block must be also present in the current # block_moved_list block_found = { } for block_moved in block_moved_list : if block_moved [ 'name' ] == block_previous [ 'name' ] : block_found = block_moved break if block_found != { } : # block has been moved again, updating its properties in the current # list to take into account its previous position. current block is # known as 'block_found', and the value to update is the original # absolute position used to get relative coordinates block_found [ 'old_X' ] = block_previous [ 'old_X' ] block_found [ 'old_Y' ] = block_previous [ 'old_Y' ] else : # block has not been moved again, adding old block information to # the current list of block_moved block_moved_list . append ( block_previous ) elif block_previous_list != [ ] : # block_moved_list is empty but not block_previous_list. This means the # user is trying to validate again without any change block_moved_list = block_previous_list elif block_moved_list != [ ] : # block_previous_list is empty, this means this is the first validation # attempt. Using the block_moved_list as it is pass else : # the two lists are empty : nothing to validate return None # block_moved_list is updated # dict aimed to hold all information about block final_block_dict = { } # dict holding all the activities that will need an update because at least # one of the blocks concerned is moved activity_dict = { } # list holding all the activities having one of their block not validated # in such a case the update process of the activity is canceled warning_activity_list = [ ] error_block_list = [ ] error_info_dict = { } ########## GETTING BLOCK INFORMATION ############ # iterating each block_moved element and recovering all usefull properties # BEWARE : no update is done here as an activity can be composed of several # blocks and so we need first to check all the blocks moved for block_moved in block_moved_list : final_block = { } # recovering the block object from block_moved information final_block [ 'block_object' ] = self . getBlockObject ( block_moved [ 'name' ] , planning . content ) # recovering original activity object final_block [ 'activity_origin' ] = final_block [ 'block_object' ] . parent_activity # recovering original axis_group object final_block [ 'group_origin' ] = final_block [ 'activity_origin' ] . parent_axis_element . parent_axis_group # recovering relative block information in planning_coordinates final_block [ 'block_info' ] = planning_coordinates [ 'content' ] [ block_moved [ 'name' ] ] # calculating delta # block_moved holds coordinates recovered from drag&drop script, while # block_info has the relative coordinates. # In fact the Drag&Drop java script used to get destination coordinates # gives them in absolute. so using original block position to get the # relative position deltaX = block_moved [ 'old_X' ] - final_block [ 'block_info' ] [ 'margin-left' ] deltaY = block_moved [ 'old_Y' ] - final_block [ 'block_info' ] [ 'margin-top' ] # calculating new block position: # width and height are already in the good format block_moved [ 'left' ] = block_moved [ 'new_X' ] - deltaX block_moved [ 'top' ] = block_moved [ 'new_Y' ] - deltaY # abstracting axis representation (for generic processing) if planning . vertical_view == 0 : block_moved [ 'report_axis_position' ] = block_moved [ 'top' ] block_moved [ 'report_axis_length' ] = block_moved [ 'height' ] block_moved [ 'lane_axis_position' ] = block_moved [ 'left' ] block_moved [ 'lane_axis_length' ] = block_moved [ 'width' ] # used afterwards to get destination group group_position = 'margin-top' group_length = 'height' # used afterwards to get lane axis displacements and modifications axis_length = 'width' else : block_moved [ 'report_axis_position' ] = block_moved [ 'left' ] block_moved [ 'report_axis_length' ] = block_moved [ 'width' ] block_moved [ 'lane_axis_position' ] = block_moved [ 'top' ] block_moved [ 'lane_axis_length' ] = block_moved [ 'height' ] group_position = 'margin-left' group_length = 'width' axis_length = 'height' # calculating center of block over main axis to check block position block_moved [ 'center' ] = ( block_moved [ 'report_axis_length' ] / 2 ) + block_moved [ 'report_axis_position' ] # now that block coordinates are recovered as well as planning # coordinates, recovering destination group over the main axis to know # if the block has been moved from a group to another group_destination = self . getDestinationGroup ( basic , planning , block_moved , planning_coordinates [ 'report_axis' ] , group_position , group_length ) if group_destination is None : # !! Generate an Error !! # block has been moved outside the content area (not in line with any # group of the current area). # adding current block to error_list error_block_list . append ( block_moved [ 'name' ] ) error_info_dict [ block_moved [ 'name' ] ] = 'out of bounds on main axis' # adding if necessary current activity to warning_list if final_block [ 'activity_origin' ] . name not in warning_activity_list : warning_activity_list . append ( final_block [ 'activity_origin' ] . name ) lane_axis_positions = [ None , None ] else : # now that all information about the main axis changes are # known, checking modifications over the lane axis. lane_axis_positions = self . getDestinationBounds ( basic , planning , block_moved , final_block [ 'block_object' ] , planning_coordinates , axis_length , destination_group = group_destination ) if lane_axis_positions [ 2 ] == 1 : # !! Generate an Error !! # block has been moved outside the content area (bounds do not match # current area limits) if block_moved [ 'name' ] not in error_block_list : error_block_list . append ( block_moved [ 'name' ] ) error_info_dict [ block_moved [ 'name' ] ] = 'out of bounds on sec axis' if final_block [ 'activity_origin' ] . name not in warning_activity_list : warning_activity_list . append ( final_block [ 'activity_origin' ] . name ) block_moved [ 'lane_axis_start' ] = lane_axis_positions [ 0 ] block_moved [ 'lane_axis_stop' ] = lane_axis_positions [ 1 ] final_block [ 'block_moved' ] = block_moved final_block [ 'group_destination' ] = group_destination #final_block_dict[block_moved['name']] = final_block try : activity_dict [ final_block [ 'activity_origin' ] . name ] . append ( final_block ) except KeyError : activity_dict [ final_block [ 'activity_origin' ] . name ] = [ final_block ] # getting object_dict to update object properties once activities are up to # date. Activities values will be updated directly on the object_dict = self . getObjectDict ( basic = basic , planning = planning ) ############# UPDATING ACTIVITIES ################ # if activity is composed of several blocks, then check if it is needed to # update activity itself depending on blocks moved. Beware this part only # deals with activities (i.e task object) : an object can be represented by # several activities (in case of calendar mode for example). # build a dict update_list = [ ] errors_list = [ ] # getting start & stop property names start_property = field . get_value ( 'x_start_bloc' ) stop_property = field . get_value ( 'x_stop_bloc' ) # getting round_script if exists round_script = getattr ( context , field . get_value ( 'round_script' ) , None ) # now processing activity updates for activity_name in activity_dict . keys ( ) : # recovering list of moved blocks in the current activity activity_block_moved_list = activity_dict [ activity_name ] # recovering activity object from first moved block activity_object = activity_block_moved_list [ 0 ] [ 'activity_origin' ] # now getting list of blocks related to the activity (moved or not) activity_block_list = activity_object . block_list if activity_object . name in warning_activity_list : # activity contains a block that has not been validated # The validation update process is canceled, and the error is reported err = ValidationError ( StandardError , activity_object ) errors_list . append ( err ) pass else : # no error : continue # recovering new activity bounds ( start_value , stop_value ) = self . getActivityBounds ( activity_object , activity_block_moved_list , activity_block_list ) # call specific external method to round value if round_script is not None : start_value = round_script ( start_value , axis = 'begin' ) stop_value = round_script ( stop_value , axis = 'end' ) # adding object name to list of objects to update if activity_object . object . getUrl ( ) not in update_list : update_list . append ( activity_object . object . getUrl ( ) ) # saving updated information in the final dict for activity_desc in object_dict [ activity_object . object . getUrl ( ) ] : if activity_desc [ 'activity_name' ] == activity_object . name : activity_desc [ 'axis_start' ] = start_value activity_desc [ 'axis_stop' ] = stop_value ############### UPDATING OBJECTS ################# # using result from updated activities to process update on objects. update_dict = { } # first building a dict with all information for each object. # now processing activity updates for object_name in update_list : object_info = object_dict [ object_name ] axis_start = None axis_stop = None for activity in object_info : activity_start_date = activity [ 'axis_start' ] activity_stop_date = activity [ 'axis_stop' ] if activity [ 'activity_name' ] == 'update' : # case current activity is in fact 'fake' activity, just data telling # if can update min & max bounds according to global decision toward # objects. can_update_start = activity_start_date can_update_stop = activity_stop_date else : if axis_start > activity_start_date or axis_start is None : axis_start = activity_start_date if axis_stop < activity_stop_date or axis_stop is None : axis_stop = activity_stop_date update_dict [ object_name ] = { } if can_update_start and axis_start is not None : update_dict [ object_name ] [ start_property ] = axis_start if can_update_stop and axis_stop is not None : update_dict [ object_name ] [ stop_property ] = axis_stop # testing if need to raise errors if len ( errors_list ) > 0 : # need to raise an error # rebuilt position string including new values block_moved_string = self . setBlockPositionToString ( block_moved_list ) # save the current block_list for repositionning the blocks # to their final position REQUEST . set ( 'previous_block_moved' , block_moved_string ) # saving blocks not validated as such as the activity they belong to to # apply a special treatment. REQUEST . set ( 'warning_activity_list' , warning_activity_list ) REQUEST . set ( 'error_block_list' , error_block_list ) REQUEST . set ( 'error_info_dict' , error_info_dict ) # now raise error => automatically called # parameters are : # - list of errors # - dict with error results raise FormValidationError ( errors_list , { } ) # the whole process is now finished, # just need to return editor for updating data return PlanningBoxEditor ( field . id , update_dict )