OOoChart.py 20.3 KB
Newer Older
Jean-Paul Smets's avatar
Jean-Paul Smets committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
##############################################################################
#
# Copyright (c) 2007 Nexedi SA and Contributors. All Rights Reserved.
#                    Jean-Paul Smets <jp@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.
#
##############################################################################

from Products.Formulator import Widget
from Products.Formulator import Widget, Validator
from Products.Formulator.DummyField import fields
from Products.Formulator.Field import ZMIField
from Selection import Selection
Nicolas Delaby's avatar
Nicolas Delaby committed
34 35 36 37
from Globals import get_request
from Products.ERP5OOo.Document.OOoDocument import STANDARD_IMAGE_FORMAT_LIST

from zLOG import LOG
Jean-Paul Smets's avatar
Jean-Paul Smets committed
38 39 40 41 42 43

class OOoChartWidget(Widget.Widget):
  """
  This class is capabale of producing ODF
  charts based on data obtained through a
  listbox.
Nicolas Delaby's avatar
Nicolas Delaby committed
44 45 46 47 48 49 50 51 52
  Some properties are useless
  http://books.evc-cit.info/odbook/ch08.html#chart-plot-area-example
    - mean-value
    - error-margin
    - error-upper-limit
    - error-lower-limit
    - error-category
    - error-percentage
    - chart-japanese-candle-stick and stock-with-volume,chart:stock-updown-bars. These attributs are used with a chart:stock
Jean-Paul Smets's avatar
Jean-Paul Smets committed
53
  """
54

Jean-Paul Smets's avatar
Jean-Paul Smets committed
55
  property_names = list(Widget.Widget.property_names)
56 57 58 59 60 61 62 63 64

  default = fields.StringField(
                                'default',
                                title='Default',
                                description=(
    "A default value (not used)."),
                                default="",
                                required=0)

65 66 67
  listbox_form_id = fields.StringField(
                              'listbox_form_id',
                              title='ListBox Form ID',
Nicolas Delaby's avatar
Nicolas Delaby committed
68 69 70
                              description= \
                                "ID of the master form.",
                              default="",
71
                              required=0)
72
  property_names.append('listbox_form_id')
Jean-Paul Smets's avatar
Jean-Paul Smets committed
73

74 75 76
  listbox_id = fields.StringField(
                              'listbox_id',
                              title='ListBox ID',
Nicolas Delaby's avatar
Nicolas Delaby committed
77 78 79
                              description= \
                                "ID of the listbox in the master form.",
                              default="",
80
                              required=0)
81
  property_names.append('listbox_id')
Jean-Paul Smets's avatar
Jean-Paul Smets committed
82

Nicolas Delaby's avatar
Nicolas Delaby committed
83 84 85 86 87 88 89 90 91 92 93 94 95
  image_display = fields.ListField('image_display',
                            title='Image Display',
                            description=(
          "Render size of this chart in HTML mode."),
                            default='medium',
                                  items=[('thumbnail','thumbnail'),
                                        ('xsmall', 'xsmall'),
                                        ('small', 'small'),
                                        ('medium', 'medium'),
                                        ('large', 'large'),
                                        ('xlarge', 'xlarge'),
                                        ],
                                  size=1)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
96 97 98
  property_names.append('image_display')

  image_format = fields.StringField('image_format',
Nicolas Delaby's avatar
Nicolas Delaby committed
99 100 101 102 103
                            title='Image Format',
                            description=(
    "The format in which the chart should be converted to."),
                            default='png',
                            required=0)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
104 105 106
  property_names.append('image_format')

  ooo_template = fields.StringField('ooo_template',
Nicolas Delaby's avatar
Nicolas Delaby committed
107 108 109 110 111
                              title='OOo Template',
                              description=('The ID of a OOo Page Template'
                                          ' to render the ListBox'),
                              default='ERP5Site_viewChart',
                              required=0)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
112 113
  property_names.append('ooo_template')

Nicolas Delaby's avatar
Nicolas Delaby committed
114 115

  chart_type = fields.ListField('chart_type',
116
                                  title='Chart Type',
Nicolas Delaby's avatar
Nicolas Delaby committed
117 118 119 120 121
                                  description=('Type of the Chart'),
                                  default='chart:bar',
                                  items=[('bar', 'chart:bar'),
                                        ('circle', 'chart:circle'),
                                        ('line', 'chart:line'),
122
                                        ('scatter', 'chart:scatter'),
Nicolas Delaby's avatar
Nicolas Delaby committed
123 124 125 126 127
                                        ],
                                  size=0)
  property_names.append('chart_type')


