Attachment 'Calendar-20060216.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 """
   3     This is improved the old Calendar processor.
   4 
   5     @copyright: 2005 by Karel Zak <kzak@redhat.com> 
   6     @license: GNU GPL, see COPYING for details.
   7 
   8     @version: 20060216
   9 """
  10 
  11 import calendar
  12 import time
  13 import locale
  14 
  15 Dependencies = []
  16 EnglishDayText = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
  17 
  18 class CalendarOptions:
  19     def __init__(self, items):
  20         self.options = {}
  21         self.defaults = {}
  22 
  23         # name of first week day is independent on locales
  24         self.defaults['firstWeekDay'] = {
  25                 'VALUE': 'Sunday'
  26         }
  27         self.defaults['headerMonth'] = {
  28                 'VALUE': 'enable', 
  29                 'STYLE': 'text-align: center; font-weight: bold; background-color: #fcfdc1; font-size: 150%'
  30         } 
  31         self.defaults['headerDayName'] = {
  32                 'VALUE': 'enable', 
  33                 'STYLE': 'text-align: center; font-weight: bold; background-color: #fff0ac; width: 10em'
  34         } 
  35         self.defaults['headerWeekendName'] = {
  36                 'VALUE': 'enable', 
  37                 'STYLE': 'text-align: center; font-weight: bold; background-color: #d6e0b7; width: 10em'
  38         }
  39         self.defaults['headerDay'] = {
  40                 'STYLE': 'text-align: center; font-weight: bold; background-color: #fff7d2; border-bottom: white 0px none'
  41         } 
  42         self.defaults['eventDay'] = {
  43                 'STYLE': 'border-top: white 0px none;'
  44         }
  45         self.defaults['headerWeekend'] = {
  46                 'VALUE': 'enable',
  47                 'STYLE': 'text-align: center; font-weight: bold; background-color: #e5ead6; border-bottom: white 0px none'
  48         } 
  49         self.defaults['headerToday'] = {
  50                 'VALUE': 'enable',
  51                 'STYLE': 'border: #a6a49a 1px solid; background-color: #d3f6d1'
  52         } 
  53         self.defaults['calendarsOrder'] = {
  54                 'VALUE': 'normal'
  55         } 
  56         self.defaults['calendarCollapse'] = {
  57                 'VALUE': 'disable'
  58         } 
  59 
  60         self.mergeOptionsAndDefaults(items)
  61 
  62     def mergeOptionsAndDefaults(self, items):
  63         if len(items) <= 0:
  64             self.options = self.defaults
  65             return
  66         for k, defaults in self.defaults.iteritems():
  67             if not items.has_key(k):
  68                 self.options[k] = defaults
  69             else:
  70                 options = items[k]
  71                 for key, val in defaults.iteritems():
  72                     if not options.has_key(key):
  73                         options[key] = val
  74                 self.options[k] = options
  75 
  76     def get(self, name):
  77         if len(self.options) > 0:
  78             if self.options.has_key(name):
  79                 return self.options[name]
  80         return None
  81 
  82     def getBool(self, name):
  83         val = self.getValue(name)
  84         if val and len(val):
  85             if val.lower() == 'true' or val.lower() == 'enable':
  86                 return 1
  87         return 0
  88 
  89     def getItem(self, name, key):
  90         items = self.get(name)
  91         if items and items.has_key(key):
  92             return items[key]
  93         return None
  94 
  95     def getValue(self, name):
  96         return self.getItem(name, 'VALUE')
  97 
  98     def getStyle(self, name):
  99         return self.getItem(name, 'STYLE')
 100 
 101 class EventCalendar:
 102     def __init__(self, y, m, options, y_today, m_today, d_today):
 103         self.y = y
 104         self.m = m
 105         self.days = {}
 106         self.options = options
 107         self.debug = []
 108         self.y_today = y_today
 109         self.m_today = m_today
 110         self.d_today = d_today
 111         self.footnotes = []
 112 
 113         val = self.getValue('firstWeekDay')
 114         start = self.dayToNumber(val)
 115         if start <= 5:
 116             self.weekend = [5-start, 6-start]
 117         else:
 118             self.weekend = [0,6]
 119 
 120         calendar.setfirstweekday(start)
 121         lastDay = calendar.monthrange(y, m)[1]
 122         for i in xrange(1,lastDay+1):
 123             self.days[i] = []
 124 
 125     def isToday(self, d):
 126         if self.y == self.y_today and self.m == self.m_today and d == self.d_today:
 127             return 1
 128         return 0
 129 
 130     def getValue(self, name):
 131         return self.options.getValue(name)
 132 
 133     def getStyle(self, name):
 134         return self.options.getStyle(name)
 135 
 136     def addEvent(self,d,event):
 137         self.days[d].append(event)
 138 
 139     def dayToNumber(self, day):
 140         for i in xrange(0, 7):
 141             if EnglishDayText[i].lower()==day.lower():
 142                 return i
 143         return None
 144 
 145     def getDayName(self, idx):
 146         lc = [locale.DAY_2, locale.DAY_3, locale.DAY_4, locale.DAY_5, locale.DAY_6, locale.DAY_7, locale.DAY_1]
 147         return locale.nl_langinfo(lc[idx])
 148 
 149     def getMonthName(self, idx):
 150         lc = [locale.MON_1, locale.MON_2, locale.MON_3, locale.MON_4, locale.MON_5, locale.MON_6, 
 151               locale.MON_7, locale.MON_8, locale.MON_9, locale.MON_10,locale.MON_11,locale.MON_12]
 152         return locale.nl_langinfo(lc[idx])
 153 
 154     def format(self, req, fmt):
 155 
 156         id = '%s_%s' % (self.y, self.m)
 157         if self.y==self.y_today and self.m==self.m_today:
 158             display = 'block'
 159         else:
 160             display = 'none'
 161        
 162         if self.options.getBool('calendarCollapse'):
 163             req.write('''<p onclick="showCalendar('%s')" style="color: blue; cursor: pointer; cursor: hand; margin-bottom: 0px">''' % id)
 164             req.write(fmt.text("%d / %s" % (self.y, self.getMonthName(self.m-1))))
 165             req.write('</p>\n')
 166             req.write('<div id="%s" style="display: %s">\n' % (id, display))
 167         
 168         req.write('<table style="background-color: transparent">\n')
 169 
 170         # Year / Month
 171         if self.options.getBool('headerMonth')==1:
 172             req.write(fmt.table_row(1))
 173             req.write(fmt.table_cell(1, {'colspan': '7', 'style': self.getStyle('headerMonth') }))
 174             req.write(fmt.text("%d / %s" % (self.y, self.getMonthName(self.m-1))))
 175             req.write(fmt.table_cell(0))
 176             req.write(fmt.table_row(0))
 177 
 178         # Names of Days
 179         if self.options.getBool('headerDayName')==1:
 180             req.write(fmt.table_row(1))
 181             for i in range(calendar.firstweekday(), calendar.firstweekday()+7):
 182                 d = i%7
 183                 if self.options.getBool('headerWeekendName') and d in [5,6]:
 184                     req.write(fmt.table_cell(1, {'style': self.getStyle('headerWeekendName') }))
 185                 else:
 186                     req.write(fmt.table_cell(1, {'style': self.getStyle('headerDayName') }))
 187                 req.write(fmt.text(self.getDayName(d)))
 188                 req.write(fmt.table_cell(0))
 189             req.write(fmt.table_row(0))
 190 
 191         calList = calendar.monthcalendar(self.y, self.m)
 192         weekRows = len(calList)
 193 
 194         for week in calList:
 195             # date
 196             req.write(fmt.table_row(1))
 197             xd = 0
 198             for day in week:
 199                 if self.options.getBool('headerWeekend') and xd in self.weekend:
 200                     req.write(fmt.table_cell(1, {'style': self.getStyle('headerWeekend') }))
 201                 else:
 202                     req.write(fmt.table_cell(1, {'style': self.getStyle('headerDay') }))
 203                 if day > 0:
 204                     req.write('<div id="%d_%d_%d">' % (self.y,self.m,day))
 205                     req.write(fmt.text("-%d-" % day))
 206                     req.write('</div>')
 207                 req.write(fmt.table_cell(0))
 208                 xd += 1
 209             req.write(fmt.table_row(0))
 210             # event
 211             req.write(fmt.table_row(1))
 212             for day in week:
 213                 req.write(fmt.table_cell(1, {'style': self.getStyle('eventDay'), 'valign': 'top' }))
 214                 if day > 0:
 215                     for event in self.days[day]:
 216                         if event.has_key('TEXT'):
 217                             if event.has_key('STYLE'):
 218                                 req.write('<div style="%s">' % event['STYLE'])
 219                             else:
 220                                 req.write('<div>')
 221                             req.write(fmt.text(event['TEXT']))
 222                             if event.has_key('FOOTNOTE'):
 223                                 dt = '%d-%d-%d' % (self.y,self.m,day)
 224                                 self.footnotes.append((dt, event['FOOTNOTE']))
 225                                 req.write(fmt.anchorlink(1, name=dt))
 226                                 req.write(fmt.text(' (%d)' % len(self.footnotes))) 
 227                                 req.write(fmt.anchorlink(0))
 228                             req.write('</div>')
 229                 req.write(fmt.table_cell(0))
 230             req.write(fmt.table_row(0))
 231 
 232         req.write('</table>\n');
 233 
 234         if len(self.footnotes):
 235             req.write(fmt.strong(1))
 236             req.write(fmt.text('Footnotes:'))
 237             req.write(fmt.strong(0))
 238             req.write(fmt.number_list(1))
 239             for d,f in self.footnotes:
 240                 req.write(fmt.listitem(1))
 241                 req.write(fmt.anchordef(d))
 242                 req.write(fmt.strong(1))
 243                 req.write(fmt.text(d+': '))
 244                 req.write(fmt.strong(0))
 245                 req.write(fmt.text(f))
 246                 req.write(fmt.listitem(0))
 247             req.write(fmt.number_list(0))
 248 
 249         if len(self.debug) > 0:
 250             req.write('DEBUG: %s' % str(self.debug))
 251 
 252         if self.options.getBool('calendarCollapse'):
 253             req.write('</div>\n');
 254 
 255 class Parser:
 256     """ Forma calendar as a table
 257     """
 258     caching = 0
 259     Dependencies = []
 260 
 261     def __init__(self, raw, request, **kw):
 262         """ Store the source text.
 263         """
 264         self.raw = raw
 265         self.request = request
 266         self.form = request.form
 267         self._ = request.getText
 268         self.events = {}
 269         self.optionsItems = {}
 270         self.options = None
 271         self.calendars = []
 272         self.debug = []
 273 
 274     def stringNormalization(self, text):
 275         text = text.strip()
 276         data = ''
 277         blnk = 0
 278         for p in text:
 279             if p==' ' or p=='\t':
 280                 if blnk==1:
 281                     continue
 282                 blnk=1
 283             blnk = 0
 284             data += p
 285         text = data.replace(' = "', '="').replace('=" ', '="').replace(' ="', '="')
 286         #self.debug.append('TEXT: %s<br>' % text)
 287         return text
 288 
 289     def stringToItems(self, text):
 290         items = {}
 291         type = None
 292         text = self.stringNormalization(text)
 293         if len(text)==0:
 294             return None, None
 295         chunks = text.split('" ')
 296         for chunk in chunks:
 297             chunk = chunk.strip()
 298             x = chunk.split('=')
 299             if len(x)!=2:
 300                 continue
 301             name, value = x
 302             value = value.strip()
 303             name = name.strip()
 304             if value and len(value)>0:
 305                 if value[0] == '"':
 306                     value = value[1:]
 307                 if value[-1] == '"':
 308                     value = value[:-1]
 309             items[name] = value
 310             if type==None:
 311                 type = name
 312         return type, items
 313         
 314     def parseDate(self, text):
 315         if text==None or len(text) < 3:
 316             return None, None, None
 317         x = text.strip().split('-')
 318         if len(x) < 3:
 319             return None, None, None
 320         return int(x[0]), int(x[1]), int(x[2])
 321 
 322     def appendEvent(self, y, m, d, items):
 323         if items and len(items) > 0:
 324             if not self.events.has_key(y):
 325                 self.events[y] = { }
 326             if not self.events[y].has_key(m):
 327                 self.events[y][m] = { }
 328             if not self.events[y][m].has_key(d):
 329                     self.events[y][m][d] = [ ]
 330             self.events[y][m][d].append(items)
 331 
 332     def parseEvent(self, linetype, items):
 333         if linetype==None or len(linetype) == 0:
 334             return
 335         from_y, from_m, from_d = self.parseDate(linetype)
 336         if from_y==None:
 337             return
 338 
 339         # store the fisrt variable as two separate variables
 340         items['TEXT'] = items[linetype]
 341         items['FROM'] = linetype
 342         del items[linetype]
 343 
 344         if items.has_key('TO'):
 345             # range
 346             to_y, to_m, to_d = self.parseDate(items['TO'])
 347             if to_y==None:
 348                 return
 349 
 350             for y in xrange(from_y, to_y+1):
 351                 max_m = to_m
 352                 min_m = from_m
 353                 if y < to_y:
 354                     max_m = 12
 355                 if y > from_y:
 356                     min_m = 1
 357                 for m in xrange(min_m, max_m+1):
 358                     max_d = to_d
 359                     min_d = from_d
 360                     if y < to_y or m < max_m:
 361                         max_d = calendar.monthrange(y, m)[1]
 362                     if y > from_y or m > from_m:
 363                         min_d = 1
 364                     for d in xrange(min_d, max_d+1):
 365                         self.appendEvent(y, m, d, items)
 366         else:
 367             # simple event
 368             self.appendEvent(from_y, from_m, from_d, items)
 369         
 370     def parse(self, raw):
 371         """ Parse to events or options
 372         """
 373         if raw==None or len(raw)==0:
 374             return
 375 
 376         lines = raw.split('\n')
 377 
 378         for line in lines:
 379             text = line.strip()
 380             if len(text) == 0:
 381                 continue
 382             linetype, items = self.stringToItems(text)
 383             if items==None:
 384                 continue
 385             if linetype == 'OPTION':
 386                 name = items['OPTION']
 387                 self.optionsItems[name] = items
 388             else:
 389                 self.parseEvent(linetype, items)
 390 
 391     def calendarCreate(self):
 392         y_today = int( time.strftime("%Y"))
 393         m_today = int( time.strftime("%m"))
 394         d_today = int( time.strftime("%d"))
 395 
 396         self.options = CalendarOptions(self.optionsItems);
 397 
 398         for y in self.events.keys():
 399             for m in self.events[y].keys():
 400                 cal = EventCalendar(y, m, self.options, y_today, m_today, d_today)
 401                 for d in self.events[y][m].keys( ):
 402                     for event in self.events[y][m][d]:
 403                         cal.addEvent(d,event)
 404                 self.calendars.append((y,m,cal))
 405 
 406         self.calendars.sort()
 407 
 408         if self.options.getValue('calendarsOrder')=='reverse':
 409             self.calendars.reverse()
 410 
 411     def format(self, formatter):
 412 
 413         self.parse(self.raw)
 414         self.calendarCreate()
 415 
 416         if len(self.calendars)==0:
 417             return
 418 
 419         self.request.write('''
 420             <script language="javascript" type="text/javascript">
 421               function showCalendar(id)
 422               {
 423                  el=document.getElementById(id).style;
 424                  el.display=(el.display == 'block')?'none':'block';
 425               }
 426             </script>\n''')
 427 
 428         for y,m,cal in self.calendars:
 429             cal.format(self.request, formatter)
 430 
 431         if len(self.debug) > 0:
 432             self.request.write('DEBUG: %s' % self.debug)
 433 
 434 # vim: set tabstop=4:
 435 # vim: set shiftwidth=4:
 436 # vim: set expandtab:

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2006-02-16 14:59:57, 14.6 KB) [[attachment:Calendar-20060216.py]]
  • [get | view] (2007-05-28 09:42:03, 2.7 KB) [[attachment:ExcelPastedTable.py]]
  • [get | view] (2005-04-12 19:22:18, 6.0 KB) [[attachment:Gantt-1.3.3-2.py]]
  • [get | view] (2007-03-24 02:05:26, 3.9 KB) [[attachment:Literate_parser-0.7_Moin-1.3.tgz]]
  • [get | view] (2007-03-24 02:08:08, 4.8 KB) [[attachment:Literate_parser-0.7_Moin-1.3.zip]]
  • [get | view] (2005-03-11 13:50:49, 12.3 KB) [[attachment:MySQL.py]]
  • [get | view] (2005-09-11 08:09:44, 1.6 KB) [[attachment:SortText-1.3.5-1.py]]
  • [get | view] (2005-11-21 08:40:10, 2.8 KB) [[attachment:Sorter-1.3.py]]
  • [get | view] (2005-06-02 13:02:06, 1.2 KB) [[attachment:colorer.py]]
  • [get | view] (2006-01-04 16:10:31, 0.6 KB) [[attachment:gettext.py]]
  • [get | view] (2004-10-19 13:05:05, 0.7 KB) [[attachment:html-parser-1.2.py]]
  • [get | view] (2005-02-17 10:46:56, 0.6 KB) [[attachment:html.py]]
  • [get | view] (2005-12-06 21:09:48, 1.3 KB) [[attachment:matlab.py]]
  • [get | view] (2005-01-20 07:42:34, 0.4 KB) [[attachment:nocamelcase.py]]
  • [get | view] (2005-11-28 16:55:23, 2.3 KB) [[attachment:php-1.3.4-1]]
  • [get | view] (2005-12-18 22:36:37, 15.0 KB) [[attachment:sctable-1.3.5-4.py]]
  • [get | view] (2004-12-31 04:41:23, 1.6 KB) [[attachment:textil.py]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.