252 lines
10 KiB
Python
252 lines
10 KiB
Python
|
# ------------------------------------------------------------------------------
|
||
|
# This file is part of Appy, a framework for building applications in the Python
|
||
|
# language. Copyright (C) 2007 Gaetan Delannay
|
||
|
|
||
|
# Appy 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 3 of the License, or (at your option) any later
|
||
|
# version.
|
||
|
|
||
|
# Appy 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
|
||
|
# Appy. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
import time
|
||
|
from appy.fields import Field
|
||
|
from appy.px import Px
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
class Date(Field):
|
||
|
|
||
|
pxView = pxCell = Px('''<x>:value</x>''')
|
||
|
pxEdit = Px('''
|
||
|
<x var="years=contextObj.getSelectableYears(widget['name'])">
|
||
|
<!-- Day -->
|
||
|
<select var="days=range(1,32)"
|
||
|
name=":'%s_day' % name" id=":'%s_day' % name">
|
||
|
<option value="">-</option>
|
||
|
<x for="day in days">
|
||
|
<option var="zDay=str(day).zfill(2)" value=":zDay"
|
||
|
selected="contextObj.dateValueSelected(name, 'day', day, \
|
||
|
rawValue)">:zDay></option></x>
|
||
|
</select>
|
||
|
|
||
|
<!-- Month -->
|
||
|
<select var="months=range(1,13)"
|
||
|
name=":'%s_month' % name" id=":'%s_month' % name">
|
||
|
<option value="">-</option>
|
||
|
<x for="month in months">
|
||
|
<option var="zMonth=str(month).zfill(2)" value=":zMonth"
|
||
|
selected="contextObj.dateValueSelected(name, 'month', month, \
|
||
|
rawValue)">:zMonth</option></x>
|
||
|
</select>
|
||
|
|
||
|
<!-- Year -->
|
||
|
<select name=":'%s_year' % name" id=":'%s_year' % name">
|
||
|
<option value="">-</option>
|
||
|
<option for="year in years" value=":year"
|
||
|
selected="contextObj.dateValueSelected(name, 'year', year, \
|
||
|
rawValue)">:year</option>
|
||
|
</select>
|
||
|
|
||
|
<!-- The icon for displaying the calendar popup -->
|
||
|
<x if="widget['calendar']">
|
||
|
<input type="hidden" id=":name" name=":name"/>
|
||
|
<img id=":'%s_img' % name" src=":'%s/ui/calendar.gif' % appUrl"/>
|
||
|
<script type="text/javascript">:contextObj.getCalendarInit(name, years)
|
||
|
</script>
|
||
|
</x>
|
||
|
|
||
|
<!-- Hour and minutes -->
|
||
|
<x if="widget['format'] == 0">
|
||
|
<select var="hours=range(0,24)"
|
||
|
name=":'%s_hour' % name" id=":'%s_hour' % name">
|
||
|
<option value="">-</option>
|
||
|
<x for="hour in hours">
|
||
|
<option var="zHour=str(hour).zfill(2)" value=":zHour"
|
||
|
selected=":contextObj.dateValueSelected(name, 'hour', hour, \
|
||
|
rawValue)">:zHour</option></x>
|
||
|
</select> :
|
||
|
<select var="minutes=range(0,60,5)"
|
||
|
name=":'%s_minute' % name" id=":'%s_minute' % name">
|
||
|
<option value="">-</option>
|
||
|
<x for="minute in minutes">
|
||
|
<option var="zMinute=str(minute).zfill(2)" value=":zMinute"
|
||
|
selected=":contextObj.dateValueSelected(name, 'minute', \
|
||
|
minute, rawValue)">:zMinute</option></x>
|
||
|
</select>
|
||
|
</x>
|
||
|
</x>''')
|
||
|
|
||
|
pxSearch = Px('''
|
||
|
<x var="years=range(widget['startYear'], widget['endYear']+1)">
|
||
|
<label>:_(widget['labelId'])</label>
|
||
|
<table>
|
||
|
<!-- From -->
|
||
|
<tr var="fromName='%s_from' % name;
|
||
|
dayFromName='%s_from_day' % name;
|
||
|
monthFromName='%s_from_month' % name;
|
||
|
yearFromName='%s*date' % widgetName">
|
||
|
<td width="10px"> </td>
|
||
|
<td><label>:_('search_from')"></label></td>
|
||
|
<td>
|
||
|
<select id=":dayFromName" name=":dayFromName">
|
||
|
<option value="">--</option>
|
||
|
<option for="value in [str(v).zfill(2) for v in range(1, 32)]"
|
||
|
value=":value">:value</option>
|
||
|
</select> /
|
||
|
<select id=":monthFromName" name=":monthFromName">
|
||
|
<option value="">--</option>
|
||
|
<option for="value in [str(v).zfill(2) for v in range(1, 13)]"
|
||
|
value=":value">:value</option>
|
||
|
</select> /
|
||
|
<select id=":yearFromName" name=":yearFromName">
|
||
|
<option value="">--</option>
|
||
|
<option for="value in range(widget['startYear'],widget['endYear']+1)"
|
||
|
value=":value">:value</option>
|
||
|
</select>
|
||
|
<!-- The icon for displaying the calendar popup -->
|
||
|
<x if="widget['calendar']">
|
||
|
<input type="hidden" id=":fromName" name=":fromName"/>
|
||
|
<img id=":'%s_img' % fromName" src=":'%s/ui/calendar.gif' % appUrl"/>
|
||
|
<script type="text/javascript">:tool.getCalendarInit(fromName, years)
|
||
|
</script>
|
||
|
</x>
|
||
|
</td>
|
||
|
</tr>
|
||
|
|
||
|
<!-- To -->
|
||
|
<tr var="toName='%s_to' % name;
|
||
|
dayToName='%s_to_day' % name;
|
||
|
monthToName='%s_to_month' % name;
|
||
|
yearToName='%s_to_year' % name">
|
||
|
<td></td>
|
||
|
<td><label>_('search_to')"></label> </td>
|
||
|
<td height="20px">
|
||
|
<select id=":dayToName" name=":dayToName">
|
||
|
<option value="">--</option>
|
||
|
<option for="value in [str(v).zfill(2) for v in range(1, 32)]"
|
||
|
value=":value">:value</option>
|
||
|
</select> /
|
||
|
<select id=":monthToName" name=":monthToName">
|
||
|
<option value="">--</option>
|
||
|
<option for="value in [str(v).zfill(2) for v in range(1, 13)]"
|
||
|
value=":value">:value</option>
|
||
|
</select> /
|
||
|
<select id=":yearToName" name=":yearToName">
|
||
|
<option value="">--</option>
|
||
|
<option for="value in range(widget['startYear'],widget['endYear']+1)"
|
||
|
value=":value">:value</option>
|
||
|
</select>
|
||
|
<!-- The icon for displaying the calendar popup -->
|
||
|
<x if="widget['calendar']">
|
||
|
<input type="hidden" id=":toName" name=":toName"/>
|
||
|
<img id=":'%s_img' % toName" src=":%s/ui/calendar.gif' % appUrl"/>
|
||
|
<script type="text/javascript">:tool.getCalendarInit(toName, years)">
|
||
|
</script>
|
||
|
</x>
|
||
|
</td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
</x>''')
|
||
|
|
||
|
# Required CSS and Javascript files for this type.
|
||
|
cssFiles = {'edit': ('jscalendar/calendar-blue.css',)}
|
||
|
jsFiles = {'edit': ('jscalendar/calendar.js',
|
||
|
'jscalendar/lang/calendar-en.js',
|
||
|
'jscalendar/calendar-setup.js')}
|
||
|
# Possible values for "format"
|
||
|
WITH_HOUR = 0
|
||
|
WITHOUT_HOUR = 1
|
||
|
dateParts = ('year', 'month', 'day')
|
||
|
hourParts = ('hour', 'minute')
|
||
|
|
||
|
def __init__(self, validator=None, multiplicity=(0,1), default=None,
|
||
|
format=WITH_HOUR, calendar=True,
|
||
|
startYear=time.localtime()[0]-10,
|
||
|
endYear=time.localtime()[0]+10, reverseYears=False,
|
||
|
show=True, page='main', group=None, layouts=None, move=0,
|
||
|
indexed=False, searchable=False, specificReadPermission=False,
|
||
|
specificWritePermission=False, width=None, height=None,
|
||
|
maxChars=None, colspan=1, master=None, masterValue=None,
|
||
|
focus=False, historized=False, mapping=None, label=None,
|
||
|
sdefault=None, scolspan=1, swidth=None, sheight=None):
|
||
|
self.format = format
|
||
|
self.calendar = calendar
|
||
|
self.startYear = startYear
|
||
|
self.endYear = endYear
|
||
|
# If reverseYears is True, in the selection box, available years, from
|
||
|
# self.startYear to self.endYear will be listed in reverse order.
|
||
|
self.reverseYears = reverseYears
|
||
|
Field.__init__(self, validator, multiplicity, default, show, page,
|
||
|
group, layouts, move, indexed, searchable,
|
||
|
specificReadPermission, specificWritePermission, width,
|
||
|
height, None, colspan, master, masterValue, focus,
|
||
|
historized, True, mapping, label, sdefault, scolspan,
|
||
|
swidth, sheight)
|
||
|
|
||
|
def getCss(self, layoutType, res):
|
||
|
# CSS files are only required if the calendar must be shown.
|
||
|
if self.calendar: Field.getCss(self, layoutType, res)
|
||
|
|
||
|
def getJs(self, layoutType, res):
|
||
|
# Javascript files are only required if the calendar must be shown.
|
||
|
if self.calendar: Field.getJs(self, layoutType, res)
|
||
|
|
||
|
def getSelectableYears(self):
|
||
|
'''Gets the list of years one may select for this field.'''
|
||
|
res = range(self.startYear, self.endYear + 1)
|
||
|
if self.reverseYears: res.reverse()
|
||
|
return res
|
||
|
|
||
|
def validateValue(self, obj, value):
|
||
|
DateTime = obj.getProductConfig().DateTime
|
||
|
try:
|
||
|
value = DateTime(value)
|
||
|
except DateTime.DateError, ValueError:
|
||
|
return obj.translate('bad_date')
|
||
|
|
||
|
def getFormattedValue(self, obj, value, showChanges=False):
|
||
|
if self.isEmptyValue(value): return ''
|
||
|
tool = obj.getTool().appy()
|
||
|
# A problem may occur with some extreme year values. Replace the "year"
|
||
|
# part "by hand".
|
||
|
dateFormat = tool.dateFormat
|
||
|
if '%Y' in dateFormat:
|
||
|
dateFormat = dateFormat.replace('%Y', str(value.year()))
|
||
|
res = value.strftime(dateFormat)
|
||
|
if self.format == Date.WITH_HOUR:
|
||
|
res += ' %s' % value.strftime(tool.hourFormat)
|
||
|
return res
|
||
|
|
||
|
def getRequestValue(self, request, requestName=None):
|
||
|
name = requestName or self.name
|
||
|
# Manage the "date" part
|
||
|
value = ''
|
||
|
for part in self.dateParts:
|
||
|
valuePart = request.get('%s_%s' % (name, part), None)
|
||
|
if not valuePart: return None
|
||
|
value += valuePart + '/'
|
||
|
value = value[:-1]
|
||
|
# Manage the "hour" part
|
||
|
if self.format == self.WITH_HOUR:
|
||
|
value += ' '
|
||
|
for part in self.hourParts:
|
||
|
valuePart = request.get('%s_%s' % (name, part), None)
|
||
|
if not valuePart: return None
|
||
|
value += valuePart + ':'
|
||
|
value = value[:-1]
|
||
|
return value
|
||
|
|
||
|
def getStorableValue(self, value):
|
||
|
if not self.isEmptyValue(value):
|
||
|
import DateTime
|
||
|
return DateTime.DateTime(value)
|
||
|
|
||
|
def getIndexType(self): return 'DateIndex'
|
||
|
# ------------------------------------------------------------------------------
|