355 lines
14 KiB
PHP
355 lines
14 KiB
PHP
<?php
|
|
/**
|
|
* This class represent a view of multiple free busy information sets.
|
|
*
|
|
* Copyright 2003-2017 Horde LLC (http://www.horde.org/)
|
|
*
|
|
* See the enclosed file COPYING for license information.
|
|
*
|
|
* @author Mike Cochrane <mike@graftonhall.co.nz>
|
|
* @author Jan Schneider <jan@horde.org>
|
|
* @package Kronolith
|
|
*/
|
|
abstract class Kronolith_FreeBusy_View
|
|
{
|
|
protected $_requiredMembers = array();
|
|
protected $_optionalMembers = array();
|
|
protected $_requiredResourceMembers = array();
|
|
protected $_optionalResourceMembers = array();
|
|
protected $_timeBlocks = array();
|
|
|
|
protected $_startHour;
|
|
protected $_endHour;
|
|
|
|
protected $_start;
|
|
protected $_end;
|
|
|
|
/**
|
|
* Adds a required attendee
|
|
*
|
|
* @param Horde_Icalendar_Vfreebusy $vFreebusy
|
|
*/
|
|
public function addRequiredMember(Horde_Icalendar_Vfreebusy $vFreebusy)
|
|
{
|
|
$this->_requiredMembers[] = clone $vFreebusy;
|
|
}
|
|
|
|
/**
|
|
* Adds an optional attendee
|
|
*
|
|
* @param Horde_Icalendar_Vfreebusy $vFreebusy
|
|
*/
|
|
public function addOptionalMember(Horde_Icalendar_Vfreebusy $vFreebusy)
|
|
{
|
|
$this->_optionalMembers[] = clone $vFreebusy;
|
|
}
|
|
|
|
/**
|
|
* Adds an optional resource
|
|
*
|
|
* @param Horde_Icalendar_Vfreebusy $vFreebusy
|
|
*/
|
|
public function addOptionalResourceMember(Horde_Icalendar_Vfreebusy $vFreebusy)
|
|
{
|
|
$this->_optionalResourceMembers[] = clone $vFreebusy;
|
|
}
|
|
|
|
/**
|
|
* Adds a required resource
|
|
*
|
|
* @param Horde_Icalendar_Vfreebusy $vFreebusy
|
|
*/
|
|
public function addRequiredResourceMember(Horde_Icalendar_Vfreebusy $vFreebusy)
|
|
{
|
|
$this->_requiredResourceMembers[] = clone $vFreebusy;
|
|
}
|
|
|
|
/**
|
|
* Renders the fb view
|
|
*
|
|
* @global Horde_Prefs $prefs
|
|
* @param Horde_Date $day The day to render
|
|
*
|
|
* @return string The html of the rendered fb view.
|
|
*/
|
|
public function render(Horde_Date $day = null)
|
|
{
|
|
global $prefs;
|
|
|
|
$this->_startHour = floor($prefs->getValue('day_hour_start') / 2);
|
|
$this->_endHour = floor(($prefs->getValue('day_hour_end') + 1) / 2);
|
|
|
|
$this->_render($day);
|
|
|
|
$vCal = new Horde_Icalendar();
|
|
|
|
/* Required members */
|
|
$required = Horde_Icalendar::newComponent('vfreebusy', $vCal);
|
|
foreach ($this->_requiredMembers as $member) {
|
|
$required->merge($member, false);
|
|
}
|
|
foreach ($this->_requiredResourceMembers as $member) {
|
|
$required->merge($member, false);
|
|
}
|
|
$required->simplify();
|
|
|
|
/* Optional members */
|
|
$optional = Horde_Icalendar::newComponent('vfreebusy', $vCal);
|
|
foreach ($this->_optionalMembers as $member) {
|
|
$optional->merge($member, false);
|
|
}
|
|
foreach ($this->_optionalResourceMembers as $member) {
|
|
$optional->merge($member, false);
|
|
}
|
|
$optional->simplify();
|
|
|
|
/* Optimal time calculation */
|
|
$optimal = Horde_Icalendar::newComponent('vfreebusy', $vCal);
|
|
$optimal->merge($required, false);
|
|
$optimal->merge($optional);
|
|
|
|
$template = $GLOBALS['injector']->createInstance('Horde_Template');
|
|
$template->set('title', $this->_title());
|
|
|
|
$html = $template->fetch(KRONOLITH_TEMPLATES . '/fbview/header.html') .
|
|
'<div class="fbgrid">';
|
|
|
|
$hours_html = $this->_hours();
|
|
|
|
// Set C locale to avoid localized decimal separators during CSS width
|
|
// calculation.
|
|
$lc = setlocale(LC_NUMERIC, 0);
|
|
setlocale(LC_NUMERIC, 'C');
|
|
|
|
// Required to attend.
|
|
if (count($this->_requiredMembers) > 0) {
|
|
$rows = '';
|
|
foreach ($this->_requiredMembers as $member) {
|
|
$member->simplify();
|
|
$blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.html', _("Busy"));
|
|
$template = $GLOBALS['injector']->createInstance('Horde_Template');
|
|
$template->set('blocks', $blocks);
|
|
$template->set('name', htmlspecialchars($member->getName()));
|
|
$rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
|
|
}
|
|
|
|
$template = $GLOBALS['injector']->createInstance('Horde_Template');
|
|
$template->set('title', _("Required Attendees"));
|
|
$template->set('rows', $rows);
|
|
$template->set('span', count($this->_timeBlocks));
|
|
$template->set('hours', $hours_html);
|
|
$template->set('legend', '');
|
|
$html .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.html');
|
|
}
|
|
|
|
// Optional to attend.
|
|
if (count($this->_optionalMembers) > 0) {
|
|
$rows = '';
|
|
foreach ($this->_optionalMembers as $member) {
|
|
$member->simplify();
|
|
$blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.html', _("Busy"));
|
|
$template = $GLOBALS['injector']->createInstance('Horde_Template');
|
|
$template->set('blocks', $blocks);
|
|
$template->set('name', htmlspecialchars($member->getName()));
|
|
$rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
|
|
}
|
|
|
|
$template = $GLOBALS['injector']->createInstance('Horde_Template');
|
|
$template->set('title', _("Optional Attendees"));
|
|
$template->set('rows', $rows);
|
|
$template->set('span', count($this->_timeBlocks));
|
|
$template->set('hours', $hours_html);
|
|
$template->set('legend', '');
|
|
$html .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.html');
|
|
}
|
|
|
|
// Resources
|
|
if (count($this->_requiredResourceMembers) > 0 || count($this->_optionalResourceMembers) > 0) {
|
|
$template = $GLOBALS['injector']->createInstance('Horde_Template');
|
|
$rows = '';
|
|
foreach ($this->_requiredResourceMembers as $member) {
|
|
$member->simplify();
|
|
$blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.html', _("Busy"));
|
|
$template = $GLOBALS['injector']->createInstance('Horde_Template');
|
|
$template->set('blocks', $blocks);
|
|
$template->set('name', htmlspecialchars($member->getName()));
|
|
$rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
|
|
}
|
|
foreach ($this->_optionalResourceMembers as $member) {
|
|
$member->simplify();
|
|
$blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.html', _("Busy"));
|
|
$template = $GLOBALS['injector']->createInstance('Horde_Template');
|
|
$template->set('blocks', $blocks);
|
|
$template->set('name', htmlspecialchars($member->getName()));
|
|
$rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
|
|
}
|
|
$template = $GLOBALS['injector']->createInstance('Horde_Template');
|
|
$template->set('title', _("Required Resources"));
|
|
$template->set('rows', $rows);
|
|
$template->set('span', count($this->_timeBlocks));
|
|
$template->set('hours', $hours_html);
|
|
$template->set('legend', '');
|
|
$html .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.html');
|
|
}
|
|
|
|
// Possible meeting times.
|
|
$optimal->setAttribute('ORGANIZER', _("All Attendees"));
|
|
$blocks = $this->_getBlocks($optimal,
|
|
$optimal->getFreePeriods($this->_start->timestamp(), $this->_end->timestamp()),
|
|
'meetingblock.html', _("All Attendees"));
|
|
|
|
$template = $GLOBALS['injector']->createInstance('Horde_Template');
|
|
$template->set('name', _("All Attendees"));
|
|
$template->set('blocks', $blocks);
|
|
$rows = $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
|
|
|
|
// Possible meeting times.
|
|
$required->setAttribute('ORGANIZER', _("Required Attendees"));
|
|
$blocks = $this->_getBlocks($required,
|
|
$required->getFreePeriods($this->_start->timestamp(), $this->_end->timestamp()),
|
|
'meetingblock.html', _("Required Attendees"));
|
|
|
|
$template = $GLOBALS['injector']->createInstance('Horde_Template');
|
|
$template->set('name', _("Required Attendees"));
|
|
$template->set('blocks', $blocks);
|
|
$rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
|
|
|
|
// Possible meeting times.
|
|
// $resource->setAttribute('ORGANIZER', _("Required Attendees"));
|
|
// $blocks = $this->_getBlocks($required,
|
|
// $required->getFreePeriods($this->_start->timestamp(), $this->_end->timestamp()),
|
|
// 'meetingblock.html', _("Required Attendees"));
|
|
//
|
|
// $template = $GLOBALS['injector']->createInstance('Horde_Template');
|
|
// $template->set('name', _("Required Attendees"));
|
|
// $template->set('blocks', $blocks);
|
|
// $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
|
|
|
|
// Reset locale.
|
|
setlocale(LC_NUMERIC, $lc);
|
|
|
|
$template = $GLOBALS['injector']->createInstance('Horde_Template');
|
|
$template->set('rows', $rows);
|
|
$template->set('title', _("Overview"));
|
|
$template->set('span', count($this->_timeBlocks));
|
|
$template->set('hours', $hours_html);
|
|
if ($prefs->getValue('show_fb_legend')) {
|
|
$template->setOption('gettext', true);
|
|
$template->set('legend', $template->fetch(KRONOLITH_TEMPLATES . '/fbview/legend.html'));
|
|
} else {
|
|
$template->set('legend', '');
|
|
}
|
|
|
|
return $html . $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.html') . '</div>';
|
|
}
|
|
|
|
/**
|
|
* Attempts to return a concrete Kronolith_FreeBusy_View instance based on
|
|
* $view.
|
|
*
|
|
* @param string $view The type of concrete Kronolith_FreeBusy_View
|
|
* subclass to return.
|
|
*
|
|
* @return mixed The newly created concrete Kronolith_FreeBusy_View
|
|
* instance, or false on an error.
|
|
*/
|
|
static public function factory($view)
|
|
{
|
|
$driver = basename($view);
|
|
$class = 'Kronolith_FreeBusy_View_' . $driver;
|
|
if (class_exists($class)) {
|
|
return new $class();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Attempts to return a reference to a concrete Kronolith_FreeBusy_View
|
|
* instance based on $view. It will only create a new instance if no
|
|
* Kronolith_FreeBusy_View instance with the same parameters currently
|
|
* exists.
|
|
*
|
|
* This method must be invoked as:
|
|
* $var = &Kronolith_FreeBusy_View::singleton()
|
|
*
|
|
* @param string $view The type of concrete Kronolith_FreeBusy_View
|
|
* subclass to return.
|
|
*
|
|
* @return mixed The created concrete Kronolith_FreeBusy_View instance, or
|
|
* false on an error.
|
|
*/
|
|
static public function &singleton($view)
|
|
{
|
|
static $instances = array();
|
|
|
|
if (!isset($instances[$view])) {
|
|
$instances[$view] = Kronolith_FreeBusy_View::factory($view);
|
|
}
|
|
|
|
return $instances[$view];
|
|
}
|
|
|
|
/**
|
|
* Render the blocks
|
|
*
|
|
* @param Horde_Icalendar_Vfreebusy $member Member's freebusy info
|
|
* @param array $periods Free periods
|
|
* @param string $blockfile Template file to use for blocks
|
|
* @param string $label Label to use
|
|
*
|
|
* @return string The block html
|
|
*/
|
|
protected function _getBlocks($member, $periods, $blockfile, $label)
|
|
{
|
|
$template = $GLOBALS['injector']->createInstance('Horde_Template');
|
|
$template->set('label', $label);
|
|
|
|
reset($periods);
|
|
list($periodStart, $periodEnd) = each($periods);
|
|
|
|
$blocks = '';
|
|
foreach ($this->_timeBlocks as $span) {
|
|
/* Horde_Icalendar_Vfreebusy only supports timestamps at the
|
|
* moment. */
|
|
$start = $span[0]->timestamp();
|
|
$end = $span[1]->timestamp();
|
|
if ($member->getStart() > $start ||
|
|
$member->getEnd() < $end) {
|
|
$blocks .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/unknownblock.html');
|
|
continue;
|
|
}
|
|
|
|
while ($start > $periodEnd &&
|
|
list($periodStart, $periodEnd) = each($periods));
|
|
|
|
if (($periodStart <= $start && $periodEnd >= $start) ||
|
|
($periodStart <= $end && $periodEnd >= $end) ||
|
|
($periodStart <= $start && $periodEnd >= $end) ||
|
|
($periodStart >= $start && $periodEnd <= $end)) {
|
|
|
|
$l_start = ($periodStart < $start) ? $start : $periodStart;
|
|
$l_end = ($periodEnd > $end) ? $end : $periodEnd;
|
|
$plen = ($end - $start) / 100.0;
|
|
|
|
$left = ($l_start - $start) / $plen;
|
|
$width = ($l_end - $l_start) / $plen;
|
|
|
|
$template->set('left', $left . '%');
|
|
$template->set('width', $width . '%');
|
|
|
|
$blocks .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/' . $blockfile);
|
|
} else {
|
|
$blocks .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/emptyblock.html');
|
|
}
|
|
}
|
|
|
|
return $blocks;
|
|
}
|
|
|
|
abstract protected function _title();
|
|
abstract protected function _hours();
|
|
abstract protected function _render(Horde_Date $day = null);
|
|
|
|
}
|