Jean-Paul Smets's avatar
Jean-Paul Smets committed
128
  colour_column_list = fields.ListTextAreaField('colour_column_list',
129
                              title="Data Color",
Nicolas Delaby's avatar
Nicolas Delaby committed
130
                              description=(
131
    "A list of colors for each data associated to a column."),
Nicolas Delaby's avatar
Nicolas Delaby committed
132
                              default=[],
133
                              required=0)
Nicolas Delaby's avatar
Nicolas Delaby committed
134 135 136 137
  property_names.append('colour_column_list')

  # vertical ="true"
  chart_position = fields.ListField('chart_position',
138
                                   title='Bar Position',
Nicolas Delaby's avatar
Nicolas Delaby committed
139
                                   description=('Render the bar in horizontal position or vertical position'),
140
                                   default='false',
Nicolas Delaby's avatar
Nicolas Delaby committed
141 142 143 144 145
                                   items=[('horizontal', 'true'),
                                          ('vertical', 'false'),
                                          ],
                                   size=0)
  property_names.append('chart_position')
146

Nicolas Delaby's avatar
Nicolas Delaby committed
147 148 149 150 151 152 153
  #legend of the chart or not
  chart_legend = fields.CheckBoxField('chart_legend',
                                         title='Chart Legend',
                                         description=('Show Chart Legend or no'),
                                         default=1,
                                         required=0)
  property_names.append('chart_legend')
154 155


Nicolas Delaby's avatar
Nicolas Delaby committed
156
  position_legend = fields.ListField('position_legend',
157
                                       title='Legend Position',
Nicolas Delaby's avatar
Nicolas Delaby committed
158 159 160 161 162 163 164 165 166 167 168 169
                                       description=('Legend Position according to the graph'),
                                       default='end',
                                       items=[('bottom', 'bottom'),
                                              ('end', 'end'),
                                              ('start', 'start'),
                                              ('top', 'top'),
                                              ],
                                       size=1)
  property_names.append('position_legend')

  #legend of the chart or not
  chart_title_or_no = fields.CheckBoxField('chart_title_or_no',
170
                                         title='Chart Title ',
Nicolas Delaby's avatar
Nicolas Delaby committed
171 172 173 174
                                         description=('Show Title on Graph or no '),
                                         default=1,
                                         required=0)
  property_names.append('chart_title_or_no')
175

Nicolas Delaby's avatar
Nicolas Delaby committed
176 177
  #grid or not
  grid_graph = fields.CheckBoxField('grid_graph',
178
                                         title='Chart Grid ',
Nicolas Delaby's avatar
Nicolas Delaby committed
179 180 181 182
                                         description=('Show Grid or no'),
                                         default=1,
                                         required=0)
  property_names.append('grid_graph')
183 184


Nicolas Delaby's avatar
Nicolas Delaby committed
185 186 187 188 189 190 191 192 193
  grid_size = fields.ListField('grid_size',
                                   title='Grid Size',
                                   description=('Render a big grid size or a small grid size'),
                                   default='major',
                                   items=[('major', 'major'),
                                          ('minor', 'minor'),
                                          ],
                                   size=0)
  property_names.append('grid_size')
194

Nicolas Delaby's avatar
Nicolas Delaby committed
195
  user_data_title = fields.StringField('user_data_title',
196
                                title="Overide Labelled Column ID",
Jean-Paul Smets's avatar
Jean-Paul Smets committed
197
                                description=(
198
      "Column Id choose by user to define the label."),
Nicolas Delaby's avatar
Nicolas Delaby committed
199 200 201 202
                                required=0)
  property_names.append('user_data_title')

  user_column_id_list = fields.ListTextAreaField('user_column_id_list',
203
                                title="Overide Column Ids",
Nicolas Delaby's avatar
Nicolas Delaby committed
204
                                description=(
205
      "A list of column Ids choose by user to draw the graph."),
Jean-Paul Smets's avatar
Jean-Paul Smets committed
206
                                default=[],
Nicolas Delaby's avatar
Nicolas Delaby committed
207 208
                                required=0)
  property_names.append('user_column_id_list')
Jean-Paul Smets's avatar
Jean-Paul Smets committed
209

Nicolas Delaby's avatar
Nicolas Delaby committed
210 211

  chart_stacked = fields.CheckBoxField('chart_stacked',
212 213
                              title='Stacked Data',
                              description=('stacked data or not'),
Jean-Paul Smets's avatar
Jean-Paul Smets committed
214 215
                              default=0,
                              required=0)
Nicolas Delaby's avatar
Nicolas Delaby committed
216 217 218 219 220 221 222 223 224
  property_names.append('chart_stacked')

  #connect-bars="false"
  connect_bars = fields.CheckBoxField('connect_bars',
                                      title='Connect Bars',
                                      description=(''),
                                      default=0,
                                      required=0)
  property_names.append('connect_bars')
Jean-Paul Smets's avatar
Jean-Paul Smets committed
225 226 227 228 229 230 231 232 233


  chart_three_dimensional = fields.CheckBoxField('chart_three_dimensional',
                              title='3D',
                              description=('Render the chart in three dimensions rather in flat mode'),
                              default=0,
                              required=0)
  property_names.append('chart_three_dimensional')

Nicolas Delaby's avatar
Nicolas Delaby committed
234 235 236 237
  #deep="false"
  deep = fields.CheckBoxField('deep',
                              title='Deep',
                              description=('Deep'),
238 239
                              default=0,
                              required=0)
Nicolas Delaby's avatar
Nicolas Delaby committed
240
  property_names.append('deep')
241

Nicolas Delaby's avatar
Nicolas Delaby committed
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
  # sector_pie_offset Default:0
  sector_pie_offset = fields.IntegerField('sector_pie_offset',
                                        title='Sector Pie Offset',
                                        description=(''),
                                        default=0,
                                        required=0)
  property_names.append('sector_pie_offset')
  


  #interpolation="none", cubic-spline, b-spline
  interpolation = fields.ListField('interpolation',
                                   title='Interpolation',
                                   description=(''),
                                   default='none',
                                   items=[('none', 'none'),
                                          ('cubic-spline', 'cubic-spline'),
                                          ('b-spline', 'b-spline')],
                                   size=1)
  property_names.append('interpolation')

  #symbol-type="none", automatic
  symbol_type = fields.ListField('symbol_type',
                                 title='Symbol Type',
                                 description=(''),
                                 default='none',
                                 items=[('none', 'none'),
                                        ('automatic', 'automatic'),],
                                 size=1)
  property_names.append('symbol_type')

  #lines-used="0" 
  lines_used = fields.ListField('lines_used',
                                title='Lines Used',
                                description=(''),
                                default='0',
                                items=[('0', '0'),
                                       ('1', '1')],
                                size=1)
  property_names.append('lines_used')

283

Nicolas Delaby's avatar
Nicolas Delaby committed
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
  #series-source=columns or rows
  series_source = fields.ListField('series_source',
                                   title='Series Source',
                                   description=(''),
                                   default='columns',
                                   items=[('columns', 'columns'),
                                          ('rows', 'rows'),],
                                   size=1)
  property_names.append('series_source')

  #regression-type="none" linear logarithmic exponential power
  regression_type = fields.ListField('regression_type',
                                     title='Regression Type',
                                     description=(''),
                                     default='none',
                                     items=[('none', 'none'),
                                            ('linear', 'linear'),
                                            ('logarithmic', 'logarithmic'),
                                            ('exponential', 'exponential'),
                                            ('power', 'power')],
                                     size=1)
  property_names.append('regression_type')

  #data-label-number="none" value percentage
  data_label_number = fields.ListField('data_label_number',
309
                                       title='Data Label Number',
Nicolas Delaby's avatar
Nicolas Delaby committed
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
                                       description=(''),
                                       default='none',
                                       items=[('none', 'none'),
                                              ('value', 'value'),
                                              ('percentage', 'percentage')],
                                       size=1)
  property_names.append('data_label_number')

  #data-label-text="false"
  data_label_text = fields.CheckBoxField('data_label_text',
                                         title='Data Label Text',
                                         description=(''),
                                         default=0,
                                         required=0)
  property_names.append('data_label_text')

  #data-label-symbol="false"
  data_label_symbol = fields.CheckBoxField('data_label_symbol',
                                           title='Data Label Symbol',
                                           description=(''),
                                           default=0,
                                           required=0)
  property_names.append('data_label_symbol')
Jean-Paul Smets's avatar
Jean-Paul Smets committed
333

334 335 336 337 338

  def getArgumentDict(self, field, REQUEST):
    """ Build argument Dict """
    def stringBoolean(value):
      return str(bool(value)).lower()
339
    form = field.aq_parent
340 341 342 343 344 345
    listbox_form_id = field.get_value('listbox_form_id')
    if listbox_form_id in ('', None):
      listbox_form_id = form.getId()
    listbox_id = field.get_value('listbox_id')
    if listbox_id in ('', None):
      listbox_id = 'listbox'
346
    extra_argument_dict = dict(
347 348
      chart_form_id = listbox_form_id,
      chart_field_id = listbox_id,
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
      chart_title = field.get_value('title'),
      chart_type = field.get_value('chart_type'),
      colour_column_dict = dict(field.get_value('colour_column_list')),
      user_column_id_dict = dict(field.get_value('user_column_id_list')),
      user_data_title= field.get_value('user_data_title'),
      chart_position = field.get_value('chart_position'),
      chart_legend = stringBoolean(field.get_value('chart_legend')),
      chart_title_or_no = stringBoolean(field.get_value('chart_title_or_no')),
      grid_graph = stringBoolean(field.get_value('grid_graph')),
      grid_size=field.get_value('grid_size'),
      chart_three_dimensional = stringBoolean(field.get_value('chart_three_dimensional')),
      deep = stringBoolean(field.get_value('deep')),
      chart_stacked = stringBoolean(field.get_value('chart_stacked')),
      sector_pie_offset = field.get_value('sector_pie_offset'),
      interpolation = field.get_value('interpolation'),
      symbol_type = field.get_value('symbol_type'),
      lines_used = field.get_value('lines_used'),
      connect_bars = stringBoolean(field.get_value('connect_bars')),
      series_source = field.get_value('series_source'),
      regression_type = field.get_value('regression_type'),
      data_label_number = field.get_value('data_label_number'),
      data_label_text = stringBoolean(field.get_value('data_label_text')),
      data_label_symbol = stringBoolean(field.get_value('data_label_symbol')),
      position_legend=field.get_value('position_legend'),
    )

    for k, v in extra_argument_dict.items():
      if REQUEST.get(k) is None:
        REQUEST.form[k] = v
    return extra_argument_dict


381
  def render_view(self, field, value, key=None, REQUEST=None, render_format='html'):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
382 383 384 385
    """
      Render a Chart in read-only.
    """
    if REQUEST is None: REQUEST=get_request()
386
    return self.render(field, key, value, REQUEST, render_format=render_format)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
387

388 389 390 391 392 393 394 395 396

  def render_odf(self, field, key, value, REQUEST, render_format='ooo'):
    """
      Render a Chart for ODT Style.
    """
    form = field.aq_parent
    here = getattr(form, 'aq_parent', REQUEST)
    extra_context = self.getArgumentDict(field, here.REQUEST)
    content = '''
397
                  <office:include path="%s/ERP5Site_buildChart" xlink:type="simple" xlink:actuate="onLoad" xlink:show="embed"/>
398 399 400 401
                  ''' % here.getPath()
    return content


Jean-Paul Smets's avatar
Jean-Paul Smets committed
402 403 404 405 406 407 408 409 410 411 412 413 414 415
  def render(self, field, key, value, REQUEST, render_format='html'):

    """
      Render a chart.

      render_format   -- If the format is set to html, render the chart
                         as a URL to ourselves with a png render_format

                         If the format is set to 'raw', render the chart
                         as raw XML.

                         If the format is set to an image type (ex. png)
                         render the chart using that format.
    """
416

Jean-Paul Smets's avatar
Jean-Paul Smets committed
417
    title = field.get_value('title')
Nicolas Delaby's avatar
Nicolas Delaby committed
418 419
    alternate_name = field.get_value('alternate_name')
    form = field.aq_parent
420

421
    # Find the applicable context
Nicolas Delaby's avatar
Nicolas Delaby committed
422
    here = getattr(form, 'aq_parent', REQUEST)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
