source: main/waeup.kofa/trunk/src/waeup/kofa/widgets/datetimewidget.py @ 8165

Last change on this file since 8165 was 8165, checked in by uli, 13 years ago

Rollback r8162.

File size: 6.3 KB
Line 
1## $Id$
2##
3## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""
19A datewidget with customizable date format.
20"""
21from datetime import datetime
22from zope.formlib.interfaces import ConversionError, IDisplayWidget
23from zope.formlib.textwidgets import (
24    DatetimeWidget, DatetimeDisplayWidget, escape)
25from zope.formlib.widget import renderElement, CustomWidgetFactory
26from zope.interface import implements
27
28#: A dictionary of supported datetime formats.
29#:
30#: The following formats are supported:
31#:
32#: ``iso``
33#:    ISO format ``YYYY-MM-DD HH:MM:SS``
34#: ``le``
35#:    little endian with slashes: ``DD/MM/YYYY HH:MM:SS``
36#: ``de``
37#:    german date format: ``DD.MM.YYYY HH:MM:SS``
38#: ``us``
39#:    middle endian format common in the U.S.: ``MM/DD/YYYY HH:MM:SS``
40#:
41DATETIME_FORMATS = {
42    'iso': ('datetimepicker', '%Y-%m-%d %H:%M:%S'),
43    'le':  ('datetimepicker-le', '%d/%m/%Y %H:%M:%S'),
44    'de':  ('datetimepicker-de', '%d.%m.%Y %H:%M:%S'),
45    'us':  ('datetimepicker-us', '%m/%d/%Y %H:%M:%S'),
46    }
47
48#: a dict containing <FORMAT> as key and suitable CSS tags as values.
49FORMATS_BY_VALUE = dict(
50    [(val[1], val[0]) for key, val in DATETIME_FORMATS.items()])
51
52class FormattedDatetimeWidget(DatetimeWidget):
53    """A datetime widget that supports different (and _explicit_) date formats.
54
55    If the widget is bound to a schema field with respective
56    attributes, it reads its `date_format` attribute (see
57    waeup.kofa.schema.FormattedDatetime for an example) and sets a CSS
58    tag according to the values.
59
60    The widget also accepts ISO format as a fallback, even if a
61    different format was set. This should help with imports.
62
63    This is an input widget.
64    """
65    date_format = '%Y-%m-%d %H:%M:%S'
66    show_time = True
67
68    def __init__(self, context, request, *args, **kw):
69        # try to grab date_format and show_time from bound schema field.
70        date_format = getattr(context, 'date_format', self.date_format)
71        if date_format is not None:
72            self.date_format = date_format
73        self.show_time = getattr(context, 'show_time', self.show_time)
74        # add css class determined by date_format
75        css_cls = FORMATS_BY_VALUE.get(self.date_format, '')
76        self.cssClass = ' '.join([self.cssClass, css_cls]).strip()
77        return super(FormattedDatetimeWidget, self).__init__(
78            context, request, *args, **kw)
79
80    def _toFieldValue(self, input):
81        # In import files we can use the hash symbol at the end of a
82        # datetime string to avoid annoying automatic datetime transformation
83        # by Excel or Calc
84        input = input.strip('#')
85        if input == self._missing:
86            return self.context.missing_value
87        else:
88            try:
89                value = datetime.strptime(input, self.date_format)
90            except (ValueError, IndexError), v:
91                try:
92                    # Try ISO format as fallback.
93                    # This is needed for instance during imports.
94                    value = datetime.strptime(
95                        input, FormattedDatetimeWidget.date_format)
96                except (ValueError, IndexError), v:
97                    raise ConversionError("Invalid datetime data", v)
98        return value
99
100    def _toFormValue(self, value):
101        if value:
102            value = value.strftime(self.date_format)
103        return value
104
105
106class FormattedDatetimeDisplayWidget(DatetimeDisplayWidget):
107    """A datetime widget that supports different (and _explicit_) date formats.
108
109    This is a display widget.
110    """
111    date_format = '%Y-%m-%d %H:%M:%S'
112    show_time = False
113
114    implements(IDisplayWidget)
115
116    def __init__(self, context, request, *args, **kw):
117        # try to grab date_format and show_time from bound schema field.
118        date_format = getattr(context, 'date_format', self.date_format)
119        if date_format is not None:
120            self.date_format = date_format
121        self.show_time = getattr(context, 'show_time', self.show_time)
122        return super(FormattedDatetimeDisplayWidget, self).__init__(
123            context, request, *args, **kw)
124
125    def __call__(self):
126        if self._renderedValueSet():
127            content = self._data
128        else:
129            content = self.context.default
130        if content == self.context.missing_value:
131            return ""
132        content = content.strftime(self.date_format)
133        return renderElement("span", contents=escape(content),
134                             cssClass=self.cssClass)
135
136class DatetimeLEWidget(FormattedDatetimeWidget):
137    date_format = '%d/%m/%Y %H:%M:%S'
138
139class DatetimeDEWidget(FormattedDatetimeWidget):
140    date_format = '%d.%m.%Y %H:%M:%S'
141
142class DatetimeUSWidget(FormattedDatetimeWidget):
143    date_format = '%m/%d/%Y %H:%M:%S'
144
145class DatetimeLEDisplayWidget(FormattedDatetimeDisplayWidget):
146    date_format = '%d/%m/%Y %H:%M:%S'
147
148class DatetimeDEDisplayWidget(FormattedDatetimeDisplayWidget):
149    date_format = '%d.%m.%Y %H:%M:%S'
150
151class DatetimeUSDisplayWidget(FormattedDatetimeDisplayWidget):
152    date_format = '%m/%d/%Y %H:%M:%S'
153
154def FriendlyDatetimeDisplayWidget(format):
155    """Get a friendly datetime display widget for `format`.
156
157    This widget is suitable for display forms.
158
159    Valid `format` values are the keys of `DATE_FORMATS`
160    dict. Default is ``le`` (little endian; DD/MM/YYYY %H:%M:%S).
161
162    This widget is not rendered with a specialized CSS tag for
163    enabling JavaScript datepickers. `css_class` is ignored which means
164    there is no difference between e.g. ``le`` and ``le-year``.`
165    """
166    css_class, date_format = DATE_FORMATS.get(format, DATE_FORMATS['le'])
167    datetime_format = date_format + ' %H:%M:%S'
168    return CustomWidgetFactory(
169        FormattedDateDisplayWidget,
170        date_format=datetime_format)
Note: See TracBrowser for help on using the repository browser.