# ------------------------------------------------------------------------------
# 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 .
# ------------------------------------------------------------------------------
import time
from appy.fields import Field
from appy.px import Px
# ------------------------------------------------------------------------------
def getDateFromIndexValue(indexValue):
'''p_indexValue is the internal representation of a date as stored in the
zope Date index (see "_convert" method in DateIndex.py in
Products.pluginIndexes/DateIndex). This function produces a DateTime
based on it.'''
# p_indexValue represents a number of minutes
minutes = indexValue % 60
indexValue = (indexValue-minutes) / 60 # The remaining part, in hours
# Get hours
hours = indexValue % 24
indexValue = (indexValue-hours) / 24 # The remaining part, in days
# Get days
day = indexValue % 31
indexValue = (indexValue-day) / 31 # The remaining part, in months
# Get months
month = indexValue % 12
year = (indexValue - month) / 12
from DateTime import DateTime
utcDate = DateTime('%d/%d/%d %d:%d UTC' % (year,month,day,hours,minutes))
return utcDate.toZone(utcDate.localZone())
# ------------------------------------------------------------------------------
class Date(Field):
pxView = pxCell = Px(''':value''')
pxEdit = Px('''
:
''')
pxSearch = Px('''
/
/
/
/
''')
# 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, mustIndex=True, 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, persist=True, view=None, xml=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, mustIndex, searchable,
specificReadPermission, specificWritePermission, width,
height, None, colspan, master, masterValue, focus,
historized, mapping, label, sdefault, scolspan, swidth,
sheight, persist, view, xml)
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, language=None):
if self.isEmptyValue(obj, 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, obj, requestName=None):
request = obj.REQUEST
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, obj, value):
if not self.isEmptyValue(obj, value):
import DateTime
return DateTime.DateTime(value)
def getIndexType(self): return 'DateIndex'
def isSelected(self, obj, fieldPart, dateValue, dbValue):
'''When displaying this field, must the particular p_dateValue be
selected in the sub-field p_fieldPart corresponding to the date
part?'''
# Get the value we must compare (from request or from database)
rq = obj.REQUEST
partName = '%s_%s' % (self.name, fieldPart)
if rq.has_key(partName):
compValue = rq.get(partName)
if compValue.isdigit():
compValue = int(compValue)
else:
compValue = dbValue
if compValue:
compValue = getattr(compValue, fieldPart)()
# Compare the value
return compValue == dateValue
def getJsInit(self, name, years):
'''Gets the Javascript init code for displaying a calendar popup for
this field, for an input named p_name (which can be different from
self.name if, ie, it is a search field).'''
# Always express the range of years in chronological order.
years = [years[0], years[-1]]
years.sort()
return 'Calendar.setup({inputField: "%s", button: "%s_img", ' \
'onSelect: onSelectDate, range:%s})' % (name, name, str(years))
# ------------------------------------------------------------------------------