# -*- coding: iso-8859-1 -*- """ This is improved the old Calendar processor. @copyright: 2005 by Karel Zak @license: GNU GPL, see COPYING for details. @version: 20060216 """ import calendar import time import locale Dependencies = [] EnglishDayText = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] class CalendarOptions: def __init__(self, items): self.options = {} self.defaults = {} # name of first week day is independent on locales self.defaults['firstWeekDay'] = { 'VALUE': 'Sunday' } self.defaults['headerMonth'] = { 'VALUE': 'enable', 'STYLE': 'text-align: center; font-weight: bold; background-color: #fcfdc1; font-size: 150%' } self.defaults['headerDayName'] = { 'VALUE': 'enable', 'STYLE': 'text-align: center; font-weight: bold; background-color: #fff0ac; width: 10em' } self.defaults['headerWeekendName'] = { 'VALUE': 'enable', 'STYLE': 'text-align: center; font-weight: bold; background-color: #d6e0b7; width: 10em' } self.defaults['headerDay'] = { 'STYLE': 'text-align: center; font-weight: bold; background-color: #fff7d2; border-bottom: white 0px none' } self.defaults['eventDay'] = { 'STYLE': 'border-top: white 0px none;' } self.defaults['headerWeekend'] = { 'VALUE': 'enable', 'STYLE': 'text-align: center; font-weight: bold; background-color: #e5ead6; border-bottom: white 0px none' } self.defaults['headerToday'] = { 'VALUE': 'enable', 'STYLE': 'border: #a6a49a 1px solid; background-color: #d3f6d1' } self.defaults['calendarsOrder'] = { 'VALUE': 'normal' } self.defaults['calendarCollapse'] = { 'VALUE': 'disable' } self.mergeOptionsAndDefaults(items) def mergeOptionsAndDefaults(self, items): if len(items) <= 0: self.options = self.defaults return for k, defaults in self.defaults.iteritems(): if not items.has_key(k): self.options[k] = defaults else: options = items[k] for key, val in defaults.iteritems(): if not options.has_key(key): options[key] = val self.options[k] = options def get(self, name): if len(self.options) > 0: if self.options.has_key(name): return self.options[name] return None def getBool(self, name): val = self.getValue(name) if val and len(val): if val.lower() == 'true' or val.lower() == 'enable': return 1 return 0 def getItem(self, name, key): items = self.get(name) if items and items.has_key(key): return items[key] return None def getValue(self, name): return self.getItem(name, 'VALUE') def getStyle(self, name): return self.getItem(name, 'STYLE') class EventCalendar: def __init__(self, y, m, options, y_today, m_today, d_today): self.y = y self.m = m self.days = {} self.options = options self.debug = [] self.y_today = y_today self.m_today = m_today self.d_today = d_today self.footnotes = [] val = self.getValue('firstWeekDay') start = self.dayToNumber(val) if start <= 5: self.weekend = [5-start, 6-start] else: self.weekend = [0,6] calendar.setfirstweekday(start) lastDay = calendar.monthrange(y, m)[1] for i in xrange(1,lastDay+1): self.days[i] = [] def isToday(self, d): if self.y == self.y_today and self.m == self.m_today and d == self.d_today: return 1 return 0 def getValue(self, name): return self.options.getValue(name) def getStyle(self, name): return self.options.getStyle(name) def addEvent(self,d,event): self.days[d].append(event) def dayToNumber(self, day): for i in xrange(0, 7): if EnglishDayText[i].lower()==day.lower(): return i return None def getDayName(self, idx): lc = [locale.DAY_2, locale.DAY_3, locale.DAY_4, locale.DAY_5, locale.DAY_6, locale.DAY_7, locale.DAY_1] return locale.nl_langinfo(lc[idx]) def getMonthName(self, idx): lc = [locale.MON_1, locale.MON_2, locale.MON_3, locale.MON_4, locale.MON_5, locale.MON_6, locale.MON_7, locale.MON_8, locale.MON_9, locale.MON_10,locale.MON_11,locale.MON_12] return locale.nl_langinfo(lc[idx]) def format(self, req, fmt): id = '%s_%s' % (self.y, self.m) if self.y==self.y_today and self.m==self.m_today: display = 'block' else: display = 'none' if self.options.getBool('calendarCollapse'): req.write('''

''' % id) req.write(fmt.text("%d / %s" % (self.y, self.getMonthName(self.m-1)))) req.write('

\n') req.write('
\n' % (id, display)) req.write('\n') # Year / Month if self.options.getBool('headerMonth')==1: req.write(fmt.table_row(1)) req.write(fmt.table_cell(1, {'colspan': '7', 'style': self.getStyle('headerMonth') })) req.write(fmt.text("%d / %s" % (self.y, self.getMonthName(self.m-1)))) req.write(fmt.table_cell(0)) req.write(fmt.table_row(0)) # Names of Days if self.options.getBool('headerDayName')==1: req.write(fmt.table_row(1)) for i in range(calendar.firstweekday(), calendar.firstweekday()+7): d = i%7 if self.options.getBool('headerWeekendName') and d in [5,6]: req.write(fmt.table_cell(1, {'style': self.getStyle('headerWeekendName') })) else: req.write(fmt.table_cell(1, {'style': self.getStyle('headerDayName') })) req.write(fmt.text(self.getDayName(d))) req.write(fmt.table_cell(0)) req.write(fmt.table_row(0)) calList = calendar.monthcalendar(self.y, self.m) weekRows = len(calList) for week in calList: # date req.write(fmt.table_row(1)) xd = 0 for day in week: if self.options.getBool('headerWeekend') and xd in self.weekend: req.write(fmt.table_cell(1, {'style': self.getStyle('headerWeekend') })) else: req.write(fmt.table_cell(1, {'style': self.getStyle('headerDay') })) if day > 0: req.write('
' % (self.y,self.m,day)) req.write(fmt.text("-%d-" % day)) req.write('
') req.write(fmt.table_cell(0)) xd += 1 req.write(fmt.table_row(0)) # event req.write(fmt.table_row(1)) for day in week: req.write(fmt.table_cell(1, {'style': self.getStyle('eventDay'), 'valign': 'top' })) if day > 0: for event in self.days[day]: if event.has_key('TEXT'): if event.has_key('STYLE'): req.write('
' % event['STYLE']) else: req.write('
') req.write(fmt.text(event['TEXT'])) if event.has_key('FOOTNOTE'): dt = '%d-%d-%d' % (self.y,self.m,day) self.footnotes.append((dt, event['FOOTNOTE'])) req.write(fmt.anchorlink(1, name=dt)) req.write(fmt.text(' (%d)' % len(self.footnotes))) req.write(fmt.anchorlink(0)) req.write('
') req.write(fmt.table_cell(0)) req.write(fmt.table_row(0)) req.write('
\n'); if len(self.footnotes): req.write(fmt.strong(1)) req.write(fmt.text('Footnotes:')) req.write(fmt.strong(0)) req.write(fmt.number_list(1)) for d,f in self.footnotes: req.write(fmt.listitem(1)) req.write(fmt.anchordef(d)) req.write(fmt.strong(1)) req.write(fmt.text(d+': ')) req.write(fmt.strong(0)) req.write(fmt.text(f)) req.write(fmt.listitem(0)) req.write(fmt.number_list(0)) if len(self.debug) > 0: req.write('DEBUG: %s' % str(self.debug)) if self.options.getBool('calendarCollapse'): req.write('
\n'); class Parser: """ Forma calendar as a table """ caching = 0 Dependencies = [] def __init__(self, raw, request, **kw): """ Store the source text. """ self.raw = raw self.request = request self.form = request.form self._ = request.getText self.events = {} self.optionsItems = {} self.options = None self.calendars = [] self.debug = [] def stringNormalization(self, text): text = text.strip() data = '' blnk = 0 for p in text: if p==' ' or p=='\t': if blnk==1: continue blnk=1 blnk = 0 data += p text = data.replace(' = "', '="').replace('=" ', '="').replace(' ="', '="') #self.debug.append('TEXT: %s
' % text) return text def stringToItems(self, text): items = {} type = None text = self.stringNormalization(text) if len(text)==0: return None, None chunks = text.split('" ') for chunk in chunks: chunk = chunk.strip() x = chunk.split('=') if len(x)!=2: continue name, value = x value = value.strip() name = name.strip() if value and len(value)>0: if value[0] == '"': value = value[1:] if value[-1] == '"': value = value[:-1] items[name] = value if type==None: type = name return type, items def parseDate(self, text): if text==None or len(text) < 3: return None, None, None x = text.strip().split('-') if len(x) < 3: return None, None, None return int(x[0]), int(x[1]), int(x[2]) def appendEvent(self, y, m, d, items): if items and len(items) > 0: if not self.events.has_key(y): self.events[y] = { } if not self.events[y].has_key(m): self.events[y][m] = { } if not self.events[y][m].has_key(d): self.events[y][m][d] = [ ] self.events[y][m][d].append(items) def parseEvent(self, linetype, items): if linetype==None or len(linetype) == 0: return from_y, from_m, from_d = self.parseDate(linetype) if from_y==None: return # store the fisrt variable as two separate variables items['TEXT'] = items[linetype] items['FROM'] = linetype del items[linetype] if items.has_key('TO'): # range to_y, to_m, to_d = self.parseDate(items['TO']) if to_y==None: return for y in xrange(from_y, to_y+1): max_m = to_m min_m = from_m if y < to_y: max_m = 12 if y > from_y: min_m = 1 for m in xrange(min_m, max_m+1): max_d = to_d min_d = from_d if y < to_y or m < max_m: max_d = calendar.monthrange(y, m)[1] if y > from_y or m > from_m: min_d = 1 for d in xrange(min_d, max_d+1): self.appendEvent(y, m, d, items) else: # simple event self.appendEvent(from_y, from_m, from_d, items) def parse(self, raw): """ Parse to events or options """ if raw==None or len(raw)==0: return lines = raw.split('\n') for line in lines: text = line.strip() if len(text) == 0: continue linetype, items = self.stringToItems(text) if items==None: continue if linetype == 'OPTION': name = items['OPTION'] self.optionsItems[name] = items else: self.parseEvent(linetype, items) def calendarCreate(self): y_today = int( time.strftime("%Y")) m_today = int( time.strftime("%m")) d_today = int( time.strftime("%d")) self.options = CalendarOptions(self.optionsItems); for y in self.events.keys(): for m in self.events[y].keys(): cal = EventCalendar(y, m, self.options, y_today, m_today, d_today) for d in self.events[y][m].keys( ): for event in self.events[y][m][d]: cal.addEvent(d,event) self.calendars.append((y,m,cal)) self.calendars.sort() if self.options.getValue('calendarsOrder')=='reverse': self.calendars.reverse() def format(self, formatter): self.parse(self.raw) self.calendarCreate() if len(self.calendars)==0: return self.request.write(''' \n''') for y,m,cal in self.calendars: cal.format(self.request, formatter) if len(self.debug) > 0: self.request.write('DEBUG: %s' % self.debug) # vim: set tabstop=4: # vim: set shiftwidth=4: # vim: set expandtab: