# Calendaring is a simple CMF/Plone calendaring implementation. # Copyright (C) 2004 Enfold Systems # # This program 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 2 of the License, or # (at your option) any later version. # # This program 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 this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # """ $Id: _base.py,v 1.5 2005/01/11 00:26:34 dreamcatcher Exp $ """ import urllib from datetime import datetime from Acquisition import Implicit, aq_inner, aq_parent from ComputedAttribute import ComputedAttribute from Products.CMFCore.utils import getToolByName from Products.Calendaring.model import makeRange, DAY, getView, SECOND from Products.Calendaring.common import dt2DT, DT2dt, toSeconds ARG_NAMES = ['cyear', 'cmonth', 'cday', 'hour', 'minute', 'second'] class ModelView(Implicit): """ Base ModelView class for support of calendar rendering """ __allow_access_to_unprotected_subobjects__ = 1 unit = 'day' _sub = 'day_view' name = 'day_view' _args = 2 _leap = DAY _skip = True # DWM: Added line to init to check the portal calendar's calendar # types. Would be preferable to check the calendar container for # registered event types #calendar_types = ['Event'] def __init__(self, dt=None, start=None, REQUEST=None): if dt is None: dt = datetime.today() if start is None: start = dt.replace(hour=0, minute=0, second=0, microsecond=0) if REQUEST is not None: start = dt.replace(hour=0, minute=0, second=0, microsecond=0) d = {} for k in ('cyear', 'cmonth', 'cday'): if REQUEST.has_key(k): d[k[1:]] = int(REQUEST.get(k)) if d: start = start.replace(**d) self.today = dt # So we always have a datetime inside # the period that we are looking at. # XXX DC: This is not guaranteed! self.cur = start self.start, self.end, self.resolution = makeRange(start, self.unit) # set calendar_types to display from portal_calendar def _context(self): return aq_parent(self) context = ComputedAttribute(_context, 1) def _factory_hook(self): return getView(self._sub) def _sub_factory(self): return self._factory_hook() sub_factory = ComputedAttribute(_sub_factory) def _parts(self): factory = self.sub_factory one = factory(self.today, self.start) end = one.end yield one.__of__(self.context) while end < self.end: sub = factory(self.today, end) end = sub.end yield sub.__of__(self.context) parts = ComputedAttribute(_parts, 1) def next(self): factory = self.__class__ view = factory(self.today, self.end + self._leap) return view.__of__(self.context) def previous(self): factory = self.__class__ leap = self._leap if self._skip: leap += DAY view = factory(self.today, self.start - leap) return view.__of__(self.context) def _make_url(self, date): request = self.REQUEST prefix = '' if hasattr(self, 'aq_parent'): prefix = self.context.absolute_url() args = dict(zip(ARG_NAMES[:self._args], date.timetuple()[:self._args])) parts = filter(None, [prefix, self.name]) return '%s?%s' % ('/'.join(parts), urllib.urlencode(args)) def next_url(self): return self._make_url(self.next().start) def previous_url(self): return self._make_url(self.previous().start) def _day(self): return self.today.day day = ComputedAttribute(_day) def _month(self): return self.today.month month = ComputedAttribute(_month) def _year(self): return self.today.year year = ComputedAttribute(_year) def _current(self): return self.start <= self.today <= self.end current = ComputedAttribute(_current) def __str__(self): name = self.__class__.__name__ args = ('name', self.name, 'unit', self.unit, 'sub', self._sub, 'today', self.today, 'start', self.start, 'end', self.end, 'resolution', self.resolution) return '%s%r' % (name, args) __repr__ = __str__ def index_html(self): """ Get template from skins tool """ st = getToolByName(self, 'portal_skins') template = st.restrictedTraverse(self.name) template = template.aq_base.__of__(self.context) return template(view=self) def getDateTimes(self): """ Return the zope DateTime objects for self.today self.start and self.end """ return {'today': dt2DT(self.today), 'current': dt2DT(self.cur), 'start': dt2DT(self.start), 'end': dt2DT(self.end - SECOND), } def _ongoingEvents(self): pc_tool = getToolByName(self, 'portal_calendar') calendar_types = pc_tool.calendar_types ct = getToolByName(self, 'portal_catalog') start = dt2DT(self.start) end = dt2DT(self.start + SECOND) res = ct(portal_type=calendar_types, start={'query': start, 'range': 'max'}, end={'query': end, 'range': 'min'}, sort_on='start') return tuple(res) ongoing_events = ComputedAttribute(_ongoingEvents, 1) def _events(self): ct = getToolByName(self, 'portal_catalog') pc_tool = getToolByName(self, 'portal_calendar') calendar_types = pc_tool.calendar_types res = ct(portal_type=calendar_types, start={'query': [dt2DT(self.start),dt2DT(self.end - SECOND)], 'range': 'min:max'}, sort_on='start') return tuple(res) events = ComputedAttribute(_events, 1) def computeDuration(self, event): """ Given an event computes the duration as an integer multiple of our sub_view ie if we're on the day vew returns the number of hours the event will last """ start = DT2dt(event.start) end = DT2dt(event.end) delta = end - start # print '----------->', toSeconds(self.resolution), self.resolution # _robert_ prevent division by 0 return round(toSeconds(delta) / (toSeconds(self.resolution) or 1))