423 424
    # Update the render format based on REQUEST parameters
    render_format = getattr(REQUEST, 'render_format', render_format)
Nicolas Delaby's avatar
Nicolas Delaby committed
425 426
    UrlIconOOo='%s/misc_/ERP5OOo/OOo.png' % here.ERP5Site_getAbsoluteUrl()
    UrlIconPdf='%s/misc_/ERP5Form/PDF.png' % here.ERP5Site_getAbsoluteUrl()
Nicolas Delaby's avatar
Nicolas Delaby committed
427 428 429 430
    if render_format == 'html':
      field_absolute_url = '%s/%s/%s' % (here.absolute_url(),
                                         form.getId(),
                                         field.getId())
Jean-Paul Smets's avatar
Jean-Paul Smets committed
431
      css_class = field.get_value('css_class')
432
      format = field.get_value('image_format') or 'png'
Jean-Paul Smets's avatar
Jean-Paul Smets committed
433
      display = field.get_value('image_display')
Nicolas Delaby's avatar
Nicolas Delaby committed
434 435
      if format in STANDARD_IMAGE_FORMAT_LIST:
        main_content = '''<div class="OOoChartContent">
Nicolas Delaby's avatar
Nicolas Delaby committed
436
          <img class="%s" src="%s?render_format=%s&display=%s" title="%s" alt="%s"/">
Nicolas Delaby's avatar
Nicolas Delaby committed
437
          </div>''' % (css_class,
Nicolas Delaby's avatar
Nicolas Delaby committed
438
                       field_absolute_url,
Nicolas Delaby's avatar
Nicolas Delaby committed
439 440 441 442
                       format,
                       display,
                       title,
                       alternate_name)
Nicolas Delaby's avatar
Nicolas Delaby committed
443
        return main_content
444
      elif format == 'raw':
Nicolas Delaby's avatar
Nicolas Delaby committed
445
        main_content = '''<div class="OOoChartContent">
Nicolas Delaby's avatar
Nicolas Delaby committed
446 447
          <a href="%s?render_format=&display=%s"><img src="%s" alt="OOo"/></a></div>
          ''' % (field_absolute_url,
Nicolas Delaby's avatar
Nicolas Delaby committed
448 449
                 display,
                 UrlIconOOo)
Nicolas Delaby's avatar
Nicolas Delaby committed
450
        return main_content
451
      elif format == 'pdf':
Nicolas Delaby's avatar
Nicolas Delaby committed
452
        main_content = '''<div class="OOoChartContent">
Nicolas Delaby's avatar
Nicolas Delaby committed
453 454
          <a href="%s?render_format=pdf&display=%s"><img src="%s" alt="PDF" /></a>
          </div>''' % (field_absolute_url,
Nicolas Delaby's avatar
Nicolas Delaby committed
455 456
                       display,
                       UrlIconPdf)
Nicolas Delaby's avatar
Nicolas Delaby committed
457
        return main_content
458 459
      else:
        raise NotImplementedError, 'Format: %s not handled' % format
Jean-Paul Smets's avatar
Jean-Paul Smets committed
460

461
    extra_context = self.getArgumentDict(field, REQUEST)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
462 463

    method_id = field.get_value('ooo_template')
464

Nicolas Delaby's avatar
Nicolas Delaby committed
465
    # Find the page template
Jean-Paul Smets's avatar
Jean-Paul Smets committed
466
    ooo_template = getattr(here, method_id)
467

Jean-Paul Smets's avatar
Jean-Paul Smets committed
468 469 470 471
    # Render the chart
    return ooo_template(format=render_format)

class OOoChartValidator(Validator.Validator):
Nicolas Delaby's avatar
Nicolas Delaby committed
472 473
  """
  """
474
  property_names =Validator.Validator.property_names
Jean-Paul Smets's avatar
Jean-Paul Smets committed
475

476 477 478
  def validate(self, key,field,  REQUEST):

    return {}
Nicolas Delaby's avatar
Nicolas Delaby committed
479 480

OOoChartWidgetInstance = OOoChartWidget()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
481 482 483 484 485 486
OOoChartValidatorInstance = OOoChartValidator()

class OOoChart(ZMIField):
    meta_type = "OOoChart"
    widget = OOoChartWidgetInstance
    validator = OOoChartValidatorInstance