1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 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: 29: 30: 31:
32: public function addRequiredMember(Kronolith_Freebusy $vFreebusy)
33: {
34: $this->_requiredMembers[] = clone $vFreebusy;
35: }
36:
37: 38: 39: 40: 41:
42: public function addOptionalMember(Kronoolith_Freebusy $vFreebusy)
43: {
44: $this->_optionalMembers[] = clone $vFreebusy;
45: }
46:
47: 48: 49: 50: 51:
52: public function addOptionalResourceMember(Kronolith_Freebusy $vFreebusy)
53: {
54: $this->_optionalResourceMembers[] = clone $vFreebusy;
55: }
56:
57: 58: 59: 60: 61:
62: public function addRequiredResourceMember(Kronolith_Freebusy $vFreebusy)
63: {
64: $this->_requiredResourceMembers[] = clone $vFreebusy;
65: }
66:
67: 68: 69: 70: 71: 72: 73: 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:
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:
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:
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:
125:
126: $lc = setlocale(LC_NUMERIC, 0);
127: setlocale(LC_NUMERIC, 'C');
128:
129:
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:
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:
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:
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:
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:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
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: 253: 254: 255: 256: 257: 258: 259: 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: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 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: 300: 301: 302: 303: 304: 305: 306: 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: 319:
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: