############################################################################## # # Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved. # Jonathan Loriette <john@nexedi.com> # # WARNING: This program as such is intended to be used by professional # programmers who take the whole responsability of assessing all potential # 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 # # This program is Free Software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################## import string, types, sys from Form import BasicForm from Products.Formulator.Field import ZMIField from Products.Formulator.DummyField import fields from Products.Formulator.MethodField import BoundMethod from DateTime import DateTime from Products.Formulator import Widget, Validator from Products.Formulator.Errors import FormValidationError, ValidationError from Selection import Selection, DomainSelection from SelectionTool import makeTreeList import OFS from AccessControl import ClassSecurityInfo from zLOG import LOG from copy import copy from Acquisition import aq_base, aq_inner, aq_parent, aq_self from Products.Formulator.Form import BasicForm from Products.ERP5Type.Utils import getPath from Products.ERP5Type.Document import newTempBase from Products.CMFCore.utils import getToolByName class PlanningBoxValidator(Validator.StringBaseValidator): def validate(self, field, key, REQUEST): try: for lang in list_value.keys(): list_value[lang] = int(list_value[lang]) except ValueError: self.raise_error('not an integer', field) return list_value PlanningBoxValidatorInstance=PlanningBoxValidator() 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): report_sections = [] 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') 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) if 'select_expression' in kw: del kw['select_expression'] if hasattr(list_method, 'method_name'): list_method = here.objectValues kw = copy(params) kw['spec'] = filtered_meta_types elif list_method in (None, ''): # Use current selection # Use previously used list method 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, form, None,selection_report_path,None,0, selection_report_current, form.id, selection_name, report_depth,is_report_opened, sort_on=selection.sort_on) # 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) selection.edit(report_list=report_list) report_sections = [] list_object = [] nbr_line=0 object_list=[] indic_line=0 index_line = 0 for s in report_tree_list: selection.edit(report = s.getSelectDomainDict()) if s.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 if s.getIsPureSummary(): stat_result = {} index = 1 report_sections += [s] nbr_line+=1 else: # Prepare query selection.edit( params = kw ) if list_method not in (None, ''): object_list = selection(method = list_method, context=here, REQUEST=REQUEST, s=s, object_list= object_list) else: object_list = here.portal_selections.getSelectionValueList(selection_name, context=here, REQUEST=REQUEST) selection.edit(report=None) index = 0 # we start to build our line object structure right here. for l in report_sections: stat_result = {} stat_context = l.getObject().asContext(**stat_result) stat_context.domain_url = l.getObject().getRelativeUrl() stat_context.absolute_url = lambda x: l.getObject().absolute_url() url=getattr(stat_context,'domain_url','') if l.getDepth() == 0: paternity = 0 if len(l.getObject().objectValues())!=0: paternity = 1 height=(height_global_div-height_header-height_axis_x-((nbr_line-1)*space_line))/float(nbr_line) line = Line(title=l.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: current_top=current_top+((height_global_div-height_header-height_axis_x-((nbr_line-1)*space_line))/float(nbr_line)) + (space_line) else: if (index+1)<=(len(report_sections)-1): if report_sections[index+1].getDepth()==0: #current_top=current_top+((height_global_div-height_header-height_axis_x)/float(nbr_line)) + (space_line) 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)) else: current_index = 0 while l.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 soon to a soon depth=0 current_soon=list_object[len(list_object)-1] while depth != (l.getDepth()-1): current_soon=list_object[len(list_object)-1].soon[len(list_object[len(list_object)-1].soon)-1] depth+=1 current_top=current_soon.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) def createGraphicCall(current_line,graphic_call): """ create html code of children used by graphic library to know which block can be moved""" for i in current_line.soon: for j in i.content: if j.types=='activity': graphic_call+='\"'+j.name+'\",' elif j.types=='info': graphic_call+='\"'+j.name+'\"+NO_DRAG,' if i.soon!=[]: # case of a soon which has soons... graphic_call+=createGraphicCall(i,graphic_call) return graphic_call #class planningboxwidget ********************************* 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_tree','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','info_block_method','security_index'] 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_tree = fields.CheckBoxField('report_tree', title='Report Tree', description=('Report Tree'), default='', 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=5, 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 Y-Axis', description=('Method for building Y-Axis' 'objects'), default='', required=0) info_block_method = fields.StringField('info_block_method', title='specific method for inserting infos in Block', description=('Method for inserting info' '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): # 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'] list_method = field.get_value('list_method') report_tree = field.get_value('report_tree') report_root_list = field.get_value('report_root_list') y_axis_method=field.get_value('y_axis_method') script=getattr(here,field.get_value('x_axis_script_id'),None) info_block_method = getattr(here,field.get_value('info_block_method'),None) object_start_method_id = field.get_value('x_start_bloc') object_stop_method_id= field.get_value('x_stop_bloc') form = field.aq_parent 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 coordinate but datas. x_axe=[] # will contain what wee need to display in X-axis. contains: (data used for construction, display of x-axis) yrange=[] # we store the value in Y-axis of each block nbr=1 y_max=1 current_top=height_header total=[] list_object=[] #in this list we store all the objects of type Line giant_string='' #will contain all the html code. report_sections=[] # END DATA DEFINITION ########################################### # we fetch fold/unfold datas ###################### #here.portal_selections.setSelectionFor(selection_name, None)#put selection to null selection = here.portal_selections.getSelectionFor(selection_name, REQUEST=REQUEST) default_params = {} sort = () if selection is None: selection = Selection(params=default_params, default_sort_on = sort) domain_list = list(selection.getDomainList()) here.portal_selections.setSelectionFor(selection_name, selection, REQUEST=REQUEST) ######################## #we build line *************************** (list_object,nbr_line,report_sections)=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) # end build line #################################################### #we build x_occurence (used for the range in x-Axis ################################## for o in report_sections: method_start = getattr(o.getObject(),object_start_method_id,None) method_stop= getattr(o.getObject(),object_stop_method_id,None) block_begin = method_start() if method_stop!=None: block_stop= method_stop() else: block_stop=None x_occurence.append([block_begin,block_stop]) x_axe=script(x_occurence,x_range) #we call this script for the range in X-Axis ################################################## # we add mobile block to the line object ################################### indic_line=0 #for o report_sections: for o in list_object: if list_object != []: list_object[indic_line].insertActivityBlock(report_sections[indic_line].getObject(),object_start_method_id,object_stop_method_id,x_axe,field) indic_line+=1 # ############################################################# # at this point list_object contains our tree of datas. Then wee add others object for the graphic. #one constructs the vertical dotted line ********************** marge_left=y_axis_width+width_line/float(len(x_axe[1])) for i in list_object: 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 list_object: i.appendHorizontalDottedLine(marge_top,maximum_y,height_global_div,height_header,height_axis_x,nbr_line,y_range,y_max,current_section) #end construct of horizontal dotted line ******************************************************** # we construct y-axis ****************************** way=[] y=[] level=0 current_top=height_header idx=0 for i in list_object: current_top=i.buildYtype(way,y,level,y_axis_width,height_global_div,height_header,height_axis_x,nbr_line,current_top,space_line,y_max,y_range,y_unity,selection_name,form) #current_top=y[len(y)-1].top+((height_global_div-height_header-height_axis_x)/float(nbr_line))+space_line current_top=y[len(y)-1].top+((height_global_div-height_header-height_axis_x-((nbr_line-1)*space_line))/float(nbr_line))+space_line idx+=1 list_object=y+list_object #we need to add the y-axis block at the beginning of our structure otherwise the display is not correct #************************end construct y-axis #build X axis ######################################## list_object.append(Line('','axis_x',y_axis_width,width_line,height_axis_x,current_top-space_line)) list_object[len(list_object)-1].createXAxis(x_axe,width_line,y_axis_width) #*************************** SESSION = REQUEST.SESSION SESSION.set('total',list_object) SESSION.set('width_line',width_line) SESSION.set('height_global', height_global_div) SESSION.set('y_axis_width', y_axis_width) SESSION.set('report_tree',report_tree) SESSION.set('report_root_list',report_root_list) SESSION.set('selection_name',selection_name) for i in list_object: giant_string+=i.render_css(y_axis_width,security_index) return giant_string def render(self,field, key, value, REQUEST): here = REQUEST['here'] portal_url= here.portal_url() SESSION = REQUEST.SESSION total = SESSION.get('total') width_line=SESSION.get('width_line') height_global_div=SESSION.get('height_global') y_axis_width=SESSION.get('y_axis_width') report_tree=SESSION.get('report_tree') report_root_list=SESSION.get('report_root_list') selection_name=SESSION.get('selection_name') giant_string='<input type=\"hidden\" name=\"list_selection_name\" value='+selection_name+' />\n' giant_string+='<div id=\"global_block\" style=\"position:absolute;width:'+str(width_line+y_axis_width)+'px;height:'+str(height_global_div)+'px;background:#d5e6de;margin-left:-99px;border-style:solid;border-color:#000000;border-width:1px;margin-top:-21px\">\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:20px;border-style:solid;border-color:#000000;border-width:1px;margin-top:1px\">' ##########################report tree # Create the header of the table with the name of the columns # Create also Report Tree Column if needed if report_tree: selection = here.portal_selections.getSelectionFor(selection_name, REQUEST=REQUEST) 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></div>""" % (here.getUrl(),report_tree_options) giant_string += report_popup else: report_popup = '' ###################################### for i in range(0,len(total)): giant_string+=total[i].render(portal_url,y_axis_width) ###################" giant_string+='<div id=\"lefttop\" style=\"position:absolute;width:5px;height:5px;background:#a45d10\"></div>\n' giant_string+='<div id=\"righttop\" style=\"position:absolute;width:5px;height:5px;background:#a45d10"></div>\n' giant_string+='<div id=\"rightbottom\" style=\"position:absolute;width:5px;height:5px;background:#a45d10\"></div>\n' giant_string+='<div id=\"leftbottom\" style=\"position:absolute;width:5px;height:5px;background:#a45d10\"></div>\n' giant_string+='<script type=\"text/javascript\">\n SET_DHTML(' for i in range(0,len(total)): graphic_call='' for j in total[i].content: if j.types=='activity': giant_string+='\"'+j.name+'\",' elif j.types=='info': giant_string+='\"'+j.name+'\"+NO_DRAG,' current_object=total[i] if current_object.soon!=[]: giant_string+=createGraphicCall(current_object,graphic_call) giant_string+='\"lefttop\"+CURSOR_NW_RESIZE, \"righttop\"+CURSOR_NE_RESIZE, \"rightbottom\"+CURSOR_SE_RESIZE, \"leftbottom\"+CURSOR_SW_RESIZE);\n' giant_string+='</script>\n </div> ' return giant_string #*************************************************** # class line ************************************** class Line: def __init__(self,title='',name='',begin=0,width=0,height=0,top=0,color='',soon=None,y_type='none',paternity=0,url=''): if soon is None: soon = [] self.title=title self.name=name self.begin=begin self.width=width self.height=height self.top=top self.content=[] self.color=color self.soon=soon 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 soon """ html_render='<div id=\"'+self.name+'\"></div>\n' for j in self.content: if j.types=='activity': if ((j.width*self.width)+(self.begin+j.begin*self.width)>self.width+y_axis_width): #checks if the block is too large for the end of the line if it is the case, one cuts the block html_render+='<div id=\"'+j.name+'\" ondblclick=\"showGrips()\" onclick=\"dd.elements.'+j.name+'.resizeTo('+str(round(j.width*self.width))+','+ str(j.height*(self.height-10))+') \">' elif ((self.begin+j.begin*self.width) < self.begin): #checks if the block starts before the beginning of the line html_render+='<div id=\"'+j.name+'\" ondblclick=\"showGrips()\" onclick=\"if (dd.elements.'+j.name+'.moved==0){dd.elements.'+j.name+'.moveBy('+str(round(j.begin*self.width))+',0);dd.elements.'+j.name+'.resizeTo('+str(round(j.width*self.width))+','+ str(j.height*(self.height-10))+');dd.elements.'+j.name+'.moved=1} \">' # "done" is used because otherwise everytime we move the block it will execute moveby() else: html_render+='<div id=\"'+j.name+'\" ondblclick=\"showGrips()\">' html_render+=j.render(self.width,self.height,portal_url,self.begin,y_axis_width) # we add info Block inside the div html_render+='</div>\n' elif j.types!='info': html_render+='<div id=\"'+j.name+'\">'+str(j.text)+'</div>\n' if self.soon!=[]: for i in self.soon: html_render+=i.render(portal_url,y_axis_width) return html_render def render_css(self,y_axis_width,security_index): css_render='#'+self.name+'{position:absolute;\nborder-style:solid;\nborder-color:#53676e;\nborder-width:1px;\n' 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=='soon1': css_render+='border-top-width:0px;\nborder-bottom-width:0px;\n' elif self.y_type=='soon2': css_render+='border-top-width:0px;' css_render+='width:'+str(self.width)+'px;\n}' for j in self.content: #we generate block's css if j.types=='activity': css_render+='#'+j.name+'{position:absolute;\nbackground:#bdd2e7;\nborder-style:solid;\nborder-color:#53676e;\nborder-width:1px;\n' css_render+='height:'+str((j.height*(self.height-10))-security_index)+'px;\n' #-10 because wee don't want a block sticked to border-top of the line # text=str('%.2f' %maximum_y)+y_unity if ((self.begin+j.begin*self.width) < self.begin): #checks if the block starts before the beginning of the line css_render+='margin-left:'+str(self.begin)+'px;\n' css_render+='width:'+str((j.width*self.width+j.begin*self.width))+'px;\n' elif ((j.width*self.width)+(self.begin+j.begin*self.width)>self.width+y_axis_width): #checks if the block is too large for the end of the line. if it is the case, one cuts the block css_render+='width:'+str(round(j.width*self.width)-((self.begin+j.begin*self.width+j.width*self.width)-(self.width+y_axis_width)))+'px;\n' css_render+='margin-left:'+str(round(self.begin+j.begin*self.width))+'px;\n' else: css_render+='width:'+str(round(j.width*self.width))+'px;\n' css_render+='margin-left:'+str(round(self.begin+j.begin*self.width))+'px;\n' css_render+='margin-top:'+str(self.top+10+j.marge_top*(self.height-10))+'px;}\n' css_render+=j.render_css(self.width,self.height-10,self,y_axis_width) # we add info Block inside the div elif j.types=='text_x' : css_render+='#'+j.name+'{position:absolute;\nborder-style:solid;\nborder-color:#53676e;\nborder-width:1px;\n' css_render+='margin-left:'+str(j.begin)+'px;\n' css_render+='margin-top:'+str(round(1+self.top+self.height/2))+'px;}\n' elif j.types=='text_y': css_render+='#'+j.name+'{position:absolute;\nborder-style:solid;\nborder-color:#53676e;\nborder-width:1px;\n' css_render+='margin-left:'+str(self.width/4)+'px;\n' css_render+='margin-top:'+str(round(1+self.top+self.height/2))+'px;\n' css_render+='border-width:0px;}\n' elif j.types=='vertical_dotted': css_render+='#'+j.name+'{position:absolute;\nborder-style:dotted;\nborder-color:#53676e;\nborder-left-width:1px;\nborder-right-width:0px;\nborder-top-width:0px;\nborder-bottom-width:0px;\n' css_render+='margin-left:'+str(j.begin)+'px;\n' css_render+='height:'+str(self.height)+'px;\n' css_render+='margin-top:'+str(1+round(self.top))+'px;}\n' elif j.types=='horizontal_dotted': css_render+='#'+j.name+'{position:absolute;\nborder-style:dotted;\nborder-color:#53676e;\nborder-left-width:0px;\nborder-right-width:0px;\nborder-top-width:1px;\nborder-bottom-width:0px;\n' css_render+='margin-left:'+str(self.begin)+'px;\n' css_render+='height:1px;\n' css_render+='margin-top:'+str(self.top+j.marge_top)+'px;' css_render+='width:'+str(self.width)+'px;}\n' elif j.types=='y_coord': css_render+='#'+j.name+'{position:absolute;\nborder-style:solid;\nborder-color:#53676e;\nfont-size:9px;\nborder-width:0px;\n' css_render+='margin-left:'+str(self.width-(len(j.text)*5))+'px;\n' #x6 because this is the appropriate width for our font (9px), maybee need to be parameter css_render+='margin-top:'+str(self.top+j.marge_top)+'px;}\n' elif j.types=='vertical': css_render+='#'+j.name+'{position:absolute;\nborder-style:solid;\nborder-color:#53676e;\nborder-left-width:1px;\nborder-right-width:0px;\nborder-top-width:0px;\nborder-bottom-width:0px;\n' css_render+='margin-left:'+str((self.width/4)+j.begin)+'px;\n' css_render+='height:'+str(j.height)+'px;\n' css_render+='margin-top:'+str(round(self.top)-self.height/2+13)+'px;}\n' elif j.types=='horizontal': css_render+='#'+j.name+'{position:absolute;\nborder-style:solid;\nborder-color:#53676e;\nborder-left-width:0px;\nborder-right-width:0px;\nborder-top-width:1px;\nborder-bottom-width:0px;\n' css_render+='margin-left:'+str((self.width/4)+j.begin)+'px;\n' css_render+='width:16px;\n' css_render+='height:1px; \n' # css_render+='margin-top:'+str(round(self.top)-self.height/2+13)+'px;}\n' css_render+='margin-top:'+str(round(1+self.top+self.height/2))+'px;}\n' if self.soon!=[]: for i in self.soon: css_render+=i.render_css(y_axis_width,security_index); return css_render def addBlock(self,name,block): self.content.append(Block('activity',name,block[0],block[1],block[2],'',block[3],block[4])) def addBlockInfo(self,name): self.content.append(Block('info',name,0,0,0,'')) def addBlockTextY(self,name,text): self.content.append(Block('text_y',name,0,0,0,text)) def addBlockCoordY(self,name,text,marge_top): self.content.append(Block('y_coord',name,0,0,0,text,{},marge_top)) def addBlockTextX(self,name,begin,text): self.content.append(Block('text_x',name,begin,0,0,text)) def addBlockDottedVert(self,name,begin): self.content.append(Block('vertical_dotted',name,begin,0,0,'')) def addBlockDottedHoriz(self,name,marge_top): self.content.append(Block('horizontal_dotted',name,0,0,0,'',{},marge_top)) def addBlockVertical(self,name,marge_top,height,marge_left): self.content.append(Block('vertical',name,marge_left,0,height,'',{},marge_top)) def addBlockHorizontal(self,name,marge_top,height,marge_left): self.content.append(Block('horizontal',name,marge_left,0,height,'',{},marge_top)) def appendVerticalDottedLine(self,x_axe,width_line,marge_left): 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.soon!=[]: for i in self.soon: i.appendVerticalDottedLine(x_axe,width_line,marge_left) def buildYtype(self,way,y,level,y_axis_width,height_global_div,height_header,height_axis_x,nbr_line,current_top,space_line,y_max,y_range,y_unity,selection_name,form): """ 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 'soon1' or 'soon2' """ report_url=self.url if level==0: name='axis'+str(self.name) if self.soon!=[]: 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.soon!=[]: y[len(y)-1].addBlockTextY('ytext'+name,str(3*'  '*level)+'<a href="portal_selections/foldReport?report_url='+report_url+'&form_id='+form.id+'&list_selection_name='+selection_name+'">-'+self.title+'</a>') else: y[len(y)-1].addBlockTextY('ytext'+name,str(3*'  '*level)+'<a href="portal_selections/unfoldReport?report_url='+report_url+'&form_id='+form.id+'&list_selection_name='+selection_name+'">+'+self.title+'</a>') else: y[len(y)-1].addBlockTextY('ytext'+name,str(3*'  '*level)+self.title) #one constructs the indicators if y_range!=0: y[len(y)-1].createIndicators(y_unity,y_range,y_max,height_global_div,height_header,height_axis_x,nbr_line) if self.soon!=[]: level+=1 for j in range(0,len(self.soon)): if j==(len(self.soon)-1): way.append(1) else: way.append(0) current_top+=((height_global_div-height_header-height_axis_x)/float(nbr_line)) current_top=self.soon[j].buildYtype(way,y,level,y_axis_width,height_global_div,height_header,height_axis_x,nbr_line,current_top,space_line,y_max,y_range,y_unity,selection_name,form) del way[len(way)-1] else: if self.soon!=[]: 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,'',[],'soon1')) if self.paternity==1: if self.soon!=[]: y[len(y)-1].addBlockTextY('ytext'+name,str(3*'  '*level)+'<a href="portal_selections/foldReport?report_url='+report_url+'&form_id='+form.id+'&list_selection_name='+selection_name+'">-'+self.title+'</a>') else: y[len(y)-1].addBlockTextY('ytext'+name,str(3*'  '*level)+'<a href="portal_selections/unfoldReport?report_url='+report_url+'&form_id='+form.id+'&list_selection_name='+selection_name+'">+'+self.title+'</a>') else: y[len(y)-1].addBlockTextY('ytext'+name,str(3*'  '*level)+self.title) # one constructs the stick y[len(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*6-18) #6 is the width of the standart font, maybe a future parameter y[len(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*6-18) #one constructs the indicators if y_range!=0: y[len(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.soon)): current_top+=((height_global_div-height_header-height_axis_x-((nbr_line-1)*space_line))/float(nbr_line)) if j==(len(self.soon)-1): way.append(1) else: way.append(0) current_top=self.soon[j].buildYtype(way,y,level,y_axis_width,height_global_div,height_header,height_axis_x,nbr_line,current_top,space_line,y_max,y_range,y_unity,selection_name,form) del way[len(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,'',[],'soon2')) 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,'',[],'soon1')) if self.paternity==1: if self.soon!=[]: y[len(y)-1].addBlockTextY('ytext'+name,str(3*'  '*level)+'<a href="portal_selections/foldReport?report_url='+report_url+'&form_id='+form.id+'&list_selection_name='+selection_name+'">-'+self.title+'</a>') else: y[len(y)-1].addBlockTextY('ytext'+name,str(3*'  '*level)+'<a href="portal_selections/unfoldReport?report_url='+report_url+'&form_id='+form.id+'&list_selection_name='+selection_name+'">+'+self.title+'</a>') else: y[len(y)-1].addBlockTextY('ytext'+name,str(3*'  '*level)+self.title) # one constructs the sticks y[len(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*6-18) y[len(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*6-18) #one constructs the indicators if y_range!=0: y[len(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): #one constructs the indicators maximum_y=y_max marge_top=0 indic=0 #while maximum_y>=(y_max/float(y_range)): 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): current_top=marge_top max_y=maximum_y indic=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 current_top+=(((height_global_div-height_header-height_axis_x)/float(nbr_line))-marge_top)/y_range #10px under the top of the line . float is important here! """ indic+=1 if self.soon!=[]: for i in self.soon: 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): indic=0 for data_block in list_block: self.addBlock('ActivityBlock_'+self.name+'_'+str(indic),data_block) indic+=1 def createXAxis(self,x_axe,width_line,y_axis_width): marge_left=y_axis_width indic1=0 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 addSoon(self,soon): self.soon.append(soon) def createLineChild(self,report_section,field,current_top,y_axis_width,width_line,space_line,height_global_div,height_header,height_axis_x,nbr_line,current_index,url): if len(report_section[current_index].getObject().objectValues())!=0: paternity=1 else: paternity=0 soon=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)/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)/float(nbr_line))+space_line else: current_top=current_top+((height_global_div-height_header-height_axis_x)/float(nbr_line)) self.addSoon(soon) return current_top def insertActivityBlock(self,line_content,object_start_method_id,object_stop_method_id,x_axe,field): marge=0 method_start = getattr(line_content,object_start_method_id,None) method_stop= getattr(line_content,object_stop_method_id,None) block_begin = method_start() list_block=[] if method_stop!=None: block_stop= method_stop() else: block_stop=None for i in x_axe[0]: if isinstance(block_begin,DateTime): comp_test1=block_begin.Date()==i else: comp_test1=block_begin==i if comp_test1==True: list_block.append([marge,(block_stop-block_begin)/(float(len(x_axe[0]))),0.75,{},0.25]) # 0.75(height) need to be defined marge+=1/float(len(x_axe[0])) if list_block!=[]: self.appendActivityBlock(list_block) if self.soon!=[]: script_x=getattr(line_content,field.get_value('data_method'),None) soon_line=script_x() indic=0 for s in soon_line: self.soon[indic].insertActivityBlock(soon_line[indic],object_start_method_id,object_stop_method_id,x_axe,field) indic+=1 #************************************************* # class block *********************************** class Block: def __init__(self,types,name,begin,width=0,height=0,text='',content={},marge_top=0): self.types=types self.name=name self.begin=begin self.width=width self.height=height self.text=text self.content=content self.marge_top=marge_top # self.color=color need to be implemented in the future! def render(self,line_width,line_height,portal_url,line_begin,y_axis_width): """used for inserting text in a block. one calculates how to organise the space. one defines a width and height parameter (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) # NEED TO BE TESTED !!! def render_css(self,line_width,line_height,line,y_axis_width): string='' font_height=10 font_width=6 line_begin=line.begin if ((line_begin+self.begin*line_width) < line_begin): #checks if the block starts before the beginning of the line block_width=self.width+self.begin elif ((self.width*line_width)+(line_begin+self.begin*line_width)>line_width+y_axis_width): #checks if the block is too large for the end of the line. if it is the case, one cuts the block 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) # NEED TO BE TESTED!! #case with five informations #************************************************************************ def addInfoCenter(self,info): #add info in the top left corner 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): """ create the body of the html for displaying info inside a block""" displayed1=['center','topright','topleft','botleft','botright'] displayed1=displayed1[0:len(self.content)] string='' for i in displayed1: displayed[i]=0 if len(self.content)==5: test_height= font_height<=((self.height*line_height)/3) test_width= ((len(self.content[i])*font_width)<=((block_width*line_width)/3)) if len(self.content)==4 or len(self.content)==3: test_height= font_height<=((self.height*line_height)/2) test_width= ((len(self.content[i])*font_width)<=((block_width*line_width)/2)) if len(self.content)==2: test_height=font_height<=(self.height*line_height) test_width= (len(self.content[i]*font_width)<=((block_width*line_width)/2)) if len(self.content)==1: test_height= font_height<=(self.height*line_height) test_width= (len(self.content[i]*font_width)<=(block_width*line_width)) for i in self.content: if test_height & test_width: string+='<div id=\"'+self.name+i+'\">'+ self.content[i] string+='</div>\n' displayed[i]=1 #******************checks if we need to add interrogation.png if ((self.width*line_width>=15) & (self.height*line_height>=15)): order=displayed1 for i in order: if displayed[i]==0: info+=self.content[i]+'|' for i in order: if displayed[i]==0: string+='<div id=\"'+self.name+i+'\" title=\"'+info+'\"><img src=\"'+portal_url+'/images/question.png\" height=\"15\" width=\"15\"> ' string+='</div>\n' break #****************** return string #************************************************** #******************************************* def buildInfoBlockCss(self,font_height,line_height,block_width,line_width): """use for creating css code when one needs to add info inside a block""" displayed1=['center','topright','topleft','botleft','botright'] displayed1=displayed1[0:len(self.content)] string='' for i in displayed1: displayed[i]=0 if len(self.content)==5: test_height= font_height<=((self.height*line_height)/3) test_width= ((len(self.content[i])*font_width)<=((block_width*line_width)/3)) if len(self.content)==4 or len(self.content)==3: test_height= font_height<=((self.height*line_height)/2) test_width= ((len(self.content[i])*font_width)<=((block_width*line_width)/2)) if len(self.content)==2: test_height=font_height<=(self.height*line_height) test_width= (len(self.content[i]*font_width)<=((block_width*line_width)/2)) if len(self.content)==1: test_height= font_height<=(self.height*line_height) test_width= (len(self.content[i]*font_width)<=(block_width*line_width)) elif len(self.content)==0: return '' matrix = {('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}, ('topleft',5):{'left':0,'top':0},('topleft',4):{'left':1,'top':1},('topleft',3):{'left':0,'top':0}, ('botleft',5):{'left':0,'top':1},('topleft',4):{'left':0,'top':1}, ('botright',5):{'left':1,'top':1} } 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}, ('topleft',5):{'left':0,'top':0},('topleft',4):{'left':1,'top':1},('topleft',3):{'left':0,'top':0}, ('botleft',5):{'left':0,'top':1},('topleft',4):{'left':0,'top':1}, ('botright',5):{'left':1,'top':1} } for i in self.content: for counter in range(1,5): matrix_data = matrix[(i,counter)] 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[i]))/left) if top==0: margin_top=0 else: margin_top = round(((self.height*line_height)/top)-(font_height/top)) if test_height & test_width: string+='#'+self.name+i+'{position:absolute;\nmargin-left:'+str(margin_left)+'px;\nmargin-top:'+str(margin_top)+'px;\n}\n' displayed[i]=1 line.addBlockInfo(self.name+i) #******************checks if we need to add interrogation.png if ((block_width*line_width>=15) & (self.height*line_height>=15)): order=('center','topright','topleft','botleft','botright') for i in order: for counter in range(1,5): matrix_data= matrix [(i,counter)] 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)/top)-(15/top)) margin_top = round(((self.height*line_height)/top)-(font_height/top)) if i=='center' & counter==3: margin_left=round(((block_width*line_width)/left)-(font_width*len(self.content[i]))/left) margin_top=round(((self.height*line_height)/top)-(font_height/top)) if i=='center' & counter==2: margin_top=round(((self.height*line_height)/top)-(font_height/top)) string+='#'+self.name+i+'{position:absolute;\nmargin-left:'+str(margin_left)+'px;\nmargin-top:'+str(margin_top)+'0px;\n}' line.addBlockInfo(self.name+i) return string ##################################################### PlanningBoxWidgetInstance = PlanningBoxWidget() class PlanningBox(ZMIField): meta_type = "PlanningBox" widget = PlanningBoxWidgetInstance validator = PlanningBoxValidatorInstance security = ClassSecurityInfo() security.declareProtected('Access contents information', 'get_value') 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')) else: return ZMIField.get_value(self, id, **kw) def render_css(self, value=None, REQUEST=None): return self.widget.render_css(self,'',value,REQUEST)