From 8500048f69ca85473de10f4fc7025ba50525a753 Mon Sep 17 00:00:00 2001
From: Sebastien Robin <seb@nexedi.com>
Date: Thu, 27 Apr 2006 21:12:58 +0000
Subject: [PATCH] commit the work done by Thomas

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@6976 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 product/ERP5Form/PlanningBox.py | 4089 ++++++++++++++++---------------
 1 file changed, 2107 insertions(+), 1982 deletions(-)

diff --git a/product/ERP5Form/PlanningBox.py b/product/ERP5Form/PlanningBox.py
index 493eb1519d..a48953c22c 100644
--- a/product/ERP5Form/PlanningBox.py
+++ b/product/ERP5Form/PlanningBox.py
@@ -1,6 +1,8 @@
 ##############################################################################
 #
 # Copyright (c) 2005 Nexedi SARL and Contributors. All Rights Reserved.
+#                    Tomas Bernard <thomas@nexedi.com>
+#     from an original experimental script written by :
 #                    Jonathan Loriette <john@nexedi.com>
 #
 # WARNING: This program as such is intended to be used by professional
@@ -8,7 +10,7 @@
 # consequences resulting from its eventual inadequacies and bugs
 # End users who are looking for a ready-to-use solution with commercial
 # garantees and support are strongly adviced to contract a Free Software
-# Service Company
+# Service Companyf
 #
 # This program is Free Software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
@@ -25,7 +27,16 @@
 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #
 ##############################################################################
+import pdb
+
 import string, types, sys
+
+# class monitoring access security control
+from Products.PythonScripts.Utility import allow_class
+from AccessControl import ClassSecurityInfo
+from Globals import InitializeClass
+
+
 from Form import BasicForm
 from Products.Formulator.Field import ZMIField
 from Products.Formulator.DummyField import fields
@@ -43,2023 +54,2112 @@ from Acquisition import aq_base, aq_inner, aq_parent, aq_self
 from Products.Formulator.Form import BasicForm
 from Products.CMFCore.utils import getToolByName
 
+from Products.ERP5Type.Utils import getPath
+
 class PlanningBoxValidator(Validator.StringBaseValidator):
-  def validate(self, field, key, REQUEST):
-    """allows to check if one block is not outside of the planning"""
-    bmoved=REQUEST.get('block_moved')
+  """
+  Class holding all methods used to validate a modified PlanningBox
+  can be called only from a HTML rendering using wz_dragdrop script
+  """
+  def validate(self,field,key,REQUEST):
+    """
+    main method to solve validation
+    first rebuild the whole structure but do not display it
+    then recover the list of block moved and check the modifications to
+    apply
+    """
+
+    # init params
+    value = None
     form = field.aq_parent
-    height_global_div= field.get_value('height_global_div')    
-    width_line = field.get_value('width_line')
     here = getattr(form, 'aq_parent', REQUEST)
-    space_line=field.get_value('space_line')
+
+    # recover usefull properties
+    #pdb.set_trace()
+    block_moved_string = REQUEST.get('block_moved')
+    old_delta1 = REQUEST.get('old_delta1')
+    old_delta2 = REQUEST.get('old_delta2')
+
+    #pdb.set_trace()
+
+    ##################################################
+    ############## REBUILD STRUCTURE #################
+    ##################################################
+    # build structure
+    structure = PlanningBoxWidgetInstance.render_structure(field=field, key=key, value=value, REQUEST=REQUEST, here=here)
+
+    # getting coordinates script generator
+    planning_coordinates_method = getattr(here,'planning_coordinates')
+    # calling script to generate coordinates
+    planning_coordinates = planning_coordinates_method(structure=structure)
+
+    ##################################################
+    ########## RECOVERING BLOK MOVED DICT ############
+    ##################################################
+    #  converting string to a structure
+    block_moved_list = []
+    if block_moved_string != '':
+      block_moved_object_list = block_moved_string.split('*')
+      for block_moved_object_string in block_moved_object_list:
+        block_moved_dict = None
+        block_moved_dict = {}
+        block_moved_sub_list = block_moved_object_string.split(',')
+        block_moved_dict['name'] = block_moved_sub_list[0]
+        block_moved_dict['old_X'] = float(block_moved_sub_list[1])
+        block_moved_dict['old_Y'] = float(block_moved_sub_list[2])
+        block_moved_dict['new_X'] = float(block_moved_sub_list[3])
+        block_moved_dict['new_Y'] = float(block_moved_sub_list[4])
+        block_moved_dict['width'] = float(block_moved_sub_list[5])
+        block_moved_dict['height'] = float(block_moved_sub_list[6])
+        block_moved_list.append(block_moved_dict)
+    else:
+      return ''
+    # block_moved_list now holds a list of structure recovered from the REQUEST.
+
+    # XXX once this works, call a special python script 'planning_validator' to process
+    # the content instead of hardcoding it in the 'PlanningBox' script
+    # for the moment, to have faster and easier debugging, leaving this part of
+    # code in the main script
+
+
+    # dict aimed to hold all informations 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 = {}
+
+    ##################################################
+    ########## GETTING BLOCK INFORMATIONS ############
+    ##################################################
+    # 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 informations
+      final_block['block_object'] = self.getBlockObject(block_moved['name'], structure.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 structure.planning.render_format == 'YX':
+        block_moved['main_axis_position']      = block_moved['top']
+        block_moved['main_axis_length']        = block_moved['height']
+        block_moved['secondary_axis_position'] = block_moved['left']
+        block_moved['secondary_axis_length']   = block_moved['width']
+        # used afterwards to get destination group
+        group_position = 'margin-top'
+        group_length = 'height'
+        # used afterwards to get secondary axis displacements and modifications
+        axis_length = 'width'
+
+      else:
+        block_moved['main_axis_position']      = block_moved['left']
+        block_moved['main_axis_length']        = block_moved['width']
+        block_moved['secondary_axis_position'] = block_moved['top']
+        block_moved['secondary_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['main_axis_length'] / 2) + block_moved['main_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(structure, block_moved,planning_coordinates['main_axis'], group_position, group_length)
+
+      if group_destination == None:
+        # XXX need to take care of such a case :
+        # block has been moved outside the content area
+        pass
+
+      # now that all informations about the main axis changes are
+      # known, checking modifications over the secondary axis.
+      secondary_axis_positions = self.getDestinationBounds(structure, block_moved, final_block['block_object'], planning_coordinates, axis_length)
+      block_moved['secondary_axis_start'] = secondary_axis_positions[0]
+      block_moved['secondary_axis_stop'] = secondary_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]
+
+
+    ##################################################
+    ############# UPDATING ACTIVITIES ################
+    ##################################################
+    update_dict = {}
+    # 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
+
+      # recovering new activity bounds
+      new_bounds = self.getActivityBounds(activity_object, activity_block_moved_list, activity_block_list)
+
+      # XXX call specific external method to round value in case hh:mn:s are useless
+
+      # saving updating informations in the final dict
+      update_dict[activity_object.link]={'start_date':new_bounds[0],'stop_date':new_bounds[1]}
+
+    # all process is now finished, just need to return final dict
+    return update_dict
+
+
+
+
+  def getBlockObject(self, block_name, content_list):
+    """
+    recover the block related to the block_name inside the content_list
+    """
+    for block in content_list:
+      if block.name == block_name:
+        return block
+
+
+
+  def getDestinationGroup(self, structure, block_moved, axis_groups, group_position, group_length):
+    """
+    recover destination group from block coordinates and main axis coordinates
+    block_moved is a dict of properties.
+    returns the group object itself, none if the block has no good coordinates
+    """
+    good_group_name = ''
+    # recovering group name
+    for axis_name in axis_groups.keys():
+      if  axis_groups[axis_name][group_position] < block_moved['center'] and axis_groups[axis_name][group_position] + axis_groups[axis_name][group_length] > block_moved['center']:
+        # the center of the block is between group min and max bounds
+        # the group we are searching for is known
+        good_group_name = axis_name
+        break
+    # if no group is found, this means the block has been put outside the bounds
+    if good_group_name == '':
+      return None
+    # group name is known, searching corresponding group object
+    for group in structure.planning.main_axis.axis_group:
+      if group.name == good_group_name:
+        return group
+    return None
+
+
+
+  def getDestinationBounds(self, structure, block_moved, block_object, planning_coordinates, axis_length):
+    """
+    check the new bounds of the block over the secondary axis according to its
+    new position
+    """
+
+    # XXX CALENDAR
+    # has to be improved : for now the axis bounds are recovered globally, it
+    # implies that all groups have the same bounds, which is not the case in
+    # calendar mode. for that will need to add special informations about the
+    # group itself to know its own bounds.
+    delta_start = block_moved['secondary_axis_position'] / planning_coordinates['frame']['content'][axis_length]
+    delta_stop  = (block_moved['secondary_axis_position'] + block_moved['secondary_axis_length']) / planning_coordinates['frame']['content'][axis_length]
+
+    # testing different cases of invalidation
+    if delta_stop < 0 or delta_start > 1 :
+      # block if fully out of the bounds
+      # XXX must generate a block_error
+      pass
+    else:
+      if delta_start < 0 or delta_stop > 1:
+        # part of the block is inside
+        pass
+
+    axis_range = structure.basic.secondary_axis_info['bound_stop'] - structure.basic.secondary_axis_info['bound_start']
+
+    # defining new final block bounds
+    new_start = delta_start * axis_range + structure.basic.secondary_axis_info['bound_start']
+    new_stop  = delta_stop * axis_range + structure.basic.secondary_axis_info['bound_start']
+
+    return [new_start,new_stop]
+
+
+
+  def getActivityBounds(self, activity, activity_block_moved_list, activity_block_list):
+    """
+    takes a list with modified blocks and another one with original blocks,
+    returning new startactivity_block_moved_list & stop for the activity
+    BEWARE : in case an activity bound was cut off to fit planning size, the
+    value will not be updated (as the block was not on the real activity bound)
+    """
+    # getting list moved block names
+    block_moved_name_list = map(lambda x: x['block_moved']['name'], activity_block_moved_list)
+
+
+    for activity_block in activity_block_list:
+      if activity_block.name in block_moved_name_list:
+        # the block composing the activity has been moved, not taking care of
+        # the original one, but only the final position (block_moved)
+        for temp_block_moved in activity_block_moved_list:
+          # recovering corresponding moved block
+          if temp_block_moved['block_moved']['name'] == activity_block.name:
+            # moved block has been found
+            temp_start = temp_block_moved['block_moved']['secondary_axis_start']
+            temp_stop  = temp_block_moved['block_moved']['secondary_axis_stop']
+            break
+      else:
+        # the block has not been moved
+        temp_start = activity_block.position_secondary.absolute_begin
+        temp_stop  = activity_block.position_secondary.absolute_end
+      # once the start & stop values are recovered, need to test them to check
+      # if it is needed to update
+      try:
+        if temp_start < new_start:
+          new_start = temp_start
+        if temp_stop > new_stop:
+          new_stop = temp_stop
+      except NameError:
+        # new_start is not defined because it is the first block found
+        new_start = temp_start
+        new_stop = temp_stop
+
+    # new start & stop values are known
+    # checking weither activity has been cut-off to fit the planning bounds 
+    if activity.secondary_axis_begin != activity.secondary_axis_start:
+      new_start = activity.secondary_axis_begin
+    if activity.secondary_axis_end != activity.secondary_axis_stop:
+      new_stop  = activity.secondary_axis_end
+
+    return [new_start,new_stop]
+
+
+class PlanningBoxWidget(Widget.Widget):
+  """
+  PlanningBox main class used to run all the process in order to generate
+  the structure of the Planning including all internal properties.
+  Contains BasicStructure and PlanningStructure instances
+  """
+
+
+
+  property_names = Widget.Widget.property_names +\
+  ['height_header', 'height_global_div','height_axis_x', 'width_line',
+   'space_line','list_method','report_root_list','selection_name',
+   'portal_types','sort','title_line','y_unity','y_axis_width',
+   'y_range','x_range','x_axis_script_id','x_start_bloc','x_stop_bloc',
+   'y_axis_method','max_y','constraint_method','color_script','info_center',
+   'info_topleft','info_topright','info_backleft','info_backright',
+   'security_index']
+
+  # Planning properties (accessed through Zope Management Interface)
+
+
+  # kind of representation to render :
+  # Planning or Calendar
+  representation_type = fields.Stringfield('representation_type',
+      title='',
+      description='',
+      default='Planning',
+      required=1)
+
+  # added especially for new Planning Structure generation
+  # is used to split result in pages in a ListBox like rendering
+  # (delimitation over the main axis)
+  main_axis_groups = fields.IntegerField('main_axis_groups',
+      title='groups per page on main axis:',
+      description=('number of groups displayed per page on main axis'),
+      default=10,
+      required=1)
+
+  # setting header height
+  size_header_height = fields.IntegerField('size_header_height',
+      title='header height:',
+      desciption=(
+      'height of the planning header'),
+      default=100,
+      required=1)
+
+  # setting left border size
+  size_border_width_left = fields.IntegerField('size_border_width_left',
+      title='Size border width left',
+      desciption=(
+      'setting left border size'),
+      default=10,
+      required=1)
+
+  # setting the width of the Planning (excl. Y axis : only the block area)
+  size_planning_width = fields.IntegerField('size_planning_width',
+      title='Planning width:',
+      desciption=(
+      'size of the planning area, excluding axis size'),
+      default=1000,
+      required=1)
+
+  # setting the with of the Y axis
+  size_y_axis_width = fields.IntegerField('size_y_axis_width',
+      title='Y axis width:',
+      description=(
+      'width of the Y axis'),
+      default=200,
+      required=1)
+
+  # setting the with of the space (between Planning and Y axis)
+  size_y_axis_space = fields.IntegerField('size_y_axis_space',
+      title='Y axis space:',
+      description=(
+      'space between Y axis and PLanning content'),
+      default=10,
+      required=1)
+
+  # setting the height of the Planning (excl. X axis)
+  size_planning_height = fields.IntegerField('size_planning_height',
+      title='Planning height:',
+      description=(
+      'size of the planning area, excluding axis_size'),
+      default=800,
+      required=1)
+
+  # setting the height of the X axis
+  size_x_axis_height = fields.IntegerField('size_x_axis_height',
+      title='X axis height:',
+      description=(
+      'height of the X axis'),
+      default=200,
+      required=1)
+
+  # setting the height of the space (between Planning and X axis)
+  size_x_axis_space = fields.IntegerField('size_x_axis_space',
+      title='X axis space:',
+      description=(
+      'space between X axis and PLaning content '),
+      default=10,
+      required=1)
+
+  
+
+
+
+
+  default = fields.TextAreaField('default',
+      title='Default',
+      description=(
+      "Default value of the text in the widget."),
+      default="",
+      width=20, height=3,
+      required=0)
+
+  height_header = fields.IntegerField('height_header',
+      title='height of the header (px):',
+      description=(
+      "value of the height of the header, required"),
+      default=50,
+      required=1)
+
+  height_global_div = fields.IntegerField('height_global_div',
+      title='height of the graphic (px):',
+      description=(
+      "value of the height of the graphic, required"),
+      default=700,
+      required=1)
+
+  height_axis_x = fields.IntegerField('height_axis_x',
+      title='height of X-axis (px):',
+      description=(
+      "value of the height of X-axis"),
+      default=50,
+      required=1)
+
+  
+
+  width_line = fields.IntegerField('width_line',
+      title='width of the graphic (px):',
+      description=(
+      "value of width_line, required"),
+      default=1000,
+      required=1)
+
+  space_line = fields.IntegerField('space_line',
+      title='space between each line of the graphic (px):',
+      description=("space between each line of the graphic,not required"),
+      default=10,
+      required=0)
+
+  report_root_list = fields.ListTextAreaField('report_root_list',
+      title="Report Root",
+      description=("A list of domains which define the possible root."),
+      default=[],
+      required=0)
+
+  selection_name = fields.StringField('selection_name',
+      title='Selection Name',
+      description=("The name of the selection to store selections params"),
+      default='',
+      required=0)
+
+  portal_types = fields.ListTextAreaField('portal_types',
+      title="Portal Types",
+      description=("Portal Types of objects to list. Required."),
+      default=[],
+      required=0)
+
+  sort = fields.ListTextAreaField('sort',
+      title='Default Sort',
+      description=("The default sort keys and order"),
+      default=[],
+      required=0)
+
+  list_method = fields.MethodField('list_method',
+      title='List Method',
+      description=("Method to use to list objects"),
+      default='',
+      required=0)
+
+  title_line = fields.StringField('title_line',
+      title="specific method which fetches the title of each line: ",
+      description=("specific method for inserting title in line"),
+      default='',
+      required=0)
+
+  y_unity = fields.StringField('y_unity',
+      title='Unity in Y-axis:',
+      description=('The unity in Y-axis,not required'),
+      default='',
+      required=0)
+
+  y_axis_width = fields.IntegerField('y_axis_width',
+      title='width of Y-axis (px):',
+      description=(
+      "width of Y-axis, required"),
+      default=200,
+      required=1) 
+
+  y_range = fields.IntegerField('y_range',
+      title='number of range of Y-axis :',
+      description=(
+      "Number of Range of Y-axis, not required"),
+      default=0,
+      required=0) 
+
+  x_range = fields.StringField('x_range',
+      title='range of X-Axis:',
+      description=('Nature of the subdivisions of X-Axes, not Required'),
+      default='day',
+      required=0)	
+
+  x_axis_script_id = fields.StringField('x_axis_script_id',
+      title='script for building the X-Axis:',
+      description=('script for building the X-Axis'),
+      default='',
+      required=0)	
+
+  x_start_bloc = fields.StringField('x_start_bloc',
+      title='specific method which fetches the data for the beginning\
+      of a block:',
+      description=('Method for building X-Axis such as getstartDate\
+      objects'),
+      default='getStartDate',
+      required=0)
+
+  x_stop_bloc = fields.StringField('x_stop_bloc',
+      title='specific method which fetches the data for the end of\
+      each block',
+      description=('Method for building X-Axis such getStopDate\
+      objects'),
+      default='getStopDate',
+      required=0)	
+
+  y_axis_method = fields.StringField('y_axis_method',
+      title='specific method of data type for creating height of blocks',
+      description=('Method for building height of blocks objects'),
+      default='',
+      required=0) 
+
+  max_y  = fields.StringField('max_y',
+      title='specific method of data type for creating Y-Axis',
+      description=('Method for building Y-Axis objects'),
+      default='',
+      required=0)
+
+  constraint_method = fields.StringField('constraint_method',
+      title='name of constraint method between blocks',
+      description=('Constraint method between blocks objects'),
+      default='SET_DHTML',
+      required=1)
+
+  color_script = fields.StringField('color_script',
+      title='name of script which allow to colorize blocks',
+      description=('script for block colors object'),
+      default='',
+      required=0)
+
+  info_center = fields.StringField('info_center',
+      title='specific method of data called for inserting info in\
+      block center',
+      description=('Method for displaying info in the center of a\
+      block object'),
+      default='',
+      required=0) 
+
+  info_topright = fields.StringField('info_topright',
+      title='specific method of data called for inserting info in\
+      block topright',
+      description=('Method for displaying info in the topright of a block\
+      object'),
+      default='',
+      required=0)
+
+  info_topleft = fields.StringField('info_topleft',
+      title='specific method of data called for inserting info in\
+      block topleft',
+      description=('Method for displaying info in the topleft corner\
+      of a block object'),
+      default='',
+      required=0)
+
+  info_backleft = fields.StringField('info_backleft',
+      title='specific method of data called for inserting info in\
+      block backleft',
+      description=('Method for displaying info in the backleft of a\
+      block object'),
+      default='',
+      required=0)
+
+  info_backright = fields.StringField('info_backright',
+      title='specific method of data called for inserting info in\
+      block backright',
+      description=('Method for displaying info in the backright of a\
+      block object'),
+      default='',
+      required=0)
+
+  security_index = fields.IntegerField('security_index',
+      title='variable depending on the type of web browser :',
+      description=("This variable is used because the rounds of each\
+      web browser seem to work differently"),
+      default=2,
+      required=0)
+
+
+
+  def render_css(self,field, key, value, REQUEST):
+    """
+    first method called for rendering by PageTemplate form_view
+    create the whole object based structure, and then call a special
+    external PageTemplate (or DTML depending) to render the CSS code
+    relative to the structure that need to be rendered
+    """
+    
+    #pdb.set_trace()
+
+
+    # build structure
+    here = REQUEST['here']
+    structure = self.render_structure(field=field, key=key, value=value, REQUEST=REQUEST, here=here)
+
+    # getting CSS script generator
+    planning_css_method = getattr(REQUEST['here'],'planning_css')
+
+    # recover CSS data buy calling DTML document
+    #pdb.set_trace()
+    CSS_data = planning_css_method(structure=structure)
+
+    # saving structure inside the request to be able to recover it afterwards when needing
+    # to render the HTML code
+    REQUEST.set('structure',structure)
+
+    # return CSS data
+    return CSS_data
+
+  def render(self,field,key,value,REQUEST):
+    """
+    method called to render the HTML code relative to the planning.
+    for that recover the structure previouly saved in the REQUEST, and then
+    call a special Page Template aimed to render
+    """
+
+    # need to test if render is HTML (to be implemented in a page template)
+    # or list (to generated a PDF output or anything else).
+
+    # recover structure
+    structure = REQUEST.get('structure')
+
+    #pdb.set_trace()
+    if structure != None:
+      # getting HTML rendering Page Template
+      planning_html_method = getattr(REQUEST['here'],'planning_content')
+
+      # recovering HTML data by calling Page Template document
+      HTML_data = planning_html_method(struct=structure)
+
+      return HTML_data
+
+
+  def render_structure(self, field, key, value, REQUEST, here):
+    """ this method is the begining of the rendering procedure. it calls all
+        methods needed to generate BasicStructure with ERP5 objects, and then
+        creates the PlanningStructure before applying zoom.
+        No code is generated (for example HTML code) contrary to the previous
+        implementation of PlanningBox. The final rendering must be done through
+        a PageTemplate parsing the PlanningStructure object.
+        """
+
+    # DATA DEFINITION
+
+
+    # recovering usefull planning properties
+    form = field.aq_parent # getting form
+    list_method = field.get_value('list_method') # method used to list objects
+    report_root_list = field.get_value('report_root_list') # list of domains
+                                                # defining the possible root
+    portal_types = field.get_value('portal_types') # Portal Types of objects to list
+    # selection name used to store selection params
     selection_name = field.get_value('selection_name')
+    # getting sorting keys and order (list)
     sort = field.get_value('sort')
-    color_script=getattr(here,field.get_value('color_script'),None)
-    height_header = field.get_value('height_header')
-    height_global_div = field.get_value('height_global_div')
-    height_axis_x=field.get_value('height_axis_x')
-    meta_types = field.get_value('meta_types')
-    list_method = field.get_value('list_method')
-    report_root_list = field.get_value('report_root_list')
-    portal_types = field.get_value('portal_types')
-    object_start_method_id = field.get_value('x_start_bloc')
-    object_stop_method_id= field.get_value('x_stop_bloc')
-    y_axis_width = field.get_value('y_axis_width')
-    script=getattr(here,field.get_value('x_axis_script_id'),None)
-    scriptY = getattr(here,field.get_value('max_y'),None)
-    x_range = field.get_value('x_range')
-    info_center = field.get_value('info_center')
-    info_topleft = field.get_value('info_topleft')        
-    info_topright = field.get_value('info_topright')
-    info_backleft = field.get_value('info_backleft')
-    info_backright = field.get_value('info_backright')
-    block_height= getattr(here,field.get_value('y_axis_method'),None)
-    portal_url = here.portal_url()
+    # contains the list of blocks that are not validated
+    # for them a special rendering is done (special colors for example)
     list_error=REQUEST.get('list_block_error')
-    old_delta2 = REQUEST.get('old_delta2')
-    lineb= REQUEST.get('line_begin')
-    if old_delta2!='None':
-      if old_delta2!='':
-        if old_delta2!={}:
-          old_delta2=convertStringToDict(old_delta2)
+    if list_error==None : list_error = []
+
+    # END DATA DEFINITION
+
+    # XXX testing : uncoment to put selection to null 
+    #here.portal_selections.setSelectionFor(selection_name, None)
+
+    selection = here.portal_selections.getSelectionFor(
+                      selection_name, REQUEST)
+
+    # params contained in the selection object is a dictionnary.
+    # must exist as an empty dictionnary if selection is empty.
+    try:
+      params = selection.getParams()
+    except (AttributeError,KeyError):
+      params = {}
+
+    #if selection.has_attribute('getParams'):
+    #  params = selection.getParams()
+
+
+    # CALL CLASS METHODS TO BUILD BASIC STRUCTURE
+    # creating BasicStructure instance (and initializing its internal values)
+    self.basic = BasicStructure(here=here,form=form, field=field, REQUEST=REQUEST, list_method=list_method, selection=selection, params = params, selection_name=selection_name, report_root_list=report_root_list, portal_types=portal_types, sort=sort, list_error=list_error)
+    # call build method to generate BasicStructure
+    self.basic.build()
+
+    # CALL CLASS METHODS TO BUILD PLANNING STRUCTURE
+    # creating PlanningStructure instance and initializing its internal values
+    self.planning = PlanningStructure()
+    # call build method to generate final Planning Structure
+    self.planning.build(basic_structure = self.basic,field=field, REQUEST=REQUEST)
+
+    # end of main process
+    # structure is completed, now just need to return structure
+    return self
+
+
+
+# instanciating class
+PlanningBoxWidgetInstance = PlanningBoxWidget()
+
+class BasicStructure:
+  """
+  First Structure recovered from ERP5 objects. Does not represent in any
+  way the final structure used for rendering the Planning (for that see
+  PlanningStructure class). for each returned object from ERP5's request,
+  create a BasicGroup and stores all object properties.
+  No zoom is applied on this structure
+  """
+
+  def __init__ (self, here='', form='', field='', REQUEST='', list_method='',
+    selection=None, params = '', selection_name='', report_root_list='',
+    portal_types='', sort=None, list_error=None):
+    """ init main internal parameters """
+    self.here = here
+    self.form = form
+    self.field = field
+    self.REQUEST = REQUEST
+    self.sort = sort
+    self.selection = selection
+    self.params = params
+    self.list_method = list_method
+    self.selection_name = selection_name # used in case no valid list_method 
+                                         # has been found
+    self.report_root_list = report_root_list
+    self.portal_types = portal_types
+    self.basic_group_list = None
+    self.report_groups= '' # needed to generate groups
+    self.list_error = list_error
+
+    self.secondary_axis_occurence = []
+    self.render_format = '' # 'list' in case output is a list containing the
+                            # full planning structure without any selection
+
+
+    self.main_axis_info = {}
+    self.secondary_axis_info = {}
+
+
+  def build(self):
+    """
+    build BasicStructure from given parameters, and for that do the
+    specified processes :
+    1 - define variables
+    2 - building query
+    3 - generate report_tree, a special structure containing all the
+        objects with their values
+    4 - create report_sections
+    """
+
+    default_params ={}
+    current_section = None
+    #params = self.selection.getParams()
+
+
+    #recovering selection if necessary
+    if self.selection is None:
+      self.selection = Selection(params=default_params, default_sort_on=self.sort)
     else:
-      old_delta2={}
+      # immediately updating the default sort value
+      self.selection.edit(default_sort_on=self.sort)
+      self.selection.edit(sort_on=self.sort)
+
+    self.here.portal_selections.setSelectionFor(self.selection_name,
+                                        self.selection,REQUEST=self.REQUEST)
+
+    # building list of portal_types
+    self.filtered_portal_types = map(lambda x: x[0], self.portal_types)
+    if len(self.filtered_portal_types) == 0:
+      self.filtered_portal_types = None
+
+    report_depth = self.REQUEST.get('report_depth',None)
+    # In report tree mode, need to remember if the items have to be displayed
+    is_report_opened = self.REQUEST.get('is_report_opened',\
+                                    self.selection.isReportOpened())
+    portal_categories = getattr(self.form,'portal_categories',None)
+    portal_domains = getattr(self.form,'portal_domains',None)
+
+    ##################################################
+    ############### BUILDING QUERY ###################
+    ##################################################
+
+    kw = self.params
+
+    # remove selection_expression if present
+    # This is necessary for now, because the actual selection expression in
+    # search catalog does not take the requested columns into account. If
+    # select_expression is passed, this can raise an exception, because stat
+    # method sets select_expression, and this might cause duplicated column
+    # names.
+    if 'select_expression' in kw:
+      del kw['select_expression']
+
     
-    #first we rebuild the initial object structure with only line and activity block.
+
+    if hasattr(self.list_method, 'method_name'):
+      if self.list_method.method_name == 'ObjectValues':
+        # list_method is available
+        self.list_method = self.here.objectValues
+        kw = copy(params)
+      else:
+        # building a complex query so we should not pass too many variables
+        kw={}
+        if self.REQUEST.form.has_key('portal_type'):
+          kw['portal_type'] = self.REQUEST.form['portal_type']
+        elif self.REQUEST.has_key('portal_type'):
+          kw['portal_type'] = self.REQUEST['portal_type']
+        elif self.filtered_portal_types is not None:
+          kw['portal_type'] = self.filtered_portal_types
+        elif kw.has_key('portal_type'):
+          if kw['portal_type'] == '':
+            del kw['portal_type']
+
+        # remove useless matter
+        for cname in self.params.keys():
+          if self.params[cname] != '' and self.params[cname] != None:
+            kw[cname] = self.params[cname]
+
+        # try to get the method through acquisition
+        try:
+          self.list_method = getattr(self.here, self.list_method.method_name)
+        except (AttributeError, KeyError):
+          pass
+    elif self.list_method in (None,''):
+      # use current selection
+      self.list_method = None
+
+
+
+    ##################################################
+    ############ BUILDING REPORT_TREE ################
+    ##################################################
+
+    # assuming result is report tree, building it
+    # When building the body, need to go through all report lines
+    # each report line is a tuple of the form :
+    #(selection_id, is_summary, depth, object_list, object_list_size, is_open)
+    default_selection_report_path = self.report_root_list[0][0].split('/')[0]
+    if (default_selection_report_path in portal_categories.objectIds()) or \
+      (portal_domains is not None and default_selection_report_path in \
+       portal_domaind.objectIds()):
+      pass
+    else:
+      default_selection_root_path = self.report_root_list[0][0]
+    selection_report_path = self.selection.getReportPath(default = \
+     (default_selection_report_path,))
+
+    # testing report_depth value
+    if report_depth is not None:
+      selection_report_curent = ()
+    else:
+      selection_report_current = self.selection.getReportList()
+
+    # building report_tree_list
+    report_tree_list = makeTreeList(here=self.here, form=self.form, root_dict=None,
+     report_path=selection_report_path, base_category=None, depth=0,
+     unfolded_list=selection_report_current, selection_name=self.selection_name,
+     report_depth=report_depth,is_report_opened=is_report_opened,
+     sort_on=self.selection.sort_on,form_id=self.form.id)
+
+    # update report list if report_depth was specified
+    if report_depth is not None:
+      report_list = map(lambda s:s[0].getRelativeUrl(), report_tree_list)
+      self.selection.edit(report_list=report_list)
+
+
+
+    ##################################################
+    ########### BUILDING REPORT_GROUPS ###############
+    ##################################################
+    # report_groups is another structure based on report_tree but
+    # taking care of the object activities.
+    # build two structures :
+    # - report_groups : list of object_tree_lines composing the planning,
+    #   whatever the current group depth, just listing all of them
+    # - blocks_object : dict (object_tree_line.getObject()) of objects
+    # (assuming objects is a list of activities).
+
+    # first init parameters
+    self.report_groups = []
+    list_object = []
+    self.nbr_groups=0
+    object_list=[]
+    self.report_activity_dict = {}
+    indic_line=0
+    index_line=0
+    blocks_object={}
+    select_expression = ''
+
+
+    # now iterating through object_tree_list
+    for object_tree_line in report_tree_list:
+      # prepare query by defining selection report object
+      self.selection.edit(report = object_tree_line.getSelectDomainDict())
+
+      if object_tree_line.getIsPureSummary():
+        # push new select_expression
+        original_select_expression = kw.get('select_expression')
+        kw['select_expression'] = select_expression
+        self.selection.edit(params = kw)
+        # pop new select_expression
+        if original_select_expression is None:
+          del kw['select_expression']
+        else:
+          kw['select_expression'] = original_select_expression
+
+      if (object_tree_line.getIsPureSummary() and \
+         selection_report_path[0]=='parent'):
+        # object_tree_line is Pure summary : does not have any activity
+        stat_result = {}
+        index=1
+        # adding current line to report_section where
+        # line is pure Summary
+        self.report_groups += [object_tree_line]
+        self.nbr_groups = self.nbr_groups + 1
+
+      else:
+        # object_tree_line is not pure summary : it has activities
+        # prepare query
+        self.selection.edit(params = kw)
+
+
+        if self.list_method not in (None,''):
+          # valid list_method has been found
+          self.selection.edit(exception_uid_list= \
+             object_tree_line.getExceptionUidList())
+          object_list = self.selection(method = self.list_method,
+             context=self.here, REQUEST=self.REQUEST)    
+        else:
+          # no list_method found
+          object_list = self.here.portal_selections.getSelectionValueList(
+            self.selection_name, context=self.here, REQUEST=self.REQUEST)
+
+
+        exception_uid_list = object_tree_line.getExceptionUidList()
+        if exception_uid_list is not None:
+          # Filter folders if parent tree :
+          # build new object_list for current line
+          # (list of relative elements)
+          new_object_list = []
+          for selected_object in object_list:
+            if selected_object.getUid() not in exception_uid_list:
+              new_object_list.append(selected_object)
+          object_list = new_object_list
+
+        object_list = []
+        add=1
+
+        # comparing report_groups'object with object_tree_line to check
+        # if the object is already present.
+        # this has to be done as there seems to be a 'bug' with make_tree_list
+        # returning two times the same object...
+        for object in self.report_groups:
+          if getattr(object_tree_line.getObject(),'uid') == \
+           getattr(object.getObject(),'uid'):
+            # object already present, flag <= 0 to prevent new add
+            add=0
+            break
+        if add == 1: # testing : object not present, can add it
+          # adding current line to report_section where
+          # line is report_tree
+          self.report_groups += [object_tree_line]
+          self.nbr_groups += 1
+          for p_object in object_list:
+            #iterating and adding each object to current_list
+            object_list.append(p_object)
+          self.report_activity_dict[object_tree_line.getObject().getTitle()] = object_list
+
+    self.selection.edit(report=None)
+
+
+    ##################################################
+    ########### GETTING MAIN AXIS BOUNDS #############
+    ##################################################
+    # before building group_object structure, need to recover axis begin & end
+    # for main to be able to generate a 'smart' structure taking into account
+    # only the area that need to be rendered. This prevents from useless processing
+
+    # calculating main axis bounds
+    self.getMainAxisInfo(self.main_axis_info)
+
+    # applying main axis selection
+    self.report_groups = self.report_groups[self.main_axis_info['bound_start']:
+                                            self.main_axis_info['bound_stop']]
+
+
+    ##################################################
+    ############ GETTING SEC AXIS BOUNDS #############
+    ##################################################
+    # now that our report_group structure has been cut need to get secondary axis
+    # bounds to add only the blocs needed afterwards
+
+    # getting secondary_axis_occurence to define begin and end secondary_axis
+    # bounds (getting absolute size)
+    self.secondary_axis_occurence = self.getSecondaryAxisOccurence()
+
+
+    # now getting start & stop bounds (getting relative size to the current
+    # rendering)
+    self.getSecondaryAxisInfo(self.secondary_axis_info)
+
+
+
+    ##################################################
+    ####### SAVING NEW PROPERTIES INTO REQUEST #######
+    ##################################################
+    if self.list_method is not None and self.render_format != 'list':
+     self.selection.edit(params = self.params)
+     self.here.portal_selections.setSelectionFor(self.selection_name, self.selection, REQUEST = self.REQUEST)
+
+
+    ##################################################
+    ######### BUILDING GROUP_OBJECT STRUCTURE ########
+    ##################################################
+    # building group_object structure using sub lines depth (in case of a
+    # report tree) by doing this.
+    # taking into account page bounds to generate only the structure needed
+
+    # instanciate BasicGroup class in BasicStructure so that the structure can
+    # be built
+    self.buildGroupStructure()
+
+
+  def getSecondaryAxisOccurence(self):
+    """
+    get secondary_axis occurences in order to define begin and end bounds
+    """
+    secondary_axis_occurence = []
+
+    # specific start & stop methods name for secondary axis
+    start_method_id = self.field.get_value('x_start_bloc')
+    stop_method_id= self.field.get_value('x_stop_bloc')
+    for object_tree_group in self.report_groups:
+      # recover method to et begin and end limits
+      method_start = getattr(object_tree_group.getObject(),start_method_id,None)
+      method_stop = getattr(object_tree_group.getObject(),stop_method_id,None)
+
+      try:
+        child_activity_list = self.report_activity_dict[object_tree_group.title]
+      except AttributeError:
+        child_activity_list = None
+
+      if method_start == None and child_activity_list != None:
+        # can not recover method from object_tree_group itself, trying
+        # over the activity list
+        for child_activity in child_activity_list:
+          method_start = getattr(child_activity,start_method_id,None)
+          method_stop = getattr(child_activity,stop_method_id,None)
+          if method_start != None:
+            block_begin = method_start()
+          else:
+            block_begin = None
+
+          if method_stop != None:
+            block_stop = method_stop()
+          else:
+            block_stop = None
+
+          secondary_axis_occurence.append([block_begin,block_stop])
+
+      else:
+        # method sucessfully recovered
+        # getting values
+        if method_start != None:
+          block_begin = method_start()
+        else:
+          block_begin = None
+
+        if method_stop != None:
+          block_stop = method_stop()
+        else:
+          block_stop = None
+
+        secondary_axis_occurence.append([block_begin,block_stop])
+
+    return secondary_axis_occurence
+
+
+  def getSecondaryAxisInfo(self, axis_dict):
+    """
+    secondary_axis_ocurence holds couples of data (begin,end) related to
+    basicActivity blocks, and axis if the instance representing the sec axis.
+    it is now possible to recover begin and end value of the planning and then
+    apply selection informations to get start and stop.
+    """
+
+    #pdb.set_trace()
+
+
+    axis_dict['zoom_start'] = int(self.params.get('zoom_start',0))
+    axis_dict['zoom_level'] = float(self.params.get('zoom_level',1))
+
+    # recovering min and max bounds to get absolute bounds
+    axis_dict['bound_begin'] = self.secondary_axis_occurence[0][0]
+    axis_dict['bound_end'] = axis_dict['bound_begin']
+    for occurence in self.secondary_axis_occurence:
+      if occurence[0] < axis_dict['bound_begin']:
+        axis_dict['bound_begin'] = occurence[0]
+      if occurence[1] > axis_dict['bound_end']:
+        axis_dict['bound_end'] = occurence[1]
+    import pdb; pdb.set_trace()
+    axis_dict['bound_range'] = axis_dict['bound_end'] - axis_dict['bound_begin']
+    # now start and stop have the extreme values of the second axis bound.
+    # this represents in fact the size of the Planning
+
+    # can now getting selection informations ( float range 0..1)
+    axis_dict['bound_start'] = 0
+    axis_dict['bound_stop'] = 1
+    if self.selection != None:
+      try:
+        axis_dict['bound_start'] = self.selection.getSecondaryAxisStart()
+        axis_dict['bound_stop'] = self.selection.getSecondaryAxisStop()
+      except AttributeError: #XXX
+        pass
+
+    # getting secondary axis page step
+    axis_zoom_step = axis_dict['bound_range'] / axis_dict['zoom_level']
+
+    # now setting bound_start
+    axis_dict['bound_start'] = axis_dict['zoom_start'] * axis_zoom_step + axis_dict['bound_begin']
+    # for bound_stop just add page step
+    axis_dict['bound_stop'] = axis_dict['bound_start'] + axis_zoom_step
+
+    # saving current zoom values
+    self.params['zoom_level'] = axis_dict['zoom_level']
+    self.params['zoom_start'] = axis_dict['zoom_start']
+
+
+  def getMainAxisInfo(self, axis_dict):
+    """
+    getting main axis properties (total pages, current page, groups per page)
+    and setting selection bounds (start & stop).
+    beware this justs calculate the position of the first group present on the
+    page (same for the last one), applying the selection is another thing in
+    case of report tree (if the first element is a sub group of a report for
+    example).
+    """
+
+    #pdb.set_trace()
+    # recovering number of groups displayed per page
+    axis_dict['bound_axis_groups'] = self.REQUEST.get('list_lines',None)
+    if axis_dict['bound_axis_groups'] == None:
+      # XXX default value is 10:
+      axis_dict['bound_axis_groups'] = self.params.get('list_lines',10)
+
+    
+    # setting begin & end bounds
+    axis_dict['bound_begin'] = 0
+    axis_dict['bound_end'] = len(self.report_groups)
+    if self.render_format == 'list':
+      axis_dict['bound_start'] = 0
+      axis_dict['bound_stop'] = axis_dict['bound_end']
+      axis_dict['bound_page_total'] = 1
+      axis_dict['bound_page_current'] = 1
+      axis_dict['bound_page_groups'] = 1
+    else:
+      # recovering first group displayed on actual page
+      try:
+        # trying to recover from REQUEST
+        axis_dict['bound_start'] = self.REQUEST.get('list_start')
+        axis_dict['bound_start'] = int(axis_dict['bound_start'])
+      except (AttributeError, TypeError):
+        # recovering from params is case failed with REQUEST
+        axis_dict['bound_start'] = self.params.get('list_start',0)
+        if type(axis_dict['bound_start']) is type([]):
+          axis_dict['bound_start'] = axis_dict['bound_start'][0]
+        axis_dict['bound_start'] = int(axis_dict['bound_start'])
+      axis_dict['bound_start'] = max(axis_dict['bound_start'],0)
+
+      if axis_dict['bound_start'] > axis_dict['bound_end']:
+        # new report_group is so small that previous if after the last element
+        axis_dict['bound_start'] = axis_dict['bound_end']
+
+      # updating start position to fit page size.
+      axis_dict['bound_start'] -= (axis_dict['bound_start'] % axis_dict['bound_axis_groups'])
+
+      # setting last group displayed on page
+      axis_dict['bound_stop'] = min (axis_dict['bound_start'] + axis_dict['bound_axis_groups'], axis_dict['bound_end'])
+      # calculating total number of pages
+      axis_dict['bound_page_total'] = int(max(axis_dict['bound_end'] - 1,0) / axis_dict['bound_axis_groups']) + 1
+      # calculating current page number
+      axis_dict['bound_page_current'] = int(axis_dict['bound_start'] / axis_dict['bound_axis_groups']) + 1
+      # adjusting first group displayed on current page
+      axis_dict['bound_start'] = min(axis_dict['bound_start'], max(0, (axis_dict['bound_page_total']-1) * axis_dict['bound_axis_groups']))
+    
+      self.params['list_lines'] = axis_dict['bound_axis_groups']
+      self.params['list_start'] = axis_dict['bound_start']
+
+
+  def buildGroupStructure(self):
+      """
+      this procedure builds BasicGroup instances corresponding to the
+      report_group_objects returned from the ERP5 request.
+      """
+      position = 0
+
+      # iterating each element
+      for report_group_object in self.report_groups:
+
+        stat_result = {}
+        stat_context = report_group_object.getObject().asContext(**stat_result)
+        stat_context.domain_url = report_group_object.getObject().getRelativeUrl()
+        stat_context.absolute_url = lambda x: report_group_object.getObject().absolute_url()
+        url=getattr(stat_context,'domain_url','')
+        # updating position_informations
+        position +=1
+        # recovering usefull informations
+        title = report_group_object.getObject().getTitle()
+        name = report_group_object.getObject().getTitle()
+        depth = report_group_object.getDepth()
+        is_open = report_group_object.is_open
+        is_pure_summary = report_group_object.is_pure_summary
+
+        # creating new group_object with all the informations collected
+        child_group = BasicGroup( title=title, name=name, url=url, constraints=None, depth=depth, position=position, field =self.field, object=report_group_object, is_open=is_open, is_pure_summary=is_pure_summary)
+
+        # creating activities related to the new group
+        # first recovering activity list if exists
+        report_activity_list = []
+        if title in self.report_activity_dict.keys():
+          report_activity_list = self.report_activity_dict[child_group.title]
+        # linking activities to the bloc. the parameter is a list of elements
+        # to link to the child_group object.
+        child_group.setBasicActivities(report_activity_list,self.list_error,self.secondary_axis_info)
+
+        try:
+          self.basic_group_list.append(child_group)
+        except (AttributeError):
+          self.basic_group_list = []
+          self.basic_group_list.append(child_group)
+
+
+
+
+class BasicGroup:
+  """
+  A BasicGroup holds informations about an ERP5Object and is stored
+  exclusively in BasicStructure. for each activity that will need to be
+  represented in the PlanningBox, a BasicActivity is created and added to
+  the current structure (for example BasicGroup represents an employee,
+  and each BasicActivity represents a task the employee has).
+  *Only one BasicGroup present while in Calendar mode.
+  *BasicGroup instance itself can hold other BasicGroups in case of
+  ReportTree mode to handle child groups.
+  """
+
+  def __init__ (self, title='', name='', url='', constraints='', depth=0, position=0, field = None, object = None, is_open=0, is_pure_summary=1):
+    self.title = title
+    self.name = name
+    self.url = url
+    self.basic_group_list = None # used with ReportTree
+    self.basic_activity_list = None # bloc activities
+    self.constraints = constraints# global contraints applying to all group
+    self.depth = depth # depth of the actual group (report_tree mode)
+    self.position = position # position of current group in the selection
+    self.field = field # field object itself. used for several purposes
+    self.object = object # ERP5 object returned & related to the group
+    self.is_open = is_open # define is report is opened  or not
+    self.is_pure_summary = is_pure_summary # define id report is single or has sons
     
-    # list_object is the variable that contains all the structure of the graphic.
-    # Basically, it a list a Line Object.
-    list_object=[]
-    selection = here.portal_selections.getSelectionFor(selection_name, REQUEST=REQUEST)
-    default_params = {}
-    if selection is None:
-      selection = Selection(params=default_params, default_sort_on = sort)
+    # specific start and stop bound values specifiec to the current group and used
+    # in case of calendar mode
+    self.start = None
+    self.stop = None
+
+
+  def setBasicActivities(self,activity_list, list_error,secondary_axis_info):
+    """
+    link a list of activities to the current object.
+    + recover group properties. Used in case activity is built from Group itself
+    + create a BasicActivity for each activity referenced in the list if 
+      necessary
+    + add the activity to the current group.
+    + update secondary_axis_occurence
+    """
+
+    # specific color scriptactivity
+    color_script = getattr(self, self.field.get_value('color_script'),None)
+
+    # specific block text_information methods
+    info_center = self.field.get_value('info_center')
+    info_topleft = self.field.get_value('info_topleft')
+    info_topright = self.field.get_value('info_topright')
+    info_backleft = self.field.get_value('info_backleft')
+    info_backright = self.field.get_value('info_backright')
+
+    # specific begin & stop methods for secondary axis
+    object_begin_method_id = self.field.get_value('x_start_bloc')
+    object_end_method_id= self.field.get_value('x_stop_bloc')
+
+    info = {}
+
+
+    # recover method to et begin and end limits
+    method_begin = getattr(self.object.getObject(),object_begin_method_id,None)
+    method_end = getattr(self.object.getObject(),object_end_method_id,None)
+
+    # getting info method from activity itself if exists
+    info_center_method = getattr(self.object.getObject(),info_center,None)
+    info_topright_method = getattr(self.object.getObject(),info_topright,None)
+    info_topleft_method = getattr(self.object.getObject(),info_topleft,None)
+    info_backleft_method = getattr(self.object.getObject(),info_backleft,None)
+    info_backright_method = getattr(self.object.getObject(),info_backright,None)
+
+    # if method recovered is not null, then updating 
+    if info_center_method!=None: info['info_center']=str(info_center_method())
+    if info_topright_method!=None: info['info_topright']=str(info_topright_method())
+    if info_topleft_method!=None: info['info_topleft']=str(info_topleft_method())
+    if info_backleft_method!=None: info['info_backleft'] =str(info_backleft_method())
+    if info_backright_method!=None: info['info_backright']=str(info_backright_method())
+
+
+    # calling color script if exists to set up activity_color
+    current_color=''
+    if color_script !=None:
+      current_color = color_script(self)
+
+    if method_begin == None and activity_list not in ([],None):
+
+      # modifying iterating mode from original PlanningBox.py script to prevent
+      # useless and repetitive tests.
+      # this process should be somehow quicker and smarter
+      indic=0
+
+      # iterating each activity linked to the current group
+      for activity_content in activity_list:
+
+        # group does not have valid begin_method, trying to find them on
+        # the activity itself.
+        method_begin = getattr(activity_content,object_begin_method_id,None)
+        method_end = getattr(activity_content,object_end_method_id,None)
+
+
+        # interpreting results and getting begin and end values from 
+        # previously recovered method
+        block_begin = ''
+        block_end = ''
+        if method_begin !=None:
+          block_begin = method_begin()
+        else:
+          block_begin = None
+
+        if method_end != None:
+          block_end = method_end()
+        else:
+          block_end = None
+
+        # testing if activity is visible according to the current zoom selection over
+        # the secondary_axis
+        if  block_begin > secondary_axis_info['bound_stop'] or block_end < secondary_axis_info['bound_start']:
+          # activity will not be displayed, stopping process
+          pass
+        else:
+          # activity is somehow displayed. checking if need to cut its bounds
+          if block_begin < secondary_axis_info['bound_start']:
+            # need to cut begin bound
+            block_start = secondary_axis_info['bound_start']
+          else: block_start = block_begin
+
+          if block_end > secondary_axis_info['bound_stop']:
+            block_stop = secondary_axis_info['bound_stop']
+          else:
+            block_stop = block_end
+
+          # defining name
+          name = "Activity_%s_%s" % (self.object.getObject().getTitle(),str(indic))
+
+          # getting info text from activity itself if exists
+          info_center_method = getattr(activity_content,info_center,None)
+          info_topright_method = getattr(activity_content,info_topright,None)
+          info_topleft_method = getattr(activity_content,info_topleft,None)
+          info_backleft_method = getattr(activity_content,info_backleft,None)
+          info_backright_method = getattr(activity_content,info_backright,None)
+
+          # if value recovered is not null, then updating 
+          if info_center_method!=None: info['info_center']=str(info_center_method())
+          if info_topright_method!=None: info['info_topright']=str(info_topright_method())
+          if info_topleft_method!=None: info['info_topleft']=str(info_topleft_method())
+          if info_backleft_method!=None: info['info_backleft'] =str(info_backleft_method())
+          if info_backright_method!=None: info['info_backright']=str(info_backright_method())
+
+          # calling color script if exists to set up activity_color
+          current_color=''
+          if color_script !=None:
+            current_color = color_script(activity_content)
+
+          # testing if some activities have errors
+          error = 'false'
+          if list_error !=None:
+            for activity_error in list_error:
+              if activity_error[0][0] == name:
+                error = 'true'
+                break
+
+
+          # creating new activity instance
+          activity = BasicActivity(title=info['info_center'],name=name, url=self.url,absolute_begin=block_begin, absolute_end=block_end,color = current_color, info_dict=info, error=error)
+
+
+          # adding new activity to personal group activity list
+          try:
+            self.basic_activity_list.append(activity)
+          except (AttributeError):
+            self.basic_activity_list = []
+            self.basic_activity_list.append(activity)
+          # incrementing indic used for differenciating activities in the same 
+          # group (used for Activity naming)
+          indic += 1
+
+
     else:
-      selection.edit(default_sort_on = sort)
-      selection.edit(sort_on = sort)       
-    here.portal_selections.setSelectionFor(selection_name, selection, REQUEST=REQUEST)
-    current_top = height_header
-    #we check what is the current zoom in order to redefine height & width
-    current_zoom = selection.getZoom()
-    current_zoom= float(current_zoom)
-    if current_zoom<=1:
-      height_global_div = round(height_global_div * current_zoom)
-      width_line = round(width_line * current_zoom)
-      space_line = round(space_line * current_zoom)  
-    #we build line
-    (list_object,nbr_line,report_sections,blocks_object)=createLineObject(meta_types=meta_types,
-                                                            selection=selection,
-                                                            selection_name=selection_name,field=field,
-                                                            REQUEST=REQUEST,list_method=list_method,
-                                                            here=here,report_root_list=report_root_list,
-                                                            y_axis_width=y_axis_width,width_line=width_line,
-                                                            space_line=space_line,
-                                                            height_global_div=height_global_div,
-                                                            height_header=height_header,
-                                                            height_axis_x=height_axis_x,form=form,
-                                                            current_top=current_top,portal_types=portal_types)
-    # blocks_object is a dictionnary that contains all informations used for building blocks of each line
- 
-    #we build x_occurence (used for the range in x-Axis 
-    x_occurence=[]
-    #report_sections contains treeListLine instance objects
-    for treelistobject in report_sections: 
-      method_start = getattr(treelistobject.getObject(),object_start_method_id,None)
-      method_stop= getattr(treelistobject.getObject(),object_stop_method_id,None)
-      if method_start!=None:
-        block_begin = method_start()
+
+      # getting begin and end values from previously recovered method
+      if method_begin !=None:
+        block_begin = method_begin()
       else:
         block_begin = None
-      
-      if method_stop!=None:
-        block_stop= method_stop()
+
+      if method_end != None:
+        block_end = method_end()
       else:
-        block_stop=None
-      if block_begin != None: 
-       x_occurence.append([block_begin,block_stop])
-      #if method start is None it means that we construct the graphic with informations contained
-      #in blocks_object. 
-      if method_start == None and report_sections!={}:
-        for Ablock in blocks_object:
-          #object_content is the current object used for building a block.
-          #For instance if the context is a project, then object_content is an orderLine.
-          for object_content in blocks_object[Ablock]:
-            method_start = getattr(object_content,object_start_method_id,None)
-            method_stop= getattr(object_content,object_stop_method_id,None)
-              
-            if method_start!=None:
-              block_begin = method_start()
-            else:
-              block_begin = None
-            
-            if method_stop!=None:
-              block_stop= method_stop()
-            else:
-              block_stop=None
-              
-            if block_begin!=None:# and block_stop!=None:
-              x_occurence.append([block_begin,block_stop])
-          
-      params=selection.getParams()
-      start=params.get('list_start')
-      
-      x_axe=script(x_occurence,x_range,float(current_zoom),start)
-      y_max= 1
-      current_max = 1
-      #this part is used for determining the maximum through datas fetched via scriptY
-      #y_max is used when blocks have different height.
-      if scriptY != None:
-        for s in report_sections:
-          current_max=scriptY(s.getObject())
-          if current_max > y_max:
-            y_max = current_max
+        block_end = None
+
+      # testing if activity is visible according to the current zoom selection over
+      # the secondary_axis
+      if  block_begin > secondary_axis_info['bound_stop'] or block_end < secondary_axis_info['bound_start']:
+        # activity will not be displayed, stopping process
+        pass
       else:
-        y_max = 1
-      indic_line=0
-      while indic_line != len(report_sections):
-        # o is a Line object, for each line, we add its blocks via insertActivityBlock
-        for o in list_object:
-          if o.title == report_sections[indic_line].getObject().getTitle():
-            if list_object != [] and report_sections[indic_line].getDepth()==0:
-              o.insertActivityBlock(line_content=report_sections[indic_line].getObject(),
-                                    object_start_method_id=object_start_method_id,
-                                    object_stop_method_id=object_stop_method_id,
-                                    x_axe=x_axe,field=field,info_center=info_center,
-                                    info_topright=info_topright,info_topleft=info_topleft,
-                                    info_backleft=info_backleft,info_backright=info_backright,
-                                    list_error=list_error,old_delta=['None','None'],REQUEST=REQUEST,
-                                    blocks_object=blocks_object,width_line=width_line,
-                                    script_height_block=block_height,y_max=y_max,color_script=color_script)                                                      
+        # activity is somehow displayed. checking if need to cut its bounds
+        if block_begin < secondary_axis_info['bound_start']:
+          # need to cut begin bound
+          block_start = secondary_axis_info['bound_start']
+        else: block_start = block_begin
+
+        if block_end > secondary_axis_info['bound_stop']:
+          block_stop = secondary_axis_info['bound_stop']
+        else:
+          block_stop = block_end
+
+        # testing if some activities have errors
+        error = 'false'
+        if list_error !=None:
+          for activity_error in list_error:
+            if activity_error[0][0] == name:
+              error = 'true'
               break
-        indic_line+=1 
-    
-    #  the structure is now rebuilt
-    block_moved = [] 
-    bloc_and_line=[] # store the line and the coordinates of block moved
-    if bmoved != '':
-      block_moved=convertStringToList(bmoved)
+
+        # defining name
+        name = "Activity_%s" % (self.object.getObject().getTitle())
+
+        # creating new activity instance
+        activity = BasicActivity(title=info['info_center'],name=name, url=self.url, absolute_begin=block_begin, absolute_end=block_end, absolute_start=block_start, absolute_stop=block_stop,color = current_color, info_dict=info, error=error)
+
+        # adding new activity to personal group activity list
+        try:
+          self.basic_activity_list.append(activity)
+        except (AttributeError):
+          self.basic_activity_list = []
+          self.basic_activity_list.append(activity)
+
+
+
+
+
+class BasicActivity:
+  """ Represents an activity, a task, in the group it belongs to. Beware
+      nothing about multitask rendering. """
+
+  def __init__ (self, title='', name='', url='', absolute_begin=None,
+    absolute_end=None,absolute_start=None,absolute_stop=None, constraints='', color=None, error='false', info_dict= None):
+    self.title = title
+    self.name = name
+    self.url = url
+    self.absolute_begin = absolute_begin # absolute values independant of any
+                                         # hypothetic zoom
+    self.absolute_end = absolute_end
+    self.absolute_start = absolute_start
+    self.absolute_stop = absolute_stop
+    self.constraints = constraints# constraints specific to the current Activity
+    self.color = color
+    self.info_dict = info_dict
+    self.error = error
+
+
+
+
+class PlanningStructure:
+  """ class aimed to generate the Planning final structure, including :
+      - activities with their blocs (so contains Activity structure)
+      - Axis informations (contains Axis Structure).
+      The zoom properties on secondary axis are applied to this structure.
+      """
+
+
+  def __init__ (self,):
+    self.main_axis = ''
+    self.secondary_axis = ''
+    self.content = []
+    self.content_delimiters = None
+
+
+  def build(self,basic_structure=None, field=None, REQUEST=None):
+    """
+    main procedure for building Planning Structure
+    do all the necessary process to construct a full Structure compliant with all
+    expectations (axis, zoom, colors, report_tree, multi_lines, etc.). From this
+    final structure just need to run a PageTemplate to get an HTML output, or any
+    other script to get the Planning result in the format you like...
+    """
+
+    # XXX defining render_format
+    # afterwards will be defined as a planningBox's property field or (perhaps even better)
+    # a on the fly button integrated over the planning representation 
+    #render_format = field.get_value('render_format')
+    self.render_format = 'YX'
+
+    # declaring main axis
+    self.main_axis = Axis(title='main axis', name='axis',
+                     unit='', axis_order=1,axis_group=[])
+
+    # declaring secondary axis
+    self.secondary_axis = Axis(title='sec axis', name='axis',
+                     unit='', axis_order=2, axis_group=[])
+
+    # linking axis objects to their corresponding accessor, i.e X or Y
+    # this allows the planning to be generic.
+    if self.render_format == 'YX':
+      self.Y = self.main_axis
+      self.X = self.secondary_axis
     else:
-      return ''
-    
-    # When a block is moved, we fetch its object Line and its corresponding object Blocks*
-    # via returnBlock 
-    for current_block in block_moved:
-      bloc_and_line=returnBlock(current_block,list_object,bloc_and_line)
-    
-    #At this point, we know which blocks have moved and the line they belong  
-    #IMPORTANT INFORMATION ABOUT RECORD:
-    #There is a problem with absolute and relative coordinates, that is why we do not
-    #directly use coordinates from bmoved, but only 'delta' which allows to find correct
-    #coordinates 
-    my_field = None
-    prev_delta='' #we store the current delta in a formated string
-    list_block_error = []
-    errors = []
-    error_result = {}
-    prev_deltaX=0
-    prev_deltaY=0
-    deltaX = 0 
-    deltaY = 0 
-    correct = 1 # correct = 1 if the block is correct otherwise correct = 0
-    new_object_planning = {} #structure returned
-    for mblock in bloc_and_line:
-      if old_delta2!=None:
-        # For each block that has moved, we add its former coordinates and its delta
-        if old_delta2.has_key(mblock[1].name):
-          prev_deltaX=float(old_delta2[mblock[1].name][0])
-          prev_deltaY=float(old_delta2[mblock[1].name][1])
-      deltaX =float(mblock[0][3]) - float(mblock[0][1])+prev_deltaX 
-      deltaY = float(mblock[0][4]) - float(mblock[0][2])+prev_deltaY
-      widthblock= float(mblock[0][5])
-      heightblock=float(mblock[0][6])
-      if mblock[1].url!='':
-        url = mblock[1].url
-      else:
-        url= mblock[2].url
-      # several test to know if a block is correct. If it is not, wee add it to list_block_error.
-      if mblock[1].begin <0:
-        deltaX = (mblock[1].begin)*mblock[2].width + float(mblock[0][3]) +prev_deltaX
-      # mblock[1] is a  block ; mblock[2] is a line
-      if (mblock[1].marge_top)*mblock[2].height+mblock[2].top+deltaY >mblock[2].top+mblock[2].height:  
-        correct = 0
-      if (mblock[1].marge_top)*mblock[2].height+heightblock+mblock[2].top+deltaY< mblock[2].top:
-        correct = 0
-      if (mblock[1].begin)*mblock[2].width+widthblock+mblock[2].begin+deltaX <mblock[2].begin:
-        correct = 0
-      if (mblock[1].begin)*mblock[2].width + deltaX+ mblock[2].begin> mblock[2].begin + mblock[2].width:
-        correct = 0
-      if correct == 0:
-        list_block_error.append(mblock)
-        err = ValidationError(StandardError,mblock[1])
-        errors.append(err)
-        if prev_delta!='':
-          prev_delta+='*'
-        prev_delta+=str(mblock[1].name)+','+str(deltaX)+','+str(deltaY)
-        # we store once again old_delta because we will need it when a block is moved again.     
+      self.Y = self.secondary_axis
+      self.X = self.main_axis
+
+    # initializing axis properties
+    self.X.name = 'axis_x'
+    self.Y.name = 'axis_y'
+
+
+    # recovering secondary_axis_ bounds
+    self.secondary_axis.start = basic_structure.secondary_axis_info['bound_start']
+    self.secondary_axis.stop = basic_structure.secondary_axis_info['bound_stop']
+
+
+    self.main_axis.size =  self.buildGroups(basic_structure=basic_structure)
+
+    #pdb.set_trace()
+    # call method to build secondary axis structure
+    # need start_bound, stop_bound and number of groups to build
+    self.buildSecondaryAxis(basic_structure)
+
+
+    # completing axisgroup informations according to their bounds
+    self.buildAxis()
+
+    # the whole structure is almost completed : axis_groups are defined, as
+    # axis_elements with their activities. Just need to create blocks related to
+    # the activities (special process only for Calendar mode) with their
+    # BlockPosition
+    self.buildBlocs()
+
+
+  def buildSecondaryAxis(self,basic_structure):
+    """
+    build secondary axis structure
+    """
+    #pdb.set_trace()
+    # getting secondary axis script generator
+    planning_secondary_axis_method = getattr(basic_structure.here,'planning_secondary_axis')
+    # calling script to generate axis_group_list
+    group_list = planning_secondary_axis_method(self.secondary_axis.start, self.secondary_axis.stop, 4)
+    axis_group_number = 0
+    for group_title in group_list:
+      # adding new group to list of groups
+      axis_group = AxisGroup(name='Group_sec_' + str(axis_group_number), title=group_title)
+
+      # updating informations
+      axis_group.axis_element_start = axis_group_number
+      axis_group.axis_element_number = 1
+      axis_group.axis_element_stop  = axis_group_number + 1
+
+      self.secondary_axis.axis_group.append(axis_group)
+      axis_group = None
+      axis_group_number += 1
+
+
+  def buildAxis (self):
+    """
+    complete axis infomations (and more precisely axis position objects) thanks
+    to the actual planning structure
+    """
+
+    # processing main axis
+    for axis_group_element in self.main_axis.axis_group:
+      axis_group_element.position_main.absolute_begin = float(axis_group_element.axis_element_start - 1) / float(self.main_axis.size)
+      axis_group_element.position_main.absolute_end = float(axis_group_element.axis_element_stop) / float(self.main_axis.size)
+      axis_group_element.position_main.absolute_range = float(axis_group_element.axis_element_number) / float(self.main_axis.size)
+      axis_group_element.position_secondary.absolute_begin = 0
+      axis_group_element.position_secondary.absolute_end = 1
+      axis_group_element.position_secondary.absolute_range= 1
+
+    for axis_group_element in self.secondary_axis.axis_group:
+      axis_group_element.position_main.absolute_begin = 0
+      axis_group_element.position_main.absolute_end = 1
+      axis_group_element.position_main.absolute_range= 1
+      axis_group_element.position_secondary.absolute_begin = float(axis_group_element.axis_element_start) / float(len(self.secondary_axis.axis_group))
+      axis_group_element.position_secondary.absolute_end = float(axis_group_element.axis_element_stop) / float(len(self.secondary_axis.axis_group))
+      axis_group_element.position_secondary.absolute_range= float(1) / float(len(self.secondary_axis.axis_group))
+
+
+  def buildGroups (self, basic_structure=None):
+    """
+    build groups from activities saved in the structure groups.
+    """
+    axis_group_number = 0
+    axis_element_already_present=0
+    for basic_group_object in basic_structure.basic_group_list:
+      axis_group_number += 1
+      axis_group = AxisGroup(name='Group_' + str(axis_group_number), title=basic_group_object.title, AxisGroup_number= axis_group_number, is_open=basic_group_object.is_open, is_pure_summary=basic_group_object.is_pure_summary, url = basic_group_object.url,depth = basic_group_object.depth, secondary_axis_start= self.secondary_axis.start, secondary_axis_stop= self.secondary_axis.stop)
+      if self.render_format == 'YX':
+        axis_group.position_y = axis_group.position_main
+        axis_group.position_x = axis_group.position_secondary
       else:
-        new_object_planning = convertDataToDate(mblock,x_axe,width_line, deltaX, 
-                                                deltaY, url, new_object_planning,lineb)  
-    REQUEST.set('list_block_error',list_block_error)
-    REQUEST.set('old_delta1',prev_delta)
-    if len(errors)>0:
-      raise FormValidationError(errors,{})
-    return new_object_planning
-
-def convertDataToDate(mblock,x_axe,width_line, deltaX, deltaY, object_url,
-                      new_object_planning, lineb):                 
-  """this is in this method that we calculate new startdate & stopdate in order 
-     to save them"""  
-  delta_axe = (DateTime(x_axe[0][-1])-DateTime(x_axe[0][0]))
-  #lineb is used to know where really starts the line due to problems with others html tags.
-  begin = (mblock[2].begin - float(mblock[0][3])+(float(lineb)-mblock[2].begin))*(-1)
-  length = float(mblock[0][5])
-  axe_begin = DateTime(x_axe[0][0])
-  coeff = float(delta_axe) / float(mblock[2].width)
-  delta_start = begin * coeff
-  delta_length = length * coeff
-  new_start = axe_begin + delta_start
-  new_stop=new_start + delta_length
-  new_object_planning[object_url]={'start_date':new_start,'stop_date':new_stop}
-  return new_object_planning    
-
-
-PlanningBoxValidatorInstance=PlanningBoxValidator()        
-
-
-def returnBlock(block_searched,planning_struct,block_and_line):
-  """return a specific structre containing the block object and its line 
-   thanks to its name"""
-  for line in planning_struct:
-    for block in line.content:
-      if block.name == block_searched[0]:
-        block_and_line.append([block_searched,block,line])   
-        break
+        axis_group.position_y = axis_group.position_secondary
+        axis_group.position_x = axis_group.position_main
+      # init absolute position over the axis
+      # XXX if a special axisGroup length is needed (statistics, or report_tree),
+      # then it should be implemented here.
+      axis_group.position_secondary.absolute_begin = 0
+      axis_group.position_secondary.absolute_end= 1
+      axis_group.position_secondary.absolute_range = 1
+      # updating axis_group properties
+      axis_group.fixProperties(form_id = basic_structure.form.id, selection_name = basic_structure.selection_name)
+      # updating start value
+      axis_group.axis_element_start = axis_element_already_present + 1
+      activity_number = 0
+      if basic_group_object.basic_activity_list != None:
+        # need to check if activity list is not empty : possible in case zoom
+        # selection is used over the secondary axis
+        for basic_activity_object in basic_group_object.basic_activity_list:
+          activity_number += 1
+          # create new activity in the PlanningStructure
+          activity = Activity(name='Group_' + str(axis_group_number) + '_Activity_' + str(activity_number), title=basic_activity_object.title, color=basic_activity_object.color, link=basic_activity_object.url, secondary_axis_begin=basic_activity_object.absolute_begin, secondary_axis_end=basic_activity_object.absolute_end, secondary_axis_start=basic_activity_object.absolute_start, secondary_axis_stop=basic_activity_object.absolute_stop, primary_axis_block=self, info=basic_activity_object.info_dict, render_format=self.render_format)
+          # adding activity to the current group
+          axis_group.addActivity(activity,axis_element_already_present)
       else:
-        if line.son!=[]:
-          block_and_line = returnBlock(block_searched,line.son,block_and_line)
-  return block_and_line
-
-def convertStringToList(import_string):
-  """ convert a string from this type 'name,x,y,w,h-name,x,y,w,h...' to a list"""
-  list_moved= []
-  r_List = import_string.split('*')
-  for i in r_List:
-    current_block = i.split(',')
-    list_moved.append(current_block)
-  return list_moved
-
-def convertStringToDict(import_string):
-  """ convert a string from this type name,x1,x2,x,y,w,h*name,x1,x2,x,y,w,h
-      to list of dictionnaries where the key is the name""" 
-  dic={}
-  r_List=import_string.split('*')
-  for i in r_List:
-    current_block = i.split(',')
-    dic[current_block[0]]=[current_block[1],current_block[2]]
-  return dic    
+        # basic_activity_list is empty : need to add a empty axis_element to
+        # prevent bug or crash
+        axis_group.axis_element_number = 1
+        new_axis_element = AxisElement(name='Group_' + str(axis_group_number) + '_AxisElement_1', relative_number= 1 , absolute_number = axis_group.axis_element_start, parent_axis_group=axis_group)
+        # add new activity to this brand new axis_element
+        new_axis_element.activity_list = []
+        axis_group.axis_element_list = []
+        axis_group.axis_element_list.append(new_axis_element)
+        
+      axis_group.axis_element_stop = axis_element_already_present + axis_group.axis_element_number
+      axis_element_already_present = axis_group.axis_element_stop
+      try:
+        self.main_axis.axis_group.append(axis_group)
+      except AttributeError:
+        self.main_axis.axis_group = []
+        self.main_axis.axis_group.append(axis_group)
+    return axis_element_already_present
 
-  
-def createLineObject(meta_types,selection,selection_name,field,REQUEST,list_method,
-                     here,report_root_list,y_axis_width,width_line,space_line,
-                     height_global_div,height_header,height_axis_x,form,current_top,portal_types):
-  """creates Line Object and stores it in list_object"""
-  report_sections = []
-  filtered_portal_types = map(lambda x: x[0], portal_types)
-  if len(filtered_portal_types) == 0:
-    filtered_portal_types = None
-  section_index = 0
-  if len(report_sections) > section_index:
-    current_section = report_sections[section_index]
-  elif len(report_sections):
-    current_section = report_sections[0]
-  else:
-    current_section = None
-  filtered_meta_types = map(lambda x: x[0], meta_types)
-  params = selection.getParams()
-  sort = field.get_value('sort')
-  selection.edit(default_sort_on = sort)
-  kw=params
-  report_depth = REQUEST.get('report_depth', None)
-  is_report_opened = REQUEST.get('is_report_opened', selection.isReportOpened())
-  portal_categories = getattr(form, 'portal_categories', None)
-  portal_domains = getattr(form, 'portal_domains', None)
-  if 'select_expression' in kw:
-    del kw['select_expression']
-  if hasattr(list_method, 'method_name'):
-    if list_method.method_name == 'objectValues':
-      list_method = here.objectValues
-      kw = copy(params)
-      kw['spec'] = filtered_meta_types
+
+  def buildBlocs(self):
+    """
+    iterate the whole planning structure to get various activities and build
+    their related blocs.
+    """
+    try:
+      for axis_group_object in self.main_axis.axis_group:
+        for axis_element_object in axis_group_object.axis_element_list:
+          for activity in axis_element_object.activity_list:
+            activity.addBlocs(main_axis_start=0, main_axis_stop=self.main_axis.size, secondary_axis_start=self.secondary_axis.start, secondary_axis_stop=self.secondary_axis.stop,planning=self)
+    except TypeError:
+      pass
+
+
+
+
+class Activity:
+  """
+  Class representing a task in the Planning, for example an appointment or
+  a duration. Can be divided in several blocs for being rendered correctly
+  (contains Bloc Structure).
+  Activity instance are not rendered but only their blocs. This Activity
+  structure is used for rebuilding tasks from bloc positions when
+  validating the Planning.
+  """
+  def __init__ (self,name=None,title=None,types=None,color=None,link=None,secondary_axis_begin=None,secondary_axis_end=None,secondary_axis_start=None,secondary_axis_stop=None,primary_axis_block=None, info=None, render_format='YX'):
+    self.name = name # internal activity_name
+    self.title = title # displayed activity_name
+    self.types = types # activity, activity_error, info
+    self.color = color # color used to render all Blocs
+    self.link = link # link to the ERP5 object
+    # self.constraints = constraints
+    self.block_list = None # contains all the blocs used to render the activity
+    self.secondary_axis_begin =secondary_axis_begin
+    self.secondary_axis_end=secondary_axis_end
+    self.secondary_axis_start=secondary_axis_start
+    self.secondary_axis_stop=secondary_axis_stop
+    self.primary_axis_block = primary_axis_block
+    self.block_bounds = None
+    self.info = info
+    self.parent_axis_element = None
+    self.render_format= render_format
+
+
+  def isValidPosition(self, bound_begin, bound_end):
+    """
+    can check if actual activity can fit within the bounds, returns :
+    - 0 if not
+    - 1 if partially ( need to cut the activity bounds to make it fit)
+    - 2 definitely
+    """
+    if self.begin > range_end or self.end < range_begin:
+      return 0
+    elif self.begin > range_begin and self.end < range_end:
+      return 1
     else:
-     # The Catalog Builds a Complex Query
-      kw = {}
-      if REQUEST.form.has_key('portal_type'):
-        kw['portal_type'] = REQUEST.form['portal_type']
-      elif REQUEST.has_key('portal_type'):
-        kw['portal_type'] = REQUEST['portal_type']
-      elif filtered_portal_types is not None:
-        kw['portal_type'] = filtered_portal_types
-      elif filtered_meta_types is not None:
-        kw['meta_type'] = filtered_meta_types
-      elif kw.has_key('portal_type'):
-        if kw['portal_type'] == '':
-          del kw['portal_type']
-      # Remove useless matter
-      for cname in params.keys():
-        if params[cname] != '' and params[cname]!=None:
-          kw[cname] = params[cname]
-      # Try to get the method through acquisition
+      return 2
+
+
+  def addBlocs(self, main_axis_start=None, main_axis_stop=None, secondary_axis_start=None, secondary_axis_stop=None,planning=None):
+    """
+    define list of (begin & stop) values for blocs representing the actual
+    activity (can have several blocs if necessary).
+    """
+
+    # recover list of bounds
+    secondary_block_bounds = self.splitActivity()
+
+    block_number = 0
+    # iterating resulting list
+    for (start,stop) in secondary_block_bounds:
+
+      block_number += 1
+      # create new block instance
+      new_block = Bloc(name=self.name + '_Block_' + str(block_number) ,color=self.color,link=self.link, number = block_number, render_format=self.render_format, parent_activity=self)
+
+      #pdb.set_trace()
+      new_block.buildInfoDict(info_dict = self.info)
+
+      # updating secondary_axis block position
+      new_block.position_secondary.absolute_begin = start
+      new_block.position_secondary.absolute_end = stop
+      new_block.position_secondary.absolute_range = stop - start
+      # updating main_axis block position
+      new_block.position_main.absolute_begin = self.parent_axis_element.absolute_number - 1
+      new_block.position_main.absolute_end = self.parent_axis_element.absolute_number
+      new_block.position_main.absolute_range = new_block.position_main.absolute_end - new_block.position_main.absolute_begin
+
+      # now absolute positions are updated, and the axis values are known
+      # (as parameters), processing relative values
+      new_block.position_secondary.relative_begin = \
+          float(new_block.position_secondary.absolute_begin - secondary_axis_start) / float(secondary_axis_stop - secondary_axis_start)
+      new_block.position_secondary.relative_end = \
+          float(new_block.position_secondary.absolute_end - secondary_axis_start) / float(secondary_axis_stop - secondary_axis_start)
+      new_block.position_secondary.relative_range = \
+          new_block.position_secondary.relative_end - new_block.position_secondary.relative_begin
+      new_block.position_main.relative_begin = \
+          float(new_block.position_main.absolute_begin - main_axis_start) / float(main_axis_stop - main_axis_start)
+      new_block.position_main.relative_end = \
+          float(new_block.position_main.absolute_end - main_axis_start) / float(main_axis_stop - main_axis_start)
+      new_block.position_main.relative_range = \
+          new_block.position_main.relative_end - new_block.position_main.relative_begin
+
       try:
-        list_method = getattr(here, list_method.method_name)
+        self.block_list.append(new_block)
       except AttributeError:
-        pass
-  elif list_method in (None, ''): # Use current selection
-    list_method = None
-  select_expression = ''
-  default_selection_report_path = report_root_list[0][0].split('/')[0]
-  if default_selection_report_path in portal_categories.objectIds() or \
-    (portal_domains is not None and default_selection_report_path in portal_domains.objectIds()):
-    pass
-  else:
-    default_selection_report_path = report_root_list[0][0]          
-  selection_report_path = selection.getReportPath(default = (default_selection_report_path,))
-  if report_depth is not None:
-    selection_report_current = ()
-  else:
-    selection_report_current = selection.getReportList()
-  report_tree_list = makeTreeList(here=here, form=form, root_dict=None,report_path=selection_report_path,
-                                  base_category=None,depth=0, 
-                                  unfolded_list=selection_report_current, selection_name=selection_name, 
-                                  report_depth=report_depth,
-                                  is_report_opened=is_report_opened, sort_on=selection.sort_on,
-                                  form_id=form.id)
-  
-  if report_depth is not None:
-    report_list = map(lambda s:s[0].getRelativeUrl(), report_tree_list)
-    selection.edit(report_list=report_list)
-  report_sections = []
-  list_object = []
-  nbr_line=0
-  object_list=[]    
-  indic_line=0 
-  index_line = 0
-  blocks_object= {}  
-  for object_tree_line in report_tree_list:      
-    selection.edit(report = object_tree_line.getSelectDomainDict())            
-    if object_tree_line.getIsPureSummary():
-      original_select_expression = kw.get('select_expression')
-      kw['select_expression'] = select_expression
-      selection.edit( params = kw )
-      if original_select_expression is None:
-        del kw['select_expression']
-      else:
-        kw['select_expression'] = original_select_expression
+        # in case this is the first add 
+        # need to initialize the list
+        self.block_list = []
+        self.block_list.append(new_block)
+        
+      try:
+        planning.content.append(new_block)
+      except AttributeError:
+        planning.content = []
+        planning.content.append(new_block)
+
+  def splitActivity(self):
+    """
+    Used for splitting an activity in multiple bloc.
+    [EDIT] will not be used to split Calendar axis (by date time depending on
+           the axis size), but will certainly be used afterwards in all cases
+           to split activity in multiple blocs according to some external
+           constraints (do not work sat & sun, or for a dayly planning do not
+           work from 18P.M to 9A.M).
+           will use an external script to do so.
+    """
+    # XXX not implemented yet
+    return [(self.secondary_axis_start,self.secondary_axis_stop)]
+
+
+
+
+class Bloc:
+  """
+  structure that will be rendered as a bloc, a task element.
+  Blocs are referenced in the Activity they belong to (logical structure),
+  but are also referenced in their relative AxisElement (to be able to
+  calculate the number of lines required for rendering when having
+  multi-tasking in parallel).
+  Contains Bloc Structure for position informations.
+  """
+
+  def __init__ (self, name=None, types=None,
+                color=None, info=None, link=None, number=0,
+                constraints=None, secondary_start=None, secondary_stop=None, render_format='YX', parent_activity = None):
+    """
+    creates a Bloc object
+    """
+    self.name = name # internal name
+    self.types = types # activity, activity_error, info
+    self.color = color
+    self.info = info # dict containing text with their position
+    self.link = link # on clic link
+    self.number = number
+    self.title=''
+    self.parent_activity = parent_activity
+    self.constraints = constraints
+    # list of all the groups the bloc belongs to (reportTree)
+    #self.container_axis_group = container_AxisGroup
+    # integer pointing to the AxisElement containing the bloc (multitasking)
+    #self.container_axis_element = container_AxisElement
+    self.position_main = Position()
+    self.position_secondary = Position(absolute_begin=secondary_start,absolute_end=secondary_stop)
+    if render_format == 'YX':
+      self.position_y = self.position_main
+      self.position_x = self.position_secondary
+    else:
+      self.position_y = self.position_secondary
+      self.position_x = self.position_main
+    self.render_dict = None
     
-    if object_tree_line.getIsPureSummary() and selection_report_path[0]=='parent':
-      stat_result = {}
-      index = 1
-      report_sections += [object_tree_line]
-      nbr_line+=1       
+  def buildInfoDict (self, info_dict=[]):
+    """
+    create Info objects to display text & images, then link them to the current object
+    """
+    #XXX /4
+    self.info = {}
+    title_list = []
+    #pdb.set_trace()
+    title_list.append(self.buildInfo(info_dict=info_dict, area='info_topleft'))
+    title_list.append(self.buildInfo(info_dict=info_dict, area='info_topright'))
+    title_list.append(self.buildInfo(info_dict=info_dict, area='info_center'))
+    title_list.append(self.buildInfo(info_dict=info_dict, area='info_botleft'))
+    title_list.append(self.buildInfo(info_dict=info_dict, area='info_botright'))
+    # updating title
+    self.title = " | ".join(title_list)
+
+  def buildInfo(self,info_dict=[],area=None):
+    if area in info_dict:
+      # creating new object
+      info = Info(info = info_dict[area], link = self.link)
+      # saving new object to block dict
+      self.info[area] = info
+      # recovering text information
+      return info_dict[area]
     else:
-      # Prepare query
-      selection.edit( params = kw )
-      if list_method not in (None, ''):
-        selection.edit(exception_uid_list=object_tree_line.getExceptionUidList())
-        object_list = selection(method = list_method, context=here, REQUEST=REQUEST)
-      else:
-        object_list = here.portal_selections.getSelectionValueList(selection_name,
-                                                          context=here, REQUEST=REQUEST)
-      
-      exception_uid_list = object_tree_line.getExceptionUidList()
-      if exception_uid_list is not None:
-      # Filter folders if this is a parent tree
-        new_object_list = []
-        for o in object_list:
-          if o.getUid() not in exception_uid_list:
-            new_object_list.append(o)
-                      
-        object_list = new_object_list
-      
-      current_list=[]
-      add = 1
-      #a test with 'add' variable because maketreelist return two times the 
-      #same object when it is open, don't know why...
-      for object in report_sections:
-        if getattr(object_tree_line.getObject(),'uid') == getattr(object.getObject(),'uid'):
-          add = 0
-          break  
-      if add == 1:       
-        report_sections += [object_tree_line] 
-        nbr_line+=1
-        for p in object_list:
-          current_list.append(p.getObject())
-        blocks_object[object_tree_line.getObject()]=current_list
-  selection.edit(report=None)
-  index = 0
-  #we start to build our line object structure right here.
-  index_report=0
-  for line_report in report_sections:
-    stat_result = {}
-    stat_context = line_report.getObject().asContext(**stat_result)
-    stat_context.domain_url = line_report.getObject().getRelativeUrl()
-    stat_context.absolute_url = lambda x: line_report.getObject().absolute_url()     
-    url=getattr(stat_context,'domain_url','')
-
-    if line_report.getDepth() == 0:
-      paternity = 1    
-      height=(height_global_div-height_header-height_axis_x-((nbr_line-1)*space_line))/float(nbr_line)
-      line = Line(title=line_report.getObject().getTitle(),
-                   name='fra' + str(indic_line),
-                   begin=y_axis_width,
-                   width=width_line,
-                   height=height,
-                   top=current_top,color='#ffffff',
-                   paternity=paternity,url=url)    
-      list_object.append(line)
-      
-      if paternity == 0:
-        height=(height_global_div-height_header-height_axis_x-
-               ((nbr_line-1)*space_line))/(float(nbr_line)) + (space_line)  
-        current_top=current_top+height
+      return ''
 
-      else:
-        if (index+1)<=(len(report_sections)-1): 
-          if report_sections[index+1].getDepth()==0:
-            height=((height_global_div-height_header-height_axis_x-
-                   (((nbr_line-1))*space_line))/float(nbr_line))+ (space_line)
-            current_top=current_top+height    
-          else:
-            height=((height_global_div-height_header-height_axis_x-
-                   (((nbr_line-1))*space_line))/float(nbr_line))
-            current_top=current_top+height 
+class Position:
+  """
+  gives a bloc [/or an area] informations about it's position on the X or Y
+  axis. can specify position in every kind of axis : continuous or listed
+  with lower and upper bound.
+  """
+
+  def __init__ (self, absolute_begin=None,
+                absolute_end=None, absolute_size=None,
+                relative_begin=None, relative_end=None, relative_size=None):
+    # absolute size takes the bloc size in the original unit for the axis
+    self.absolute_begin = absolute_begin
+    self.absolute_end = absolute_end
+    self.absolute_size = absolute_size
+    # selative size in % of the current axis size
+    self.relative_begin = relative_begin
+    self.relative_end = relative_end
+    self.relative_size = relative_size
+
+
+class Axis:
+  """
+  Structure holding informations about a specified axis.Can be X or Y axis.
+  Is aimed to handle axis with any kind of unit : continuous or listed (
+  including possibly a listed ReportTree).
+  Two of them are needed in a PlanningStructure to have X and Y axis.
+  In case of listed axis, holds AxisGroup Structure.
+  """
+
+  def __init__(self, title=None, unit=None, types=None, axis_order=None, name=None, axis_group=None):
+    self.title = title # axis title
+    self.unit = unit # unit kind (time, nb... person, task, etc.)
+    self.types = types # continuous / listed (incl. ReportTree)
+    self.name = name
+    self.size = 0 # value
+    # axis group is a single group that contain the axis structure.
+    # defined to be able to use a generic and recursive method to 
+    self.axis_group = axis_group
+    # specify if axis is primary or secondary.
+    # - if primary axis in Planning, zoom selection is applied thanks to 
+    # a cut over the basic structure objects (based on their position and
+    # their length).
+    # - if secondary axis in Planning, then need to apply the second zoom
+    # bounds (application will be based on two bounds : start & stop)
+    self.axis_order = axis_order
+    # dict containing all class properties with their values
+    self.render_dict=None
+
+
+class AxisGroup:
+  """
+  Class representing an item, that can have the following properties :
+  - one or several rendered lines (multiTasking) : contains AxisElement
+  structure to hold this.
+  - one or several sub groups (ReportTree) : contains AxisGroup structure
+  to hold sub groups elements.
+  """
+
+  def __init__ (self, name='', title='',
+                AxisGroup_list=None, AxisGroup_number=0,
+                AxisElement_list=None,AxisElement_number=0, is_open=0, is_pure_summary=1,depth=0, url=None, axis_element_already_insered= 0, secondary_axis_start=None, secondary_axis_stop=None):
+    self.name = name
+    self.title = title
+    self.axis_group_list = AxisGroup_list # ReportTree
+    self.axis_group_number = AxisGroup_number
+    self.axis_element_list = AxisElement_list # Multitasking
+    self.axis_element_number = AxisElement_number
+    self.axis_element_start = None
+    self.axis_element_stop = None
+    # dict containing all class properties with their values
+    self.render_dict=None
+    self.is_open = is_open
+    self.is_pure_summary = is_pure_summary
+    self.depth = depth
+    self.url = url
+    self.link = None # link to fold or unfold current report in report-tree mode
+    self.position_main = Position()
+    self.position_secondary = Position()
+    self.position_x = None
+    self.position_y = None
+    # UPDATE secondary axis_bounds are now linked to each axis_group to support
+    # calendar output( were each axis_group has its own start and stop)
+    self.secondary_axis_start = secondary_axis_start
+    self.secondary_axis_stop = secondary_axis_stop
+
+
+  def fixProperties(self, form_id=None, selection_name=None):
+    """
+    using actual AxisGroup properties to define some special comportement that
+    the axisGroup should have, especially in case of report-tree
+    """
+    if self.is_open:
+      # current report is unfold, action 'fold'
+      self.link = 'portal_selections/foldReport?report_url=' + self.url + '&form_id='+ form_id + '&list_selection_name=' + selection_name
+      self.title = '[-] ' + self.title
     else:
-      current_index = 0      
-      while line_report.getDepth() == report_sections[index-current_index].getDepth():
-        current_index += 1
-      if report_sections[index-current_index].getDepth() == 0:
-        current_top=list_object[len(list_object)-1].createLineChild(report_sections,field,
-                                current_top,y_axis_width,width_line,space_line,height_global_div,
-                                height_header,height_axis_x,nbr_line,index,url)
-      else : # in this case wee add a son to a son
-        depth=0 
-        current_son=list_object[len(list_object)-1]
-        while depth != (line_report.getDepth()-1):
-          current_son=list_object[len(list_object)-1].son[len(list_object[len(list_object)-1].son)-1]
-          depth+=1
-        current_top=current_son.createLineChild(report_sections,field,current_top,y_axis_width,
-                                                 width_line,space_line,height_global_div,height_header
-                                                ,height_axis_x,nbr_line,index,url)    
-    index += 1
-    indic_line+=1
-  return (list_object,nbr_line,report_sections,blocks_object)
-
-def createGraphicCall(current_line,graphic_call):
-  """ create html code of children used by graphic library to know which block can be moved.
-      Refers to javascript library for more information"""
-  for line in current_line.son:
-    for block in line.content:
-      if block.types=='activity' or block.types=='activity_error':
-        graphic_call+='\"'+block.name+'\",'
-      elif block.types=='info':
-        graphic_call+='\"'+block.name+'\"+NO_DRAG,'   
-    if line.son!=[]: # case of a son which has sons...
-      graphic_call+=createGraphicCall(line,graphic_call)        
-  return graphic_call
-  
-class PlanningBoxWidget(Widget.Widget):
-    property_names = Widget.Widget.property_names +\
-                     ['height_header', 'height_global_div','height_axis_x', 'width_line','space_line',
-                     'list_method','report_root_list','selection_name','portal_types',
-                     'meta_types','sort','title_line','y_unity','y_axis_width','y_range','x_range',
-                     'x_axis_script_id','x_start_bloc','x_stop_bloc','y_axis_method','max_y',
-                     'constraint_method','color_script','info_center','info_topleft','info_topright',
-                     'info_backleft','info_backright','security_index']
+      # current report is fold, action 'unfold'
+      self.link = 'portal_selections/unfoldReport?report_url=' + self.url + '&form_id='+ form_id + '&list_selection_name=' + selection_name
+      self.title = '[+] ' + self.title
     
-    default = fields.TextAreaField('default',
-                                title='Default',
-                                description=(
-        "Default value of the text in the widget."),
-                                default="",
-                                width=20, height=3,
-                                required=0)	     
-     
-                             
-    height_header = fields.IntegerField('height_header',
-                                title='height of the header (px):',
-                                description=(
-        "value of the height of the header, required"),
-                                default=50,
-                                required=1)    
-                                                                             
-    height_global_div = fields.IntegerField('height_global_div',
-                                title='height of the graphic (px):',
-                                description=(
-        "value of the height of the graphic, required"),
-                                default=700,
-                                required=1) 
-    height_axis_x = fields.IntegerField('height_axis_x',
-                                title='height of X-axis (px):',
-                                description=(
-        "value of the height of X-axis"),
-                                default=50,
-                                required=1) 	
-                                
-    width_line = fields.IntegerField('width_line',
-                                title='width of the graphic (px):',
-                                description=(
-        "value of width_line, required"),
-                                default=1000,
-                                required=1) 
-    space_line = fields.IntegerField('space_line',
-                                title='space between each line of the graphic (px):',
-                                description=(
-        "space between each line of the graphic,not required"),
-                                default=10,
-                                required=0)   
-                                
-    report_root_list = fields.ListTextAreaField('report_root_list',
-                                 title="Report Root",
-                                 description=(
-        "A list of domains which define the possible root."),
-                                 default=[],
-                                 required=0)
-  
-    selection_name = fields.StringField('selection_name',
-                                 title='Selection Name',
-                                 description=('The name of the selection to store'
-                                              'params of selection'),
-                                 default='',
-                                 required=0)
-                                 
-    portal_types = fields.ListTextAreaField('portal_types',
-                                 title="Portal Types",
-                                 description=(
-        "Portal Types of objects to list. Required."),
-                                 default=[],
-                                 required=0)
-                                 
-    meta_types = fields.ListTextAreaField('meta_types',
-                                 title="Meta Types",
-                                 description=(
-        "Meta Types of objects to list. Required."),
-                                 default=[],
-                                 required=0)
-                                                              
-    sort = fields.ListTextAreaField('sort',
-                                 title='Default Sort',
-                                 description=('The default sort keys and order'),
-                                 default=[],
-                                 required=0)
-  
-    list_method = fields.MethodField('list_method',
-                                 title='List Method',
-                                 description=('The method to use to list'
-                                             'objects'),
-                                 default='',
-                                 required=0)                             
-
-    title_line = fields.StringField('title_line',
-                                title='specific method which fetches the title of each line: ',
-                                description=('specific method for inserting title in line'),
-                                default='',
-                                required=0)                            
-
-    y_unity = fields.StringField('y_unity',
-                                 title='Unity in Y-axis:',
-                                 description=('The unity in Y-axis,not required'),
-                                 default='',
-                                 required=0)
-
-    y_axis_width = fields.IntegerField('y_axis_width',
-                                title='width of Y-axis (px):',
-                                description=(
-        "width of Y-axis, required"),
-                                default=200,
-                                required=1) 
-    
-    y_range = fields.IntegerField('y_range',
-                                title='number of range of Y-axis :',
-                                description=(
-        "Number of Range of Y-axis, not required"),
-                                default=0,
-                                required=0) 
- 
-    x_range = fields.StringField('x_range',
-                                 title='range of X-Axis:',
-                                 description=('Nature of the subdivisions of X-Axes, not Required'),
-                                 default='day',
-                                 required=0)	
- 
-    x_axis_script_id = fields.StringField('x_axis_script_id',
-                                 title='script for building the X-Axis:',
-                                 description=('script for building the X-Axis'),
-                                 default='',
-                                 required=0)	
-
-    x_start_bloc = fields.StringField('x_start_bloc',
-                                 title='specific method which fetches the data for the beginning of a\
-                                        block:',
-                                 description=('Method for building X-Axis such as getstartDate'
-                                              'objects'),
-                                 default='getStartDate',
-                                 required=0)	
-    
-    x_stop_bloc = fields.StringField('x_stop_bloc',
-                                 title='specific method which fetches the data for the end of each block',
-                                 description=('Method for building X-Axis such getStopDate'
-                                              'objects'),
-                                 default='',
-                                 required=0)	
-
- 
-    y_axis_method = fields.StringField('y_axis_method',
-                                 title='specific method of data type for creating height of blocks',
-                                 description=('Method for building height of blocks'
-                                              'objects'),
-                                 default='',
-                                 required=0) 
-                                 
-
-    max_y  = fields.StringField('max_y',
-                                 title='specific method of data type for creating Y-Axis',
-                                 description=('Method for building Y-Axis'
-                                              'objects'),
-                                 default='',
-                                 required=0)
 
+  def addActivity(self, activity=None, axis_element_already_insered= 0):
+    """
+    procedure that permits to add activity to the corresponding AxisElement.
+    can create new Axis Element in the actual Axisgroup if necessary.
+    Permits representation of MULTITASKING
+    """
+
+    # declaring variable used to check if activity has already been added
+    added = 0
+    try:
+      # iterating each axis_element of the axis_group
+      for axis_element in self.axis_element_list:
   
+        can_add = 1
+        # recovering all activity properties of the actual axis_element and
+        # iterating through them to check if one of them crosses the new one
+        for activity_statement in axis_element.activity_list:
   
-    constraint_method = fields.StringField('constraint_method',
-                                          title='name of constraint method between blocks',
-                                          description=('Constraint method between blocks'
-                                                      'objects'),
-                                          default='SET_DHTML',
-                                          required=1)
+          if activity_statement.isValidPosition(activity.begin, activity.end) != 0:
+            # isValidPosition returned 1 or 2, this means the activity already
+            # present does prevent from adding the new activity as there is
+            # coverage.
+            # stop iterating actual axis_element and try with the next one
+            can_add = 0
+            break
   
-    
-    color_script = fields.StringField('color_script',
-                                        title='name of script which allow to colorize blocks',
-                                        description=('script for block colors'  
-                                                    'objects'),                        
-                                        default='',   
-                                        required=0)  
-    
-    
-    info_center = fields.StringField('info_center',
-                                 title='specific method of data called for inserting info in block center',
-                                 description=('Method for displaying info in the center of a block'
-                                              'objects'),
-                                 default='',
-                                 required=0) 
-   
-    info_topright = fields.StringField('info_topright',
-                                 title='specific method of data called for inserting info in block topright',
-                                 description=('Method for displaying info in the topright of a block'
-                                              'objects'),
-                                 default='',
-                                 required=0)
-                                 
-    info_topleft = fields.StringField('info_topleft',
-                                 title='specific method of data called for inserting info in block topleft',
-                                 description=('Method for displaying info in the topleft corner of a block'
-                                              'objects'),
-                                 default='',
-                                 required=0)                             
-                                 
-    info_backleft = fields.StringField('info_backleft',
-                                 title='specific method of data called for inserting info in block backleft',
-                                 description=('Method for displaying info in the backleft of a block'
-                                              'objects'),
-                                 default='',
-                                 required=0)
-    info_backright = fields.StringField('info_backright',
-                                 title='specific method of data called for inserting info in block backright',
-                                 description=('Method for displaying info in the backright of a block'
-                                              'objects'),
-                                 default='',
-                                 required=0)
-   
-    security_index = fields.IntegerField('security_index',
-                                title='variable depending of the type of web browser :',
-                                description=("This variable is used because the rounds of each\
-                                              web browser seem to work differently"),
-                                default=2,
-                                required=0) 	 
-                                                                                       
-    def render_css(self, field, key, value, REQUEST):
-        """In this method we build our structure object, then we return all the style sheet of each div"""
-        
-        # DATA DEFINITION 
-        height_header = field.get_value('height_header')
-        height_global_div = field.get_value('height_global_div')
-        height_axis_x=field.get_value('height_axis_x')
-        width_line = field.get_value('width_line')
-        space_line = field.get_value('space_line')
-        selection_name = field.get_value('selection_name')
-        security_index = field.get_value('security_index')
-        y_unity = field.get_value('y_unity')
-        y_axis_width = field.get_value('y_axis_width')
-        y_range = field.get_value('y_range')
-        portal_types= field.get_value('portal_types')
-        meta_types = field.get_value('meta_types')
-        x_range=field.get_value('x_range')
-        here = REQUEST['here']
-        title=field.get_value('title')
-        list_method = field.get_value('list_method')
-        report_root_list = field.get_value('report_root_list')
-        scriptY = getattr(here,field.get_value('max_y'),None)
-        script=getattr(here,field.get_value('x_axis_script_id'),None)
-        block_height= getattr(here,field.get_value('y_axis_method'),None)
-        constraint_method = field.get_value('constraint_method')
-        color_script = getattr(here,field.get_value('color_script'),None)
-        #info inside a block
-        
-        info_center = field.get_value('info_center')
-        info_topleft = field.get_value('info_topleft')        
-        info_topright = field.get_value('info_topright')
-        info_backleft = field.get_value('info_backleft')
-        info_backright = field.get_value('info_backright')
-
-        object_start_method_id = field.get_value('x_start_bloc')
-        object_stop_method_id= field.get_value('x_stop_bloc')
-        form = field.aq_parent
-        sort = field.get_value('sort')   
-        x_occurence=[] # contains datas of start and stop of each block like
-                       # this [ [ [x1,x2],[x1,x2] ],[ [x1,x2],[x1,x2] ],.....] 
-                       #it is not directly coordinates but datas.                    
-        x_axe=[] # will contain what wee need to display in X-axis.
-        yrange=[] # we store the value in Y-axis of each block 
-        nbr=1
-        blocks_object={}      
-        current_top=height_header
-        line_list=[] #in this list we store all the objects of type Line
-        giant_string='' #will contain all the html code.
-        report_sections=[]
-        list_error=REQUEST.get('list_block_error')
-        old_delta=[REQUEST.get('old_delta1'),REQUEST.get('old_delta2')]
-        # END DATA DEFINITION                         
-        
-        # we fetch fold/unfold datas 
-        #here.portal_selections.setSelectionFor(selection_name, None)#uncoment to put selection to null
-        selection = here.portal_selections.getSelectionFor(selection_name, REQUEST=REQUEST)
-        default_params = {}
-        if selection is None:
-          selection = Selection(params=default_params, default_sort_on = sort)
-        else:
-          selection.edit(default_sort_on = sort)
-          selection.edit(sort_on = sort)       
-        here.portal_selections.setSelectionFor(selection_name, selection, REQUEST=REQUEST)
-        # we check what is the current zoom in order to redefine height & width
-        if selection is None:
-          current_zoom = 1
-        else:
-          current_zoom = selection.getZoom()
-        current_zoom= float(current_zoom)
-        if current_zoom<=1:
-          height_global_div = round(height_global_div * current_zoom)
-          width_line = round(width_line * current_zoom)
-          space_line = round(space_line * current_zoom)  
-        #we build lines 
-        (line_list,nbr_line,report_sections,blocks_object)=createLineObject(meta_types=meta_types,
-                                                                selection=selection,
-                                                                selection_name=selection_name,field=field,
-                                                                REQUEST=REQUEST,list_method=list_method,
-                                                                here=here,report_root_list=report_root_list,
-                                                                y_axis_width=y_axis_width,
-                                                                width_line=width_line,space_line=space_line,
-                                                                height_global_div=height_global_div,
-                                                                height_header=height_header,
-                                                                height_axis_x=height_axis_x,form=form,
-                                                                current_top=current_top,
-                                                                portal_types=portal_types)
-        #we build x_occurence (used for the range in x-Axis 
-        
-        for tree_list_object in report_sections:
-          method_start = getattr(tree_list_object.getObject(),object_start_method_id,None)
-          method_stop= getattr(tree_list_object.getObject(),object_stop_method_id,None)
-          if method_start!=None:
-            block_begin = method_start()
-          else:
-            block_begin = None
-          
-          if method_stop!=None:
-            block_stop= method_stop()
-          else:
-            block_stop=None
-          
-          if block_begin!=None:# and block_stop!=None:  
-            x_occurence.append([block_begin,block_stop])
-          
-          if method_start == None and report_sections!={}:
-            for Ablock in blocks_object:
-              for object_content in blocks_object[Ablock]:
-                method_start = getattr(object_content,object_start_method_id,None)
-                method_stop= getattr(object_content,object_stop_method_id,None)
-              
-                if method_start!=None:
-                  block_begin = method_start()
-                else:
-                  block_begin = None
-            
-                if method_stop!=None:
-                  block_stop= method_stop()
-                else:
-                  block_stop=None
-              
-                if block_begin!=None:# and block_stop!=None:
-                  x_occurence.append([block_begin,block_stop])
-          
-        params=selection.getParams()
-        start=params.get('list_start')
-        
-        x_axe=script(x_occurence,x_range,float(current_zoom),start)
-        #x_axe[0] is a list of chronological dates that wich represents the 
-        #the range of the graphic.for example: 
-        #x_axis=[['2005/11/04','2005/12/04' etc.],['april','may','june' etc.]
-        #,start_delimiter,delta]
-        # we add mobile block to the line object 
-        
-        y_max= 1
-        current_max = 1
-        if scriptY != None:
-          for s in report_sections:
-            current_max=scriptY(s.getObject())
-            if current_max > y_max:
-              y_max = current_max
-        else:
-          y_max = 1
-
-        indic_line=0
-        while indic_line != len(report_sections):
-          for object_line in line_list:
-            if object_line.title == report_sections[indic_line].getObject().getTitle():
-              if line_list != [] and report_sections[indic_line].getDepth()==0:
-                object_line.insertActivityBlock(line_content=report_sections[indic_line].getObject(),
-                                      object_start_method_id=object_start_method_id,
-                                      object_stop_method_id=object_stop_method_id,
-                                      x_axe=x_axe,field=field,info_center=info_center,
-                                      info_topright=info_topright,info_topleft=info_topleft,
-                                      info_backleft=info_backleft,info_backright=info_backright,
-                                      list_error=list_error,old_delta=old_delta,REQUEST=REQUEST,
-                                      blocks_object=blocks_object,width_line=width_line,
-                                      script_height_block=block_height,y_max=y_max,color_script=color_script)                                                      
-                break
-          indic_line+=1
-        # At this point line_list contains our tree of datas. Then we
-        # add others labels, indicators etc. for the graphic.
-
-        #One constructs the vertical dotted line
-        if x_axe != []:        
-          marge_left=y_axis_width+width_line/float(len(x_axe[1]))
-          for i in line_list:
-            i.appendVerticalDottedLine(x_axe,width_line,marge_left)
-
-        #one constructs the maximum horizontal dotted line 10px under the top of the line
-        maximum_y=y_max
-        marge_top=10
-        if y_range!=0:
-          for i in line_list:  
-            i.appendHorizontalDottedLine(marge_top,maximum_y,height_global_div,height_header,
-                                         height_axis_x,nbr_line,y_range,y_max)
-        #end construct of horizontal dotted line 
-
-        # we construct y-axis
-        way=[]    
-        y=[] #we store here the objects for creating y-axis 
-        level=0
-        current_top=height_header
-        idx=0
-        
-        for i in line_list:
-          current_top=i.buildYtype(way=way,y=y,level=level,y_axis_width=y_axis_width,
-                                   height_global_div=height_global_div,height_header=height_header,
-                                   height_axis_x=height_axis_x,nbr_line=nbr_line,current_top=current_top,
-                                   space_line=space_line,y_max=y_max,y_range=y_range,
-                                   y_unity=y_unity,selection_name=selection_name,form=form)  
-          height=((height_global_div-height_header-height_axis_x-((nbr_line-1)*space_line))/\
-                 float(nbr_line))+space_line
-          current_top=y[-1].top+height
-          idx+=1
-        line_list=y+line_list #we need to add the y-axis block at the beginning of our structure
-                                  #otherwise the display is not correct;don't know why...
-
-        #build X axis 
-        line_list.append(Line('','axis_x',y_axis_width,width_line,height_axis_x,\
-                                current_top-space_line)) 
-        line_list[-1].createXAxis(x_axe,width_line,y_axis_width)
-        if x_axe!=[]:
-          x_subdivision=width_line/float(len(x_axe[1]))
-        else:
-          x_subdivision = 0
-        REQUEST.set('line_list',line_list)  
-        REQUEST.set('report_root_list',report_root_list)
-        REQUEST.set('selection_name',selection_name)
-        REQUEST.set('x_axe',x_axe)
-        REQUEST.set('start',start)
-        REQUEST.set('delta1',old_delta[0])
-        REQUEST.set('delta2',old_delta[1])
-        REQUEST.set('constraint_method',constraint_method)
-        for i in line_list:
-          giant_string+=i.render_css(y_axis_width,security_index,x_subdivision)   
-        return giant_string
-    
-    def render(self,field, key, value, REQUEST):
-        """ this method return a string called 'giant_string' wich contains the planningbox html
-            of the web page""" 
-        here = REQUEST['here']
-        portal_url= here.portal_url()
-        title=field.get_value('title')
-        line_list = REQUEST.get('line_list')
-        x_axe = REQUEST.get('x_axe')  
-        width_line = field.get_value('width_line')
-        start_page=REQUEST.get('list_start')
-        height_global_div = field.get_value('height_global_div')
-        y_axis_width = field.get_value('y_axis_width')
-        report_root_list=REQUEST.get('report_root_list')
-        selection_name = field.get_value('selection_name')
-        start_page=REQUEST.get('start')
-        report_root_list = field.get_value('report_root_list')
-        constraint_method=REQUEST.get('constraint_method')
-        #the following javascript function allows to know where is exactly situated 
-        #the beginning of lines in absolute coordinates since we have problems due to 
-        #others tags (form,tr,table...) which are declared previously in the html.    
-        
-        giant_string="""<script type="text/javascript">
-        function setLineBegin()
-        {
-        document.forms["main_form"]["line_begin"].value = document.getElementById("fra0").offsetLeft;
-        }
-        window.onmousemove = setLineBegin;
-        </script>"""
-        
-        # we record current delta in delta1, and we record old_delta in delta2
-        odelta=[REQUEST.get('delta1'),REQUEST.get('delta2')]
-        selection = here.portal_selections.getSelectionFor(selection_name, REQUEST=REQUEST)
-        giant_string+='<input type=\"hidden\" name=\"list_selection_name\" value='+selection_name+' />\n'
-        
-        #header of the graphic###
-        giant_string+='<div id=\"header\" style=\"position:absolute;width:'+str(width_line+y_axis_width)+\
-                      'px;height:'+str(height_global_div)+'px;background:#d5e6de;margin-left:0px;\
-                       border-style:solid;border-color:#000000;border-width:1px;margin-top:1px\">\
-                       <table><tr><td><h3><u>'+title+'</h3></u></td><td>'
-
-        selection = here.portal_selections.getSelectionFor(selection_name, REQUEST=REQUEST)
-        if selection is None:
-          selection_report_path = report_root_list[0]
-        else:  
-          selection_report_path = selection.getReportPath()
-        
-        report_tree_options = ''
-        for c in report_root_list:
-          if c[0] == selection_report_path:
-            report_tree_options += """<option selected value="%s">%s</option>\n""" % (c[0], c[1])
-          else:
-            report_tree_options += """<option value="%s">%s</option>\n""" % (c[0], c[1])
-        
-        report_popup = """<select name="report_root_url"
-                       onChange="submitAction(this.form,'%s/portal_selections/setReportRoot')">
-                       %s</select></td>\n""" % (here.getUrl(),report_tree_options)
-        giant_string += report_popup
-        
-        #now we declare zoom widget 
-        if selection != None:
-          current_zoom=selection.getZoom()
-        else:
-          current_zoom = 1
-        zoom=(0.25,0.5,0.75,1,2,4,8,10)
-        zoom_select= """<td>
-              <select name="zoom" onChange="submitAction(this.form,'"""
-        zoom_select+=here.getUrl()+ '/portal_selections/setZoom\')">'
-        for z in zoom:
-          if z == float(current_zoom):
-            zoom_select+='<option selected value=\"'+str(z)+'\">x'+str(z)+'</option>\n'
-          else:
-            zoom_select+='<option value=\"'+str(z)+'\">x'+str(z)+'</option>\n'
-        giant_string += zoom_select
-        
-        
-        #now the page number widget 
-        pages='</select></td><td><select name="list_start" title=Change  \
-        onChange="submitAction(this.form,\''+here.getUrl()+'/portal_selections/setPage\')">'
-        selected=''
-        date_planning=''
-        if x_axe!=[]:
-          x_planning=x_axe[2]
-          delta=x_axe[3]
-          if isinstance(x_planning, DateTime):
-            date_planning = x_planning
-            for p in range(1,float(current_zoom)+1):
-              if x_planning == start_page :
-                selected= 'selected '
-              else:
-                selected= '' 
-              pages+='<option '+selected+'value=\"'+str(date_planning.Date())+'\">'+str(p)+' of '\
-                     +str(current_zoom)+'</option>\n'
-              date_planning+=delta
-              x_planning=date_planning.Date()
-          else:
-            for p in range(1,float(current_zoom)+1):
-              axe_index = 0
-              while x_planning != x_axe[0][axe_index]:
-                axe_index+=1 
-              
-              if x_planning == start_page :
-                selected= 'selected '
-              else:
-                selected= '' 
-              pages+='<option '+selected+'value=\"'+str(x_axe[0][axe_index])+'\">'+str(p)+' of '\
-                     +str(current_zoom)+'</option>\n'
-              axe_index = axe_index + delta       
-              current_item = x_axe[0][axe_index]
-        else:
-          x_planning=[]
-          delta=0
+        if can_add:
+          # the whole activity_statements in actual axis have been succesfully
+          # tested without problem.
+          # can add new activity to the actual axis_element
+          added = 1
+          axis_element.activity_list.append(activity)
   
-        pages+='</select></td></tr></table></div>\n'        
-        giant_string += pages 
-        #just because setPage wants it
-        giant_string += '<input type=\"hidden\" name=\"listbox_uid:list\">\n'
-        #we change old_delta2 to  old_delta1
-        giant_string += '<input type=\"hidden\" name=\"old_delta1\" value=\"'+str(odelta[0])+'\">\n'
-        giant_string += '<input type=\"hidden\" name=\"old_delta2\" value=\"'+str(odelta[0])+'\">\n' 
-        giant_string+= '<input type=\"hidden\" name=\"block_moved\">\n'
-        giant_string+= '<input type=\"hidden\" name=\"line_begin\">\n'
-
-        for i in range(0,len(line_list)):
-          giant_string+=line_list[i].render(portal_url,y_axis_width)    
-
-        #here is the declaration of four divs which are used for redimensionning
-        giant_string+='<div id=\"top\" style=\"position:absolute;width:5px;height:5px;\
-                        background:#a45d10\"></div>\n'
-        giant_string+='<div id=\"right\" style=\"position:absolute;width:5px;height:5px;\
-                        background:#a45d10"></div>\n'
-        giant_string+='<div id=\"bottom\" style=\"position:absolute;width:5px;height:5px\
-                       ;background:#a45d10\"></div>\n'
-        giant_string+='<div id=\"left\" style=\"position:absolute;width:5px;height:5px;\
-                       background:#a45d10\"></div>\n'
-        giant_string+='<script type=\"text/javascript\">\n'+ constraint_method + '('
-
-        for i in range(0,len(line_list)):
-          graphic_call=''
-          for j in line_list[i].content:
-            if j.types=='activity' or j.types=='activity_error':
-              giant_string+='\"'+j.name+'\",'
-            elif j.types=='info':
-              giant_string+='\"'+j.name+'\"+NO_DRAG,'
-          current_object=line_list[i]
-          if current_object.son!=[]:  
-           giant_string+=createGraphicCall(current_object,graphic_call)     
-        giant_string+='\"top\"+CURSOR_N_RESIZE+VERTICAL, \"right\"+CURSOR_E_RESIZE+HORIZONTAL,\
-                       \"bottom\"+CURSOR_S_RESIZE+VERTICAL,\
-                       \"left\"+CURSOR_W_RESIZE+HORIZONTAL);\n'
-        giant_string+='</script> </div> \n '
-        return giant_string  
-
-# class line 
-class Line:
-  """objects which represent a line directly in a planningbox"""
-  def __init__(self,title='',name='',begin=0,width=0,height=0,top=0,color='',son=None,y_type='none',
-               paternity=0,url=''):  
-    """used for building a Line object"""
-    if son is None:
-     son = []
-    self.title=title
-    self.name=name
-    self.begin=begin
-    self.width=width
-    self.height=height
-    self.top=top
-    self.content=[]
-    self.color=color
-    self.son=son
-    self.y_type=y_type
-    self.paternity=paternity
-    self.url=url
-
-  def render(self,portal_url,y_axis_width):
-    """ creates "pure" html code of the line, its Block, its son """
-    html_render='<div id=\"'+self.name+'\"></div>\n'
-    for block in self.content:
-      if block.types=='activity' or block.types=='activity_error':
-        #checks if the block starts before the beginning of the line               
-        if ((self.begin+block.begin*self.width) < self.begin): 
-          html_render+='<div id=\"'+block.name+'\" ondblclick=\"showGrips()\" onclick=\"if (dd.elements.'\
-                       +block.name+'.moved==0){dd.elements.'+block.name+'.moveBy('+\
-                       str(round(block.begin*self.width))+',0);dd.elements.'+block.name+'.resizeTo('+\
-                       str(round(block.width*self.width))+','+ str(block.height*(self.height-10))+\
-                       ');dd.elements.'+block.name+'.moved=1;} \">'
-        # "done" is used because otherwise everytime we move the block it will execute moveby()
-        #checks if the block is too large for the end of the line if it is the case, one cuts the block
-        elif ((block.width*self.width)+(self.begin+block.begin*self.width)>self.width+y_axis_width): 
-          html_render+='<div id=\"'+block.name+'\" ondblclick=\"showGrips()\" onclick=\"dd.elements.'\
-                       +block.name+'.resizeTo('+str(round(block.width*self.width))+','\
-                       +str(block.height*(self.height-10))+') \">'
-        else:
-          html_render+='<div id=\"'+block.name+'\" ondblclick=\"showGrips()\">'      
-        # we add info Block inside the div thanks to the render method of the Block class
-        html_render+=block.render(self.width,self.height,portal_url,self.begin,y_axis_width,self)      
-        html_render+='</div>\n'
-      elif block.types!='info':
-        html_render+='<div id=\"'+block.name+'\">'+str(block.text)+'</div>\n'      
-    if self.son!=[]:
-      for i in self.son:
-        html_render+=i.render(portal_url,y_axis_width)      
-    return html_render    
-    
-    
-  def render_css(self,y_axis_width,security_index,x_subdivision):
-    """creates style sheet of each div which represents a Line instance """
-    css_render='#'+self.name+'{position:absolute;\nborder-style:solid;\nborder-color:#53676e;\
-                               \nborder-width:1px;\n'
-    data={}
-    if self.color!='':
-      css_render+='background:'+str(self.color)+';\n'
-    css_render+='height:'+str(self.height)+'px;\n'
-    css_render+='margin-left:'+str(self.begin)+'px;\n'
-    css_render+='margin-top:'+str(self.top)+'px;\n'
-    if self.y_type=='father1':
-      css_render+='border-bottom-width:0px;'
-    elif self.y_type=='son1':
-      css_render+='border-top-width:0px;\nborder-bottom-width:0px;\n'    
-    elif self.y_type=='son2':
-      css_render+='border-top-width:0px;'
-    css_render+='width:'+str(self.width)+'px;\n}'
-    for block in self.content: #we generate block's css
-      if block.types=='activity' or block.types=='activity_error':
-        if block.types=='activity':
-          css_render+='#'+block.name+'{position:absolute;\nbackground:'+block.color+';\nborder-style:solid;\
-                      \nborder-color:#53676e;\nborder-width:1px;\n'
-        if block.types=='activity_error':
-          css_render+='#'+block.name+'{position:absolute;\nbackground:'+block.color+';\nborder-style:solid;\
-                      \nborder-color:#ff0000;\nborder-width:1px;\n'
-        css_render+='height:'+str((block.height*(self.height-10))-security_index)+'px;\n' 
-        #-10 because wee don't want a block sticked to border-top of the line
-        if ((self.begin+block.begin*self.width) < self.begin) and block.types!='activity_error': 
-        #checks if the block starts before the beginning of the line
-          css_render+='margin-left:'+str(self.begin)+'px;\n' 
-          css_render+='width:'+str((block.width*self.width+block.begin*self.width))+'px;\n' 
-        #checks if the block is too large for the end of the line. if it is the case, one cuts the block  
-        elif ((block.width*self.width)+(self.begin+block.begin*self.width)>self.width+y_axis_width) and \
-               block.types!='activity_error': 
-          css_render+='width:'+str(round(block.width*self.width)-((self.begin+block.begin*self.width+
-          block.width*self.width)-(self.width+y_axis_width)))+'px;\n'
-          css_render+='margin-left:'+str(round(self.begin+block.begin*self.width))+'px;\n' 
-        else:  
-          css_render+='width:'+str(round(block.width*self.width))+'px;\n'
-          css_render+='margin-left:'+str(round(self.begin+block.begin*self.width))+'px;\n' 
-        css_render+='margin-top:'+str(self.top+10+block.marge_top*(self.height-10))+'px;}\n'
-        # we add info Block inside the div  
-        css_render+=block.render_css(self.width,self.height,self,y_axis_width)       
-        
-      elif block.types=='text_x' : 
-        data={'border-style:':'solid;','border-color:':'#53676e;','border-width:':'1px;',
-              'margin-left:':str(block.begin)+'px;',
-              'margin-top:':str(round(1+self.top+self.height/2))+'px;'}
-        
-      elif block.types=='text_y':
-        data={'border-style:':'solid;','border-color:':'#53676e;','border-width:':'0px;',  
-              'margin-left:':str(self.width/4)+'px;',
-              'margin-top:':str(round(1+self.top+self.height/2))+'px;'}
-
-
-      elif block.types=='vertical_dotted':
-        data={'border-style:':'dotted;','border-color':'#53676e;',
-              'margin-left:':str(block.begin)+'px;','margin-top:':str(1+round(self.top))+'px;',
-              'height:':str(self.height)+'px;',
-              'border-left-width:':'1px;','border-right-width:':'0px;','border-top-width:':'0px;',    
-              'border-bottom-width:':'0px;'}
-
-      elif block.types=='horizontal_dotted': 
-        data={'border-style:':'dotted;','border-color:':'#53676e;',
-               'margin-left:':str(self.begin)+'px;','margin-top:':str(self.top+block.marge_top)+'px;',
-               'border-left-width:':'0px;','border-right-width:':'0px;',
-               'border-top-width:':'1px;','border-bottom-width:':'0px;',
-               'width:':str(self.width)+'px;'}
-
-      elif block.types=='y_coord':
-        data={'border-style:':'solid;','border-color:':'#53676e;','border-width:':'0px;',
-               'margin-left:':str(self.width-(len(block.text)*5))+'px;',
-               'margin-top:':str(self.top+block.marge_top)+'px;',
-               'height:':'','border-left-width:':'1px;','border-right-width:':'0px;',
-               'border-top-width:':'0px;','border-bottom-width':'0px;','font-size:':'9px;'}
-            
-      elif block.types=='vertical':
-        data={'border-style:':'solid;','border-color:':'#53676e;',
-              'margin-left:':str((self.width/4)+block.begin)+'px;',
-              'margin-top:':str(round(self.top)-self.height/2+13)+'px;',
-              'height:':str(block.height)+'px;','border-left-width:':'1px;',
-              'border-right-width:':'0px;','border-top-width:':'0px;', 
-              'border-bottom-width:':'0px;'}
-                       
-      elif block.types=='horizontal':
-        data={'border-style:':'solid;','border-color:':'#53676e;',
-              'margin-left:':str((self.width/4)+block.begin)+'px;',
-              'margin-top:':str(round(1+self.top+self.height/2))+'px;',
-              'height:':'1px;','border-left-width:':'0px;','border-right-width:':'0px;',
-              'border-top-width:':'1px;','border-bottom-width:':'0px;','width:':'16px;','height:':'1px;',
-             }      
-
-      if block.types!='activity':
-        if block.types!='activity_error':
-          if block.types!='info':
-            css_render+='#'+block.name+'{position:absolute;\n'
-            for key in data:
-              css_render+=key + data[key] + '\n'
-            css_render+='}\n'  
-
-    if self.son!=[]:
-      for i in self.son:
-        css_render+=i.render_css(y_axis_width,security_index,x_subdivision);
-    return css_render      
-
-  def addBlock(self,name,block,error=0):
-    """just create and add a block inside 'content' attribut of a Line instance""" 
-    type_block=''
-    if error == 0:
-      type_block='activity'
-    else:
-      type_block='activity_error'
-    self.content.append(Block(type_block,name=name,begin=block[0],width=block[1],height=block[2],text='',
-                              content=block[3],marge_top=block[4],url=block[5],color=block[6]))
-    
-    
-  def addBlockInfo(self,name):
-    """add a block info inside an activity block"""
-    self.content.append(Block('info',name,0,0,0,''))
-    
-  def addBlockTextY(self,name,text):
-    """ add a text  block in y-axis"""
-    self.content.append(Block('text_y',name,0,0,0,text))  
+          # updating activity properties
+          activity.parent_axis_element = axis_element
   
-  def addBlockCoordY(self,name,text,marge_top):
-    """ add a text block in y-axis (coordinates) """
-    self.content.append(Block('y_coord',name,0,0,0,text,{},marge_top))  
-    
-  def addBlockTextX(self,name,begin,text):
-    """ add a text block in x-axis"""
-    self.content.append(Block('text_x',name,begin,0,0,text))    
-    
-  def addBlockDottedVert(self,name,begin):
-    """ add a vertical dotted line"""
-    self.content.append(Block('vertical_dotted',name,begin,0,0,''))  
-    
-  def addBlockDottedHoriz(self,name,marge_top):
-    """append a dotted horizontal block"""
-    self.content.append(Block('horizontal_dotted',name,0,0,0,'',{},marge_top))   
+      if not added:
+        # all axis_elements of the current group have been tested and no one can
+        # contain the new activity.
+        self.axis_element_number += 1
+        # Need to create a new axis_element to hold the new activity
+        new_axis_element = AxisElement(name='Group_' + str(self.axis_group_number) + '_AxisElement_' + str(self.axis_element_number), relative_number=self.axis_element_number, absolute_number=axis_element_already_insered  + self.axis_element_number)
   
-  def addBlockVertical(self,name,marge_top,height,marge_left):
-    """append a vertical block(line)""" 
-    self.content.append(Block('vertical',name,marge_left,0,height,'',{},marge_top)) 
-     
-  def addBlockHorizontal(self,name,marge_top,height,marge_left):
-    """append a horizontal  block (line)""" 
-    self.content.append(Block('horizontal',name,marge_left,0,height,'',{},marge_top))    
-         
-  def appendVerticalDottedLine(self,x_axe,width_line,marge_left):
-    """append a vertical dotted  block"""
-    current_marge=marge_left
-    indic=0
-    for j in x_axe[1]:
-      nameblock='Block_vert_'+self.name+str(indic)
-      self.addBlockDottedVert(nameblock,current_marge)
-      current_marge+=width_line/float(len(x_axe[1]))   
-      indic+=1
-    if self.son!=[]:
-      for i in self.son:
-        i.appendVerticalDottedLine(x_axe,width_line,marge_left) 
-      
-  def buildYtype(self,way=[],y=[],level=0,y_axis_width=0,height_global_div=0,height_header=0,
-                 height_axis_x=0,nbr_line=0,current_top=0,space_line=0,y_max=0,y_range=0,
-                 y_unity=0,selection_name='',form=0): 
-    """ used for determining the type of each part of y axis taking into account father and children
-       'way' is a list whichs allows to determinate if the current block is a type 'son1' or 'son2'.
-        y parameter is a list which contains all the objects for creating y-axis.  
-
-    """
-    report_url=self.url
-    if level==0:
-      name='axis'+str(self.name)
-      if self.son!=[]:
-        y.append(Line('',name,1,y_axis_width,
-                ((height_global_div-height_header-height_axis_x-((nbr_line-1)*space_line))/float(nbr_line)),
-                current_top,'',[],'father1'))
-      else:
-        y.append(Line('',name,1,y_axis_width,((height_global_div-height_header-height_axis_x-\
-        ((nbr_line-1)*space_line))/float(nbr_line)),current_top,'',[],'father2'))
-        
-      if self.paternity==1:
-        if self.son!=[]:
-          y[-1].addBlockTextY('ytext'+name,str(3*'&nbsp '*level)+\
-          '<a href="portal_selections/foldReport?report_url='+report_url+'&form_id='+\
-          form.id+'&list_selection_name='+selection_name+'">-'+self.title+'</a>')
-        else:
-          y[-1].addBlockTextY('ytext'+name,str(3*'&nbsp '*level)+\
-          '<a href="portal_selections/unfoldReport?report_url='+\
-          report_url+'&form_id='+form.id+'&list_selection_name='+\
-          selection_name+'">+'+self.title+'</a>')
-      else:
-        y[-1].addBlockTextY('ytext'+name,str(3*'&nbsp '*level)+self.title)
-      
-      #one constructs the indicators
-      if y_range!=0:
-        y[-1].createIndicators(y_unity,y_range,y_max,height_global_div,height_header,height_axis_x,nbr_line)
-      
-      if self.son!=[]:
-        level+=1
-        for j in range(0,len(self.son)):
-          if j==(len(self.son)-1):
-            way.append(1)
-          else:
-            way.append(0)
-          current_top+=((height_global_div-height_header-height_axis_x-((nbr_line-1)*space_line))/
-                       float(nbr_line))  
-         
-          current_top=self.son[j].buildYtype(way=way,y=y,level=level,y_axis_width=y_axis_width,
-                                             height_global_div=height_global_div,
-                                             height_header=height_header,
-                                             height_axis_x= height_axis_x,nbr_line=nbr_line,
-                                             current_top=current_top,space_line=space_line,
-                                             y_max=y_max,y_range=y_range,
-                                             y_unity=y_unity,selection_name=selection_name,form=form)
-          del way[-1]
+        # add new activity to this brand new axis_element
+        new_axis_element.activity_list = []
+        new_axis_element.activity_list.append(activity)
   
-    else:
-      if self.son!=[]:
-        name=str(self.name)
-        for num in way:
-          name=name+str(num)
-        y.append(Line('',name,1,y_axis_width,((height_global_div-height_header-height_axis_x)/float(nbr_line))
-                      ,current_top,'',[],'son1'))
-
-        if self.paternity==1:
-          if self.son!=[]:
-            y[-1].addBlockTextY('ytext'+name,str(3*'&nbsp '*level)+\
-                                      '<a href="portal_selections/foldReport?report_url='+report_url+\
-                                      '&form_id='+form.id+'&list_selection_name='+selection_name+'">-'+\
-                                      self.title+'</a>')
-          else:
-            y[-1].addBlockTextY('ytext'+name,str(3*'&nbsp '*level)+\
-                                      '<a href="portal_selections/unfoldReport?report_url='+report_url+\
-                                      '&form_id='+form.id+'&list_selection_name='+selection_name+'">+'\
-                                      +self.title+'</a>') 
-        else:
-          y[-1].addBlockTextY('ytext'+name,str(3*'&nbsp '*level)+self.title)
-
-        # one constructs the stick
-        y[-1].addBlockVertical('stickVer'+name,current_top-
-                                    ((height_global_div-height_header-height_axis_x-((nbr_line-1)*space_line))\
-                                    /float(nbr_line)),
-                                    (height_global_div-height_header-height_axis_x-((nbr_line-1)*space_line))\
-                                    /float(nbr_line),3*level*5-18) 
-                                     #5 is the width of the standart font, maybe a future parameter
-        y[-1].addBlockHorizontal('stickHor'+name,current_top-
-                                    ((height_global_div-height_header-height_axis_x-((nbr_line-1)*space_line))\
-                                    /float(nbr_line)),
-                                    (height_global_div-height_header-height_axis_x-((nbr_line-1)*space_line))\
-                                    /float(nbr_line),3*level*5-18) 
-        #one constructs the indicators
-        if y_range!=0:
-          y[-1].createIndicators(y_unity,y_range,y_max,height_global_div,height_header,height_axis_x,nbr_line)
-        level+=1
-        for j in range(0,len(self.son)):
-          current_top+=((height_global_div-height_header-height_axis_x-((nbr_line-1)*space_line))/\
-                       float(nbr_line))
-          if j==(len(self.son)-1):
-            way.append(1)
-          else:
-            way.append(0)
-          current_top=self.son[j].buildYtype(way=way,y=y,level=level,y_axis_width=y_axis_width,
-                                             height_global_div=height_global_div,
-                                             height_header=height_header,height_axis_x=height_axis_x,
-                                             nbr_line=nbr_line,current_top=current_top,
-                                             space_line=space_line,y_max=y_max,y_range=y_range,
-                                             y_unity=y_unity,selection_name=selection_name,form=form)
-          del way[-1]
-      else:
-        name=str(self.name)
-        test='true'
-        for num in way:
-          name=name+str(num)
-          if num==0:
-            test='false'
-        if test=='true':
-          y.append(Line('',name,1,y_axis_width,((height_global_div-height_header-height_axis_x-\
-                       ((nbr_line-1)*space_line))/float(nbr_line)),current_top,'',[],'son2'))
-        else:
-          y.append(Line('',name,1,y_axis_width,((height_global_div-height_header-height_axis_x-\
-                       ((nbr_line-1)*space_line))/float(nbr_line)),current_top,'',[],'son1'))
-          
-        if self.paternity==1:
-          if self.son!=[]:
-            y[-1].addBlockTextY('ytext'+name,str(3*'&nbsp '*level)+
-            '<a href="portal_selections/foldReport?report_url='+report_url+
-            '&form_id='+form.id+'&list_selection_name='+selection_name+'">-'+self.title+'</a>')
-          else:
-            y[-1].addBlockTextY('ytext'+name,str(3*'&nbsp '*level)+
-            '<a href="portal_selections/unfoldReport?report_url='+report_url+
-            '&form_id='+form.id+'&list_selection_name='+selection_name+'">+'+self.title+'</a>')
-            
-        else:
-          y[-1].addBlockTextY('ytext'+name,str(3*'&nbsp '*level)+self.title)  
+        # updating activity properties
+        activity.parent_axis_element = new_axis_element
   
-        # one constructs the sticks
-        y[-1].addBlockVertical('stickVer'+name,current_top-((height_global_div-height_header-\
-                               height_axis_x-((nbr_line-1)*space_line))/float(nbr_line)),
-                               (height_global_div-height_header-height_axis_x)/float(nbr_line),\
-                               3*level*5-18)  
-        y[-1].addBlockHorizontal('stickHor'+name,current_top-((height_global_div-height_header\
-                                 -height_axis_x-((nbr_line-1)*space_line))/float(nbr_line)),
-                                 (height_global_div-height_header-height_axis_x)/float(nbr_line),\
-                                 3*level*5-18) 
-        #one constructs the indicators   
-        if y_range!=0:
-          y[-1].createIndicators(y_unity,y_range,y_max,height_global_div,height_header,\
-                                 height_axis_x,nbr_line)
-    return current_top      
-
-  def createIndicators(self,y_unity,y_range,y_max,height_global_div,height_header,\
-                       height_axis_x,nbr_line):
-    """creates a blocks used for y-axis coordinates"""
-    
-    maximum_y=y_max
-    marge_top=0
-    indic=0
-    while maximum_y>=0:
-      nameblock='Block_'+self.name+str(indic)
-      text=str('%.2f' %maximum_y)+y_unity    
-      self.addBlockCoordY(nameblock,text,marge_top) 
-      maximum_y=maximum_y-(y_max/float(y_range)) 
-      marge_top+=(((height_global_div-height_header-height_axis_x)/float(nbr_line))-10)/y_range 
-      indic+=1
-
-
-  def appendHorizontalDottedLine(self,marge_top,maximum_y,height_global_div,height_header,
-                                 height_axis_x,nbr_line,y_range,y_max): 
-    """creates a horizontal dotted line """
-    current_top=marge_top
-    max_y=maximum_y
-    indic=0
-    if y_range !=0:
-      while max_y>=0:
-        nameblock='Block_hor_'+self.name+str(indic)
-        self.addBlockDottedHoriz(nameblock,current_top) 
-        max_y=max_y-(y_max/float((y_range-1)))  #-1 because we don't want a dotted line on the X-axis
-        #10px under the top of the line . float is important here!
-        current_top+=(((height_global_div-height_header-height_axis_x)/float(nbr_line))-marge_top)/y_range
-        indic+=1
-      if self.son!=[]:
-        for i in self.son:
-          i.appendHorizontalDottedLine(marge_top,maximum_y,height_global_div,
-                                       height_header,height_axis_x,nbr_line,y_range,y_max)
-     
-  def appendActivityBlock(self,list_block,list_error,old_delta,REQUEST):
-    """create an activity block"""
-    indic=0
-    name_block=''
-    prev_deltaX=0
-    prev_deltaY=0
-    old_delta2=old_delta[1]
-    if old_delta2!='None' and old_delta2!=None:
-      if old_delta2!='':
-        if old_delta2!={}:
-          old_delta2=convertStringToDict(old_delta2)
-    else:
-      old_delta2={}  
-    
-    for data_block in list_block:
-      name_block='ActivityBlock_'+self.name+'_'+str(indic)
-      if list_error != None: 
-        for blockerror in list_error: #we are about to build block with red border
-          if blockerror[0][0] == name_block:
-            if old_delta2.has_key(name_block):
-              prev_deltaX=float(old_delta2[name_block][0])
-              prev_deltaY=float(old_delta2[name_block][1])
-            deltaX =float(blockerror[0][3]) - float(blockerror[0][1])+prev_deltaX 
-            deltaY = float(blockerror[0][4]) - float(blockerror[0][2])+prev_deltaY
-            #data_block_error is [begin,width,top,info,height]
-            begin=(blockerror[1].begin*blockerror[2].width+deltaX)/blockerror[2].width
-            width=float(blockerror[0][5])/blockerror[2].width
-            top=((blockerror[1].marge_top)*(blockerror[2].height-10)+deltaY)/(blockerror[2].height-10)
-            height=float(blockerror[0][6])/(blockerror[2].height-10)
-            data_block_error= [begin,width,height,data_block[3],top,blockerror[1].url]
-            self.addBlock(name_block,data_block_error,1)  
-          else:
-            self.addBlock(name_block,data_block)
-      else:
-        self.addBlock(name_block,data_block)  
-      indic+=1
-    
-  def createXAxis(self,x_axe,width_line,y_axis_width):
-    """creates x-axis """
-    marge_left=y_axis_width
-    indic1=0
-    if x_axe!=[]:
-      for i in x_axe[1]:
-        nameblock='block_'+self.name+str(indic1)
-        self.addBlockTextX(nameblock,marge_left,i)
-        indic1+=1  
-        marge_left+=width_line/float(len(x_axe[1]))
-        
-  def addSon(self,son):
-    """add a child Line to a Line """
-    self.son.append(son)       
-
-  def createLineChild(self,report_section=None,field='',current_top=0,y_axis_width=0,
-                      width_line=0,space_line=0,height_global_div=0,height_header=0,
-                      height_axis_x=0,nbr_line=0,current_index=0,url=''): 
-    """ create the Line object which is the son of an other Line Object"""
-    if len(report_section[current_index].getObject().objectValues())!=0:
-      paternity=1
-    else:
-      paternity=0   
-    son=Line(title=str(report_section[current_index].getObject().getTitle()),
-              name=self.name+'s'+str(current_index) ,begin=y_axis_width,width=width_line,
-              height=(height_global_div-height_header-height_axis_x-((nbr_line-1)*space_line))\
-              /float(nbr_line),top=current_top,color='#ffffff',paternity=paternity,url=url) 
-    if (current_index+1)<=(len(report_section)-1): 
-     if report_section[current_index+1].getDepth() == 0:
-       current_top=current_top+((height_global_div-height_header-height_axis_x-
-                   ((nbr_line-1)*space_line))/float(nbr_line))+space_line       
-     else:
-       current_top=current_top+((height_global_div-height_header-height_axis_x-
-                   ((nbr_line-1)*space_line))/float(nbr_line))
-    self.addSon(son)                
-    return current_top 
-
-  def insertActivityBlock(self,line_content=None,object_start_method_id=None,object_stop_method_id=None,
-                          x_axe=[],field='',info_center='',info_topright='',info_topleft='',
-                          info_backleft='',info_backright='',list_error='',old_delta='',REQUEST=None,
-                          blocks_object={},width_line=0,script_height_block=None,y_max = 1,color_script=None):
-    """allows to create the mobile block objects"""
-    #first we check if the block has information
-    center= getattr(line_content,info_center,None) 
-    topright = getattr(line_content,info_topright,None)
-    topleft = getattr(line_content,info_topleft,None)
-    backleft= getattr(line_content,info_backleft,None)
-    backright= getattr(line_content,info_backright,None)
-    info={}
-    if center!=None: info['center']=str(center())
-    if topright!=None: info['topright']=str(topright())
-    if topleft!=None: info['topleft']=str(topleft())
-    if backleft!=None: info['botleft']=str(backleft())
-    if backright!=None: info['backright']=str(backright()) 
-    marge=0
-    method_start = getattr(line_content,object_start_method_id,None)  
-    method_stop= getattr(line_content,object_stop_method_id,None)
-    wrong_left=0 
-    wrong_right=0
-    list_block=[]
-    current_color=''
-    if method_start==None and blocks_object!={}:
-      for Ablock in blocks_object:
-        #object_content is the current object used for building a block.
-        #For instance if the context is a project, then object_content is an orderLine.
-        for object_content in blocks_object[Ablock]:
-          if self.title == Ablock.getObject().getTitle(): 
-            method_start = getattr(object_content,object_start_method_id,None)  
-            method_stop= getattr(object_content,object_stop_method_id,None)     
-    
-            if method_start != None:
-              block_begin = method_start()
-            else:
-              block_begin = None
-      
-            if method_stop!=None:
-              block_stop= method_stop()
-            else:
-              block_stop=None
-            if isinstance(block_begin,DateTime):    
-                if round(block_begin-DateTime(x_axe[0][0]))>0:
-                  block_left=float(round(block_begin-DateTime(x_axe[0][0])))/round(
-                             (DateTime(x_axe[0][-1])+1)-DateTime(x_axe[0][0]))
-                elif round(block_begin-DateTime(x_axe[0][0]))==0:
-                  block_left=0
-                else:
-                  block_left=float(round(block_begin-DateTime(x_axe[0][0])))/round(
-                         (DateTime(x_axe[0][-1])+1)-DateTime(x_axe[0][0]))
-
-                if block_stop-DateTime(x_axe[0][0])<=0:
-                  wrong_left = 1  #means that the block is outside of x-axis range
-        
-                if block_begin-DateTime(x_axe[0][-1])>=0:            
-                  wrong_right = 1 #the same
-      
-                block_right=float(round(block_stop-DateTime(x_axe[0][0])))/round(
-                              (DateTime(x_axe[0][-1])+1)-DateTime(x_axe[0][0]))
-                
-                center= getattr(object_content,info_center,None) 
-                topright = getattr(object_content,info_topright,None)
-                topleft = getattr(object_content,info_topleft,None)
-                backleft= getattr(object_content,info_backleft,None)
-                backright= getattr(object_content,info_backright,None)
-                info={}
-                if center!=None: info['center']=str(center())
-                if topright!=None: info['topright']=str(topright())
-                if topleft!=None: info['topleft']=str(topleft())
-                if backleft!=None: info['botleft']=str(backleft())
-                if backright!=None: ignfo['botright']=str(backright())
-                url = getattr(object_content,'domain_url','')
-                url = object_content.getUrl()
-                
-                #if there is a script wich allows to know the height of the current block,
-                #then we use it, otherwise block's height is 0,75
-                if script_height_block == None or y_max==1:
-                  height = 0.75
-                else:
-                  height = float(script_height_block(object_content))/y_max
-                
-                if color_script != None:
-                  current_color = color_script(object_content)
-                
-                if wrong_left!=1 and wrong_right!=1: # if outside we do not display
-                  list_block.append([block_left,block_right-block_left,height,info,1-height,url,current_color])
-            else:
-              if block_begin !=None:
-                for i in x_axe[0]:
-                  if block_begin==i:
-                    center= getattr(object_content,info_center,None) 
-                    topright = getattr(object_content,info_topright,None)
-                    topleft = getattr(object_content,info_topleft,None)
-                    backleft= getattr(object_content,info_backleft,None)
-                    backright= getattr(object_content,info_backright,None)
-                    info={}
-                    if center!=None: info['center']=str(center())
-                    if topright!=None: info['topright']=str(topright())
-                    if topleft!=None: info['topleft']=str(topleft())
-                    if backleft!=None: info['botleft']=str(backleft())
-                    if backright!=None: ignfo['botright']=str(backright())
-                    url = getattr(object_content,'domain_url','')
-                    if script_height_block == None or y_max==1:
-                      height = 0.75
-                    else:
-                      height = float(script_height_block(object_content))/y_max
-                    if color_script != None:
-                      current_color = color_script(object_content) 
-                    list_block.append([marge,(block_stop-block_begin)/(float(len(x_axe[0]))),height,info,
-                                      1-height,url,current_color])   
-               # 0.75(height) need to be defined        
-                  marge+=1/float(len(x_axe[0])) 
-    else:
-      if method_start != None:
-        block_begin = method_start()
-      else:
-        block_begin = None
-      
-      if method_stop!=None:
-        block_stop= method_stop()
-      else:
-        block_stop=None
-      # if datas are DateTime type we need to do special process.
-      if isinstance(block_begin,DateTime):    
-        if round(block_begin-DateTime(x_axe[0][0]))>0:
-          block_left=float(round(block_begin-DateTime(x_axe[0][0])))/float(
-                     (DateTime(x_axe[0][-1])+1)-DateTime(x_axe[0][0]))
-        elif round(block_begin-DateTime(x_axe[0][0]))==0:
-          block_left=0
-        else:
-          block_left=float(round(block_begin-DateTime(x_axe[0][0])))/round(
-                 (DateTime(x_axe[0][-1]+1))-DateTime(x_axe[0][0]))
+        # register the axis_element to the actual group.
+        self.axis_element_list.append(new_axis_element)
+    except TypeError:
+      # in case axis_element_list is None
+      # Need to create a new axis_element to hold the new activity
+      self.axis_element_number += 1
+      new_axis_element = AxisElement(name='Group_' + str(self.axis_group_number) + '_AxisElement_1', relative_number= self.axis_element_number, absolute_number = axis_element_already_insered + self.axis_element_number, parent_axis_group=self)
 
-        if block_stop!=None:
-          if block_stop-DateTime(x_axe[0][0])<=0:
-            wrong_left = 1  #means that the block is outside of x-axis range
-        
-        if block_begin-DateTime(x_axe[0][-1])>=0:            
-          wrong_right = 1 #the same
-        if block_stop!=None:
-          block_right=float(round(block_stop-DateTime(x_axe[0][0])))/round(
-                            (DateTime(x_axe[0][-1])+1)-DateTime(x_axe[0][0]))
-        
-        if wrong_left!=1 and wrong_right!=1: # if outside we do not display
-          if script_height_block == None or y_max==1:
-            height = 0.75
-          else:
-            height = float(script_height_block(line_content.getObject()))/y_max
-          if color_script != None:
-            current_color = color_script(line_content)  
-          if block_stop != None:  
-            list_block.append([block_left,block_right-block_left,height,info,1-height,'',current_color])
-          else:
-            list_block.append([block_left,1/(float(len(x_axe[0]))),height,info,1-height,'',current_color])
-          
-      else:
-        if block_begin !=None:
-          if block_stop !=None:
-            for i in x_axe[0]:
-              if block_begin==i:
-                if script_height_block == None or y_max==1:
-                  height = 0.75
-                else:
-                  height = float(script_height_block(line_content.getObject()))/y_max
-                if color_script != None:
-                  current_color = color_script(object_content)
-              list_block.append([marge,1/(float(len(x_axe[0]))),height,info,1-height,'',current_color])   
-                # 0.75(height) need to be defined        
-              marge+=1/float(len(x_axe[0]))
-          else:
-            for i in x_axe[0]:
-              if isinstance(block_begin,list): 
-                for item in block_begin:
-                  if item == i:
-                    if script_height_block == None or y_max==1:
-                      height = 0.75
-                    else:
-                      height = float(script_height_block(line_content.getObject()))/y_max
-                    if color_script != None:
-                      current_color = color_script(object_content) 
-                    list_block.append([marge,1/(float(len(x_axe[0]))),height,info,1-height,'',current_color])  
-              marge+=1/float(len(x_axe[0]))
-    if list_block!=[]:
-      self.appendActivityBlock(list_block,list_error,old_delta,REQUEST) 
-      
-    if self.son!=[]:
-      son_line= line_content.objectValues()
-      indic=0
-      while indic != len(son_line):
-        indic2=0
-        for s in son_line:
-          if s.getTitle() == self.son[indic].title:
-            
-            self.son[indic].insertActivityBlock(line_content=s,object_start_method_id=object_start_method_id,
-                                                object_stop_method_id=object_stop_method_id,x_axe=x_axe,
-                                                field=field,info_center=info_center,
-                                                info_topright=info_topright,info_topleft=info_topleft,
-                                                info_backleft=info_backleft,info_backright=info_backright,
-                                                list_error=list_error,old_delta=old_delta,REQUEST=REQUEST,
-                                                width_line=width_line,
-                                                script_height_block=script_height_block,
-                                                color_script=color_script)
-        indic+=1
-  
-        
-# class block      
-class Block:
-  def __init__(self,types,name,begin,width=0,height=0,text='',content={},marge_top=0,id='',url='',color=''):
-    """creates a block object"""
-    self.types=types
-    self.name=name
-    self.begin=begin
-    self.width=width
-    self.height=height
-    self.text=text
-    self.content=content #stores info block in a dictionnary
-    self.marge_top=marge_top
-    if color=='':
-      self.color='#bdd2e7'
-    else: 
-      self.color=color 
-    self.id = name
-    self.url = url
-  
-  def render(self,line_width,line_height,portal_url,line_begin,y_axis_width,line):
-    """used for inserting text in a block. one calculates how to organise the space.
-    one defines a width and height parameters (in pixel) which can be 
-    changed (depends on the size and the font used).
-    One fetches content which is a dictionnary like 
-    this {'center':'ezrzerezr','topright':'uihiuhiuh',
-          'topleft':'jnoinoin','botleft':'ioioioioi','botright':'ononono'}
-    """ 
-    string=''
-    font_height=10
-    font_width=6
-    info=''
-    #checks if the block starts before the beginning of the line
-    if ((line_begin+self.begin*line_width) < line_begin): 
-      block_width=self.width+self.begin 
-    #checks if the block is too large for the end of the line. if it is the case, one cuts the block
-    elif ((self.width*line_width)+(line_begin+self.begin*line_width)>line_width+y_axis_width): 
-      block_width=self.width*line_width-((line_begin+self.begin*line_width+self.width*line_width)\
-                  -(line_width+y_axis_width))
-      block_width=block_width/line_width
-    else:
-      block_width=self.width
-    return self.buildInfoBlockBody(line_width,block_width,font_width,line_height,font_height,
-                                   line,portal_url)
-    
-  def render_css(self,line_width,line_height,line,y_axis_width):
-    """used for inserting info inside an activity block"""
-    string=''
-    font_height=10
-    font_width=6
-    line_begin=line.begin
-    #checks if the block starts before the beginning of the line
-    if ((line_begin+self.begin*line_width) < line_begin) and self.types!='activity_error':
-      block_width=self.width+self.begin
-    #checks if the block is too large for the end of the line. if it is the case, one cuts the block  
-    elif ((self.width*line_width)+(line_begin+self.begin*line_width)>line_width+y_axis_width) \
-          and self.types!='activity_error':
-      block_width=self.width*line_width-((line_begin+self.begin*line_width+self.width*line_width)\
-                  -(line_width+y_axis_width))
-      block_width=block_width/line_width
-    else:
-      block_width=self.width
-    return self.buildInfoBlockCss(font_height,line_height,block_width,line_width,font_width,line)
-    
+      # add new activity to this brand new axis_element
+      new_axis_element.activity_list = []
+      new_axis_element.activity_list.append(activity)
+
+      # updating activity properties
+      activity.parent_axis_element = new_axis_element
+
+      # register the axis_element to the actual group.
+      self.axis_element_list = []
+      self.axis_element_list.append(new_axis_element)
+
+
+class AxisElement:
+  """
+  Represents a line in an item. In most cases, an AxisGroup element will
+  hold ony one AxisElement (simple listed axis), but sometimes more
+  AxisElements are required (multi, simultaneous tasking).
+  AxisElement is linked with the blocs displayed in it : this is only
+  usefull when doing multitasking to check if a new bloc can be added to an
+  existing AxisElement or if it is needed to create a new AxisElement in
+  the AxisGroup to hold it.
+  """
+  def __init__ (self,name='', relative_number=0, absolute_number=0, activity_list=None, parent_axis_group = None):
+    self.name = name
+    self.relative_number = relative_number # personal AxisElement id in the AxisGroup
+    self.absolute_number = absolute_number # id in the current rendering
+    self.activity_list = activity_list
+    # dict containing all class properties with their values
+    self.render_dict=None
+    self.parent_axis_group = parent_axis_group
+
+
+class Info:
+  """
+  Class holding all informations to display an info text div inside of a block or
+  AxisGroup or whatever
+  """
+  security = ClassSecurityInfo()
+
+  def __init__(self, info=None, link=None, title=None):
+    self.info = info
+    self.link = link
+    self.title = title
+
+  security.declarePublic('edit')
+  def edit(self, info=None):
+     """
+     special method allowing to update Info content from an external script
+     """
+     self.info = info
+
+# declaring validator instance
+PlanningBoxValidatorInstance = PlanningBoxValidator()
 
-  def addInfoCenter(self,info): 
-    """add info in center of a block"""    
-    self.content['center']=info  
-    
-  def addInfoTopLeft(self,info): 
-    """add info in the top left corner of a block """   
-    self.content['topleft']=info
-  
-  def addInfoTopRight(self,info): 
-    """add info in the top right corner of a block"""    
-    self.content['topright']=info
-  
-  def addInfoBottomLeft(self,info): 
-    """add info in the bottom left corner of a block"""    
-    self.content['botleft']=info
-  
-  def addInfoBottomRight(self,info): 
-    """add info in the bottom right corner of a block"""    
-    self.content['botright']=info
-   
-
-  def buildInfoBlockBody(self,line_width,block_width,font_width,line_height,font_height,line,portal_url):
-    """ create the body of the html for displaying info inside a block"""
-    string=''
-    #line_height=line_height-10
-    already=0
-    block_name=''
-    length_list_info=0
-    info=''
-    curr_url = ''
-    for i in self.content:
-      if self.content[i]!=None:
-        length_list_info += 1
-    for i in self.content:
-      if length_list_info==5:
-        test_height= font_height<=((self.height*line_height)/3)
-        test_width= ((len(self.content[i])*font_width)<=((block_width*line_width)/3))
-      if length_list_info==4 or length_list_info==3:
-        test_height= font_height<=((self.height*line_height)/2)
-        test_width= ((len(self.content[i])*font_width)<=((block_width*line_width)/2))
-      if length_list_info==2:
-        test_height=font_height<=(self.height*line_height)
-        test_width= (len(self.content[i]*font_width)<=((block_width*line_width)/2))
-      if length_list_info==1: 
-        test_height= font_height<=(self.height*line_height)
-        test_width= (len(self.content[i]*font_width)<=(block_width*line_width))   
-      if test_height & test_width:
-        if self.url!='':
-          curr_url = self.url
-        else:
-          curr_url = line.url
-        string+='<div id=\"'+self.name+i+'\"><a href=\"'+portal_url+'/'+curr_url+'\">'+ self.content[i]
-        string+='</a href></div>\n' 
-      else: #one adds interogation.png  
-        if ((self.width*line_width>=15) & (self.height*line_height>=15)): 
-          info+=self.content[i]+'|'
-          if already==0 or i=='center':
-            block_name=self.name+i
-            already=1
-    if already==1:
-      string+='<div id=\"'+block_name+'\" title=\"'+info+'\"><a href=\"'+portal_url+'/'+curr_url+'\">\
-              <img src=\"'+portal_url+'/images/question.png\" height=\"15\" width=\"15\"></a href> '
-      string+='</div>\n'   
-    return string     
-
-
-  def buildInfoBlockCss(self,font_height,line_height,block_width,line_width,font_width,line):
-    """used for creating css code when one needs to add info inside a block"""
-    string=''
-    already=0#used when we add interro.png 
-    list_info_length = 0 #counts number of info inside a block(between 0 and 5)
-    for j in self.content:
-      if  self.content[j]!= None:
-        list_info_length += 1 
-    if list_info_length ==0:return ''
-
-    #definition of coefficient for different cases of info display.
-    matrix = {
-    ('center',5):{'left':2,'top':2},
-    ('center',4):{'left':0,'top':0},
-    ('center',3):{'left':2,'top':2},
-    ('center',2):{'left':2,'top':2},
-    ('center',1):{'left':2,'top':2},
-    
-    ('topright',5):{'left':1.01,'top':0},
-    ('topright',4):{'left':1.01,'top':0},
-    ('topright',3):{'left':1.01,'top':0},
-    ('topright',2):{'left':1.01,'top':2},
-    ('topright',1):{'left':1.01,'top':0},
-    
-    ('topleft',5):{'left':0,'top':0},
-    ('topleft',4):{'left':1,'top':1},
-    ('topleft',3):{'left':0,'top':0},
-    ('topleft',2):{'left':0,'top':0},
-    ('topleft',1):{'left':0,'top':0},
-    
-    ('botleft',5):{'left':0,'top':1},
-    ('botleft',4):{'left':0,'top':1},
-    ('botleft',3):{'left':0,'top':1},
-    ('botleft',2):{'left':0,'top':1},
-    ('botleft',1):{'left':0,'top':1},
-    
-    ('botright',5):{'left':1.01,'top':1.1},
-    ('botright',4):{'left':1.01,'top':1.1},
-    ('botright',3):{'left':1.01,'top':1.1},
-    ('botright',2):{'left':1.01,'top':1.1},
-    ('botright',1):{'left':1.01,'top':1.1}
-    }   
-    #definition of coefficient for different cases, when info strings are too long,
-    #we use a small picture. The coefficient are suitable for are 15x15px picture. 
-    matrix_picture = {
-    ('center',5):{'left':2,'top':2},
-    ('center',4):{'left':0,'top':0},
-    ('center',3):{'left':2,'top':2},
-    ('center',2):{'left':0,'top':2},
-    ('center',1):{'left':2,'top':2},
-    
-    ('topright',5):{'left':1,'top':0},
-    ('topright',4):{'left':1,'top':0},
-    ('topright',3):{'left':1,'top':0},
-    ('topright',2):{'left':1,'top':2},
-    ('topright',1):{'left':0,'top':0},
-    
-    ('topleft',5):{'left':0,'top':0},
-    ('topleft',4):{'left':1,'top':1},
-    ('topleft',3):{'left':0,'top':0},
-    ('topleft',2):{'left':0,'top':0},
-    ('topleft',1):{'left':0,'top':0},
-    
-    ('botleft',5):{'left':0,'top':1},
-    ('botleft',4):{'left':0,'top':1},
-    ('botleft',3):{'left':0,'top':1},
-    ('botleft',2):{'left':0,'top':1}, 
-    ('botleft',1):{'left':0,'top':1},
-    
-    ('botright',5):{'left':1,'top':1},
-    ('botright',4):{'left':0,'top':0},
-    ('botright',3):{'left':0,'top':0},
-    ('botright',2):{'left':0,'top':0},
-    ('botright',1):{'left':1,'top':1}
-    }  
-    
-    idx= 0
-    margin_left=0
-    margin_top=0
-   
-    for block in self.content:         
-      matrix_data = matrix[(block,list_info_length)]
-      left = matrix_data['left']
-      top= matrix_data['top']
-      if left == 0:
-        margin_left=0
-      else:
-        margin_left = round(((block_width*line_width)/left)-(font_width*len(self.content[block]))/left)  
-      if top==0:
-        margin_top=0  
-      else:
-        margin_top = round(((self.height*(line_height-10))/top)-(font_height))
-      if list_info_length==5:
-        test_height= font_height<=((self.height*(line_height))/3)
-        test_width= ((len(self.content[block])*font_width)<=((block_width*line_width)/3))
-      if list_info_length==4 or list_info_length==3:
-        test_height= font_height<=((self.height*(line_height))/2)
-        test_width= ((len(self.content[block])*font_width)<=((block_width*line_width)/2))
-      if list_info_length==2:
-        test_height=font_height<=(self.height*(line_height))
-        test_width= (len(self.content[block]*font_width)<=((block_width*line_width)/2))
-      if list_info_length==1: 
-        test_height= font_height<=(self.height*(line_height))
-        test_width= (len(self.content[block]*font_width)<=(block_width*line_width))
-
-      if test_height & test_width:
-        string+='#'+self.name+block+'{position:absolute;\nmargin-left:'+\
-                 str(margin_left)+'px;\nmargin-top:'+str(margin_top)+'px;\n}\n'              
-        line.addBlockInfo(self.name+block)
-      else: # we add question.png because the size of the block is not enough
-        if ((self.width*line_width>=15) & (self.height*line_height>=15)): 
-          matrix_data= matrix_picture[(block,list_info_length)]
-          left = matrix_data['left']
-          top = matrix_data['top']
-          if left == 0:
-            margin_left=0
-          else:
-           margin_left=round(((block_width*line_width)/left)-(15/left))
-          if top==0:
-            margin_top=0  
-          else:
-            margin_top=round(((self.height*(line_height-10))/top)-(15/top))
-          if block=='center' and list_info_length==3:
-            margin_left=round(((block_width*line_width)/left)-(15/left))
-            margin_top=round(((self.height*(line_height-10))/top)-(font_height))
-          if block=='center' and list_info_length==2:  
-            margin_top=round(((self.height*(line_height-10))/top)-(font_height/top))    
-          if already==0 or block=='center':
-            string+='#'+self.name+block+'{position:absolute;\nmargin-left:'+str(margin_left)+\
-                    'px;\nmargin-top:'+str(margin_top)+'0px;\n}'  
-            block_disp=self.name+block
-            already=1
-    return string
-    
-  def get_error_message(self,err_type):
-    return 'incorrect block'
-PlanningBoxWidgetInstance = PlanningBoxWidget()        
-          
 class PlanningBox(ZMIField):
     meta_type = "PlanningBox"
     widget = PlanningBoxWidgetInstance
@@ -2069,9 +2169,34 @@ class PlanningBox(ZMIField):
     def get_value(self, id, **kw):
       if id == 'default' and kw.get('render_format') in ('list', ):
         return self.widget.render(self, self.generate_field_key() , None , 
-                                  kw.get('REQUEST'), render_format=kw.get('render_format'))
+                                  kw.get('REQUEST'),
+                                  render_format=kw.get('render_format'))
       else:
         return ZMIField.get_value(self, id, **kw)
 
-    def render_css(self, value=None, REQUEST=None):      
+    def render_css(self, value=None, REQUEST=None):
       return self.widget.render_css(self,'',value,REQUEST)
+
+
+InitializeClass(BasicStructure)
+allow_class(BasicStructure)
+InitializeClass(BasicGroup)
+allow_class(BasicGroup)
+InitializeClass(BasicActivity)
+allow_class(BasicActivity)
+InitializeClass(PlanningStructure)
+allow_class(PlanningStructure)
+InitializeClass(Activity)
+allow_class(Activity)
+InitializeClass(Bloc)
+allow_class(Bloc)
+InitializeClass(Position)
+allow_class(Position)
+InitializeClass(Axis)
+allow_class(Axis)
+InitializeClass(AxisGroup)
+allow_class(AxisGroup)
+InitializeClass(AxisElement)
+allow_class(AxisElement)
+InitializeClass(Info)
+allow_class(Info)
-- 
2.30.9