Overview

Packages

  • Kronolith
  • None

Classes

  • Kronolith
  • Kronolith_Ajax_Application
  • Kronolith_Ajax_Imple_ContactAutoCompleter
  • Kronolith_Ajax_Imple_Embed
  • Kronolith_Ajax_Imple_TagActions
  • Kronolith_Ajax_Imple_TagAutoCompleter
  • Kronolith_Api
  • Kronolith_Calendar
  • Kronolith_Calendar_External
  • Kronolith_Calendar_External_Tasks
  • Kronolith_Calendar_Holiday
  • Kronolith_Calendar_Internal
  • Kronolith_Calendar_Remote
  • Kronolith_Calendar_Resource
  • Kronolith_Calendars_Base
  • Kronolith_Calendars_Default
  • Kronolith_Calendars_Kolab
  • Kronolith_Day
  • Kronolith_Driver
  • Kronolith_Driver_Holidays
  • Kronolith_Driver_Horde
  • Kronolith_Driver_Ical
  • Kronolith_Driver_Kolab
  • Kronolith_Driver_Mock
  • Kronolith_Driver_Resource
  • Kronolith_Driver_Sql
  • Kronolith_Event
  • Kronolith_Event_Holidays
  • Kronolith_Event_Horde
  • Kronolith_Event_Ical
  • Kronolith_Event_Kolab
  • Kronolith_Event_Resource
  • Kronolith_Event_Sql
  • Kronolith_Exception
  • Kronolith_Factory_Calendars
  • Kronolith_Factory_Geo
  • Kronolith_Form_CreateCalendar
  • Kronolith_Form_CreateResource
  • Kronolith_Form_CreateResourceGroup
  • Kronolith_Form_DeleteCalendar
  • Kronolith_Form_DeleteResource
  • Kronolith_Form_DeleteResourceGroup
  • Kronolith_Form_EditCalendar
  • Kronolith_Form_EditRemoteCalendar
  • Kronolith_Form_EditResource
  • Kronolith_Form_EditResourceGroup
  • Kronolith_Form_SubscribeRemoteCalendar
  • Kronolith_Form_UnsubscribeRemoteCalendar
  • Kronolith_FreeBusy
  • Kronolith_FreeBusy_View
  • Kronolith_FreeBusy_View_Day
  • Kronolith_FreeBusy_View_Month
  • Kronolith_FreeBusy_View_Week
  • Kronolith_FreeBusy_View_Workweek
  • Kronolith_Geo_Base
  • Kronolith_Geo_Mysql
  • Kronolith_Geo_Sql
  • Kronolith_LoginTasks_SystemTask_Upgrade
  • Kronolith_LoginTasks_Task_PurgeEvents
  • Kronolith_Notification_Listener_AjaxStatus
  • Kronolith_Resource
  • Kronolith_Resource_Base
  • Kronolith_Resource_Group
  • Kronolith_Resource_Single
  • Kronolith_Storage
  • Kronolith_Storage_Kolab
  • Kronolith_Storage_Sql
  • Kronolith_Tagger
  • Kronolith_Test
  • Kronolith_View_Day
  • Kronolith_View_DeleteEvent
  • Kronolith_View_EditEvent
  • Kronolith_View_Event
  • Kronolith_View_ExportEvent
  • Kronolith_View_Month
  • Kronolith_View_Week
  • Kronolith_View_WorkWeek
  • Kronolith_View_Year
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * This class represent a view of multiple free busy information sets.
  4:  *
  5:  * Copyright 2003-2012 Horde LLC (http://www.horde.org/)
  6:  *
  7:  * See the enclosed file COPYING for license information.
  8:  *
  9:  * @author  Mike Cochrane <mike@graftonhall.co.nz>
 10:  * @author  Jan Schneider <jan@horde.org>
 11:  * @package Kronolith
 12:  */
 13: abstract class Kronolith_FreeBusy_View
 14: {
 15:     protected $_requiredMembers = array();
 16:     protected $_optionalMembers = array();
 17:     protected $_requiredResourceMembers = array();
 18:     protected $_optionalResourceMembers = array();
 19:     protected $_timeBlocks = array();
 20: 
 21:     protected $_startHour;
 22:     protected $_endHour;
 23: 
 24:     protected $_start;
 25:     protected $_end;
 26: 
 27:     /**
 28:      * Adds a required attendee
 29:      *
 30:      * @param Kronolith_Freebusy $vFreebusy
 31:      */
 32:     public function addRequiredMember(Kronolith_Freebusy $vFreebusy)
 33:     {
 34:         $this->_requiredMembers[] = clone $vFreebusy;
 35:     }
 36: 
 37:     /**
 38:      * Adds an optional attendee
 39:      *
 40:      * @param Kronolith_Freebusy $vFreebusy
 41:      */
 42:     public function addOptionalMember(Kronoolith_Freebusy $vFreebusy)
 43:     {
 44:         $this->_optionalMembers[] = clone $vFreebusy;
 45:     }
 46: 
 47:     /**
 48:      * Adds an optional resource
 49:      *
 50:      * @param Kronolith_Freebusy $vFreebusy
 51:      */
 52:     public function addOptionalResourceMember(Kronolith_Freebusy $vFreebusy)
 53:     {
 54:         $this->_optionalResourceMembers[] = clone $vFreebusy;
 55:     }
 56: 
 57:     /**
 58:      * Adds a required resource
 59:      *
 60:      * @param Kronolith_Freebusy $vFreebusy
 61:      */
 62:     public function addRequiredResourceMember(Kronolith_Freebusy $vFreebusy)
 63:     {
 64:         $this->_requiredResourceMembers[] = clone $vFreebusy;
 65:     }
 66: 
 67:     /**
 68:      * Renders the fb view
 69:      *
 70:      * @global Horde_Prefs $prefs
 71:      * @param  Horde_Date $day  The day to render
 72:      *
 73:      * @return string  The html of the rendered fb view.
 74:      */
 75:     public function render(Horde_Date $day = null)
 76:     {
 77:         global $prefs;
 78: 
 79:         $this->_startHour = floor($prefs->getValue('day_hour_start') / 2);
 80:         $this->_endHour = floor(($prefs->getValue('day_hour_end') + 1) / 2);
 81: 
 82:         $this->_render($day);
 83: 
 84:         $vCal = new Horde_Icalendar();
 85: 
 86:         /* Required members */
 87:         $required = Horde_Icalendar::newComponent('vfreebusy', $vCal);
 88:         foreach ($this->_requiredMembers as $member) {
 89:             $required->merge($member, false);
 90:         }
 91:         foreach ($this->_requiredResourceMembers as $member) {
 92:             $required->merge($member, false);
 93:         }
 94:         $required->simplify();
 95: 
 96:         /* Optional members */
 97:         $optional = Horde_Icalendar::newComponent('vfreebusy', $vCal);
 98:         foreach ($this->_optionalMembers as $member) {
 99:             $optional->merge($member, false);
100:         }
101:         foreach ($this->_optionalResourceMembers as $member) {
102:             $optional->merge($member, false);
103:         }
104:         $optional->simplify();
105: 
106:         /* Optimal time calculation */
107:         $optimal = Horde_Icalendar::newComponent('vfreebusy', $vCal);
108:         $optimal->merge($required, false);
109:         $optimal->merge($optional);
110: 
111:         $base_url = Horde::selfUrl()
112:             ->remove('date')
113:             ->remove('fbview')
114:             ->add('fbview', $this->view);
115: 
116:         $template = $GLOBALS['injector']->createInstance('Horde_Template');
117:         $template->set('title', $this->_title());
118: 
119:         $html = $template->fetch(KRONOLITH_TEMPLATES . '/fbview/header.html') .
120:             '<div class="fbgrid">';
121: 
122:         $hours_html = $this->_hours();
123: 
124:         // Set C locale to avoid localized decimal separators during CSS width
125:         // calculation.
126:         $lc = setlocale(LC_NUMERIC, 0);
127:         setlocale(LC_NUMERIC, 'C');
128: 
129:         // Required to attend.
130:         if (count($this->_requiredMembers) > 0) {
131:             $rows = '';
132:             foreach ($this->_requiredMembers as $member) {
133:                 $member->simplify();
134:                 $blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.html', _("Busy"));
135:                 $template = $GLOBALS['injector']->createInstance('Horde_Template');
136:                 $template->set('blocks', $blocks);
137:                 $template->set('name', $member->getName());
138:                 $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
139:             }
140: 
141:             $template = $GLOBALS['injector']->createInstance('Horde_Template');
142:             $template->set('title', _("Required Attendees"));
143:             $template->set('rows', $rows);
144:             $template->set('span', count($this->_timeBlocks));
145:             $template->set('hours', $hours_html);
146:             $template->set('legend', '');
147:             $html .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.html');
148:         }
149: 
150:         // Optional to attend.
151:         if (count($this->_optionalMembers) > 0) {
152:             $rows = '';
153:             foreach ($this->_optionalMembers as $member) {
154:                 $member->simplify();
155:                 $blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.html', _("Busy"));
156:                 $template = $GLOBALS['injector']->createInstance('Horde_Template');
157:                 $template->set('blocks', $blocks);
158:                 $template->set('name', $member->getName());
159:                 $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
160:             }
161: 
162:             $template = $GLOBALS['injector']->createInstance('Horde_Template');
163:             $template->set('title', _("Optional Attendees"));
164:             $template->set('rows', $rows);
165:             $template->set('span', count($this->_timeBlocks));
166:             $template->set('hours', $hours_html);
167:             $template->set('legend', '');
168:             $html .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.html');
169:         }
170: 
171:         // Resources
172:         if (count($this->_requiredResourceMembers) > 0 || count($this->_optionalResourceMembers) > 0) {
173:             $template = $GLOBALS['injector']->createInstance('Horde_Template');
174:             $rows = '';
175:             foreach ($this->_requiredResourceMembers as $member) {
176:                 $member->simplify();
177:                 $blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.html', _("Busy"));
178:                 $template = $GLOBALS['injector']->createInstance('Horde_Template');
179:                 $template->set('blocks', $blocks);
180:                 $template->set('name', $member->getName());
181:                 $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
182:             }
183:             foreach ($this->_optionalResourceMembers as $member) {
184:                 $member->simplify();
185:                 $blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.html', _("Busy"));
186:                 $template = $GLOBALS['injector']->createInstance('Horde_Template');
187:                 $template->set('blocks', $blocks);
188:                 $template->set('name', $member->getName());
189:                 $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
190:             }
191:             $template = $GLOBALS['injector']->createInstance('Horde_Template');
192:             $template->set('title', _("Required Resources"));
193:             $template->set('rows', $rows);
194:             $template->set('span', count($this->_timeBlocks));
195:             $template->set('hours', $hours_html);
196:             $template->set('legend', '');
197:             $html .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.html');
198:         }
199: 
200:         // Possible meeting times.
201:         $optimal->setAttribute('ORGANIZER', _("All Attendees"));
202:         $blocks = $this->_getBlocks($optimal,
203:                                     $optimal->getFreePeriods($this->_start->timestamp(), $this->_end->timestamp()),
204:                                     'meetingblock.html', _("All Attendees"));
205: 
206:         $template = $GLOBALS['injector']->createInstance('Horde_Template');
207:         $template->set('name', _("All Attendees"));
208:         $template->set('blocks', $blocks);
209:         $rows = $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
210: 
211:         // Possible meeting times.
212:         $required->setAttribute('ORGANIZER', _("Required Attendees"));
213:         $blocks = $this->_getBlocks($required,
214:                                     $required->getFreePeriods($this->_start->timestamp(), $this->_end->timestamp()),
215:                                     'meetingblock.html', _("Required Attendees"));
216: 
217:         $template = $GLOBALS['injector']->createInstance('Horde_Template');
218:         $template->set('name', _("Required Attendees"));
219:         $template->set('blocks', $blocks);
220:         $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
221: 
222:         // Possible meeting times.
223: //        $resource->setAttribute('ORGANIZER', _("Required Attendees"));
224: //        $blocks = $this->_getBlocks($required,
225: //                                    $required->getFreePeriods($this->_start->timestamp(), $this->_end->timestamp()),
226: //                                    'meetingblock.html', _("Required Attendees"));
227: //
228: //        $template = $GLOBALS['injector']->createInstance('Horde_Template');
229: //        $template->set('name', _("Required Attendees"));
230: //        $template->set('blocks', $blocks);
231: //        $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
232: 
233:         // Reset locale.
234:         setlocale(LC_NUMERIC, $lc);
235: 
236:         $template = $GLOBALS['injector']->createInstance('Horde_Template');
237:         $template->set('rows', $rows);
238:         $template->set('title', _("Overview"));
239:         $template->set('span', count($this->_timeBlocks));
240:         $template->set('hours', $hours_html);
241:         if ($prefs->getValue('show_fb_legend')) {
242:             $template->setOption('gettext', true);
243:             $template->set('legend', $template->fetch(KRONOLITH_TEMPLATES . '/fbview/legend.html'));
244:         } else {
245:             $template->set('legend', '');
246:         }
247: 
248:         return $html . $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.html') . '</div>';
249:     }
250: 
251:     /**
252:      * Attempts to return a concrete Kronolith_FreeBusy_View instance based on
253:      * $view.
254:      *
255:      * @param string $view  The type of concrete Kronolith_FreeBusy_View
256:      *                      subclass to return.
257:      *
258:      * @return mixed  The newly created concrete Kronolith_FreeBusy_View
259:      *                instance, or false on an error.
260:      */
261:     static public function factory($view)
262:     {
263:         $driver = basename($view);
264:         $class = 'Kronolith_FreeBusy_View_' . $driver;
265:         if (class_exists($class)) {
266:             return new $class();
267:         }
268: 
269:         return false;
270:     }
271: 
272:     /**
273:      * Attempts to return a reference to a concrete Kronolith_FreeBusy_View
274:      * instance based on $view.  It will only create a new instance if no
275:      * Kronolith_FreeBusy_View instance with the same parameters currently
276:      * exists.
277:      *
278:      * This method must be invoked as:
279:      * $var = &Kronolith_FreeBusy_View::singleton()
280:      *
281:      * @param string $view  The type of concrete Kronolith_FreeBusy_View
282:      *                      subclass to return.
283:      *
284:      * @return mixed  The created concrete Kronolith_FreeBusy_View instance, or
285:      *                false on an error.
286:      */
287:     static public function &singleton($view)
288:     {
289:         static $instances = array();
290: 
291:         if (!isset($instances[$view])) {
292:             $instances[$view] = Kronolith_FreeBusy_View::factory($view);
293:         }
294: 
295:         return $instances[$view];
296:     }
297: 
298:     /**
299:      * Render the blocks
300:      *
301:      * @param Horde_Icalendar_Vfreebusy $member  Member's freebusy info
302:      * @param array $periods                     Free periods
303:      * @param string $blockfile                  Template file to use for blocks
304:      * @param string $label                      Label to use
305:      *
306:      * @return string  The block html
307:      */
308:     protected function _getBlocks($member, $periods, $blockfile, $label)
309:     {
310:         $template = $GLOBALS['injector']->createInstance('Horde_Template');
311:         $template->set('label', $label);
312: 
313:         reset($periods);
314:         list($periodStart, $periodEnd) = each($periods);
315: 
316:         $blocks = '';
317:         foreach ($this->_timeBlocks as $span) {
318:             /* Horde_Icalendar_Vfreebusy only supports timestamps at the
319:              * moment. */
320:             $start = $span[0]->timestamp();
321:             $end = $span[1]->timestamp();
322:             if ($member->getStart() > $start ||
323:                 $member->getEnd() < $end) {
324:                 $blocks .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/unknownblock.html');
325:                 continue;
326:             }
327: 
328:             while ($start > $periodEnd &&
329:                    list($periodStart, $periodEnd) = each($periods));
330: 
331:             if (($periodStart <= $start && $periodEnd >= $start) ||
332:                 ($periodStart <= $end && $periodEnd >= $end) ||
333:                 ($periodStart <= $start && $periodEnd >= $end) ||
334:                 ($periodStart >= $start && $periodEnd <= $end)) {
335: 
336:                 $l_start = ($periodStart < $start) ? $start : $periodStart;
337:                 $l_end = ($periodEnd > $end) ? $end : $periodEnd;
338:                 $plen = ($end - $start) / 100.0;
339: 
340:                 $left = ($l_start - $start) / $plen;
341:                 $width = ($l_end - $l_start) / $plen;
342: 
343:                 $template->set('left', $left . '%');
344:                 $template->set('width', $width . '%');
345: 
346:                 $blocks .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/' . $blockfile);
347:             } else {
348:                 $blocks .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/emptyblock.html');
349:             }
350:         }
351: 
352:         return $blocks;
353:     }
354: 
355:     abstract protected function _title();
356:     abstract protected function _hours();
357:     abstract protected function _render(Horde_Date $day = null);
358: 
359: }
360: 
API documentation generated by ApiGen