[ Index ]
 

Code source de eGroupWare 1.2.106-2

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/calendar/inc/ -> class.uiviews.inc.php (source)

   1  <?php
   2  /**************************************************************************\
   3  * eGroupWare - Calendar - Views and Widgets                                *
   4  * http://www.egroupware.org                                                *
   5  * Written and (c) 2004/5 by Ralf Becker <RalfBecker@outdoor-training.de>   *
   6  * --------------------------------------------                             *
   7  *  This program is free software; you can redistribute it and/or modify it *
   8  *  under the terms of the GNU General Public License as published by the   *
   9  *  Free Software Foundation; either version 2 of the License, or (at your  *
  10  *  option) any later version.                                              *
  11  \**************************************************************************/
  12  
  13  /* $Id: class.uiviews.inc.php 23119 2006-12-25 12:58:03Z ralfbecker $ */
  14  
  15  include_once (EGW_INCLUDE_ROOT . '/calendar/inc/class.uical.inc.php');
  16  
  17  /**
  18   * Class to generate the calendar views and the necesary widgets
  19   *
  20   * @package calendar
  21   * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
  22   * @copyright (c) 2004/5 by RalfBecker-At-outdoor-training.de
  23   * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
  24   */
  25  class uiviews extends uical
  26  {
  27      var $public_functions = array(
  28          'day'   => True,
  29          'day4'  => True,
  30          'week'  => True,
  31          'month' => True,
  32          'planner' => True,
  33      );
  34  
  35      /**
  36       * integer level or string function- or widget-name
  37       * 
  38       * @var mixed $debug 
  39       */
  40      var $debug=false;
  41  
  42      /**
  43       * minimum width for an event
  44       * 
  45       * @var int $eventCol_min_width
  46       */
  47      var $eventCol_min_width = 80;
  48      
  49      /**
  50       * extra rows above and below the workday
  51       * 
  52       * @var int $extraRows 
  53       */
  54      var $extraRows = 1;
  55  
  56      var $timeRow_width = 40;
  57  
  58      /**
  59       * how many rows per day get displayed, gets set be the timeGridWidget
  60       * 
  61       * @var int $rowsToDisplay 
  62       */
  63      var $rowsToDisplay;
  64  
  65      /**
  66       * height in percent of one row, gets set be the timeGridWidget
  67       * 
  68       * @var int $rowHeight
  69       */
  70      var $rowHeight;
  71      
  72      /**
  73       * standard params for calling bocal::search for all views, set by the constructor
  74       * 
  75       * @var array $search_params
  76       */
  77      var $search_params;
  78      
  79      /**
  80       * should we use a time grid, can be set for week- and month-view to false by the cal_pref no_time_grid
  81       * 
  82       * @var boolean $use_time_grid=true 
  83       */
  84      var $use_time_grid=true;
  85      
  86      /**
  87       * Can we display the whole day in a timeGrid of the size of the workday and just scroll to workday start
  88       *
  89       * @var boolean $scroll_to_wdstart;
  90       */
  91      var $scroll_to_wdstart=false;
  92  
  93      /**
  94       * Constructor
  95       *
  96       * @param array $set_states=null to manualy set / change one of the states, default NULL = use $_REQUEST
  97       */
  98  	function uiviews($set_states=null)
  99      {
 100          $this->uical(false,$set_states);    // call the parent's constructor
 101  
 102          $GLOBALS['egw_info']['flags']['nonavbar'] = False;
 103          $app_header = array(
 104              'day'   => lang('Dayview'),
 105              '4day'  => lang('Four days view'),
 106              'week'  => lang('Weekview'),
 107              'month' => lang('Monthview'),
 108              'planner' => lang('Group planner'),
 109          );
 110          $GLOBALS['egw_info']['flags']['app_header'] = $GLOBALS['egw_info']['apps']['calendar']['title'].
 111              (isset($app_header[$this->view]) ? ' - '.$app_header[$this->view] : '').
 112              // for a single owner we add it's name to the app-header
 113              (count(explode(',',$this->owner)) == 1 ? ': '.$this->bo->participant_name($this->owner) : '');
 114  
 115          // standard params for calling bocal::search for all views
 116          $this->search_params = array(
 117              'start'   => $this->date,
 118              'cat_id'  => $this->cat_id,
 119              'users'   => explode(',',$this->owner),
 120              'filter'  => $this->filter,
 121              'daywise' => True,
 122          );
 123          $this->holidays = $this->bo->read_holidays($this->year);
 124          
 125          $this->check_owners_access();
 126      }
 127      
 128      /**
 129       * Show the last view or the default one, if no last
 130       */
 131  	function index()
 132      {
 133          if (!$this->view) $this->view = 'week';
 134  
 135          // handle views in other files
 136          if (!isset($this->public_functions[$this->view]))
 137          {
 138              $GLOBALS['egw']->redirect_link('/index.php',array('menuaction'=>$this->view_menuaction));
 139          }
 140          // get manual to load the right page
 141          $GLOBALS['egw_info']['flags']['params']['manual'] = array('page' => 'ManualCalendar'.ucfirst($this->view));
 142          
 143          $this->{$this->view}();
 144      }
 145      
 146      /**
 147       * Show the calendar on the home page
 148       *
 149       * @return string with content
 150       */
 151      function &home()
 152      {
 153          // set some stuff for the home-page
 154          $this->uiviews(array(
 155              'date'       => $this->bo->date2string($this->bo->now_su),
 156              'cat_id'     => 0,
 157              'filter'     => 'all',
 158              'owner'      => substr($this->cal_prefs['defaultcalendar'],0,7) == 'planner' && $this->cal_prefs['planner_start_with_group'] ? 
 159                  $this->cal_prefs['planner_start_with_group'] : $this->user,
 160              'multiple'   => 0,
 161              'view'       => $this->bo->cal_prefs['defaultcalendar'],            
 162          ));
 163          
 164          if (($error = $this->check_owners_access()))
 165          {
 166              return $error;
 167          }
 168          if ($this->group_warning)
 169          {
 170              $group_warning = '<p class="redItalic" align="center">'.$this->group_warning."</p>\n";
 171          }
 172          switch($this->cal_prefs['defaultcalendar'])
 173          {
 174              case 'planner_user':
 175              case 'planner_cat':
 176              case 'planner':
 177                  return $group_warning.$this->planner(true);
 178  
 179              case 'month':
 180                  return $group_warning.$this->month(0,true);
 181  
 182              default:
 183              case 'week':
 184                  return $group_warning.$this->week(0,true);
 185                  
 186              case 'day':
 187                  return $group_warning.$this->day(true);
 188          }
 189      }
 190      
 191      /**
 192       * Displays the planner view
 193       *
 194       * @param boolean $home=false if true return content suitable for home-page
 195       */
 196      function &planner($home=false)
 197      {
 198          if (!$this->planner_days)    // planner monthview
 199          {
 200              if ($this->day < 15)    // show one complete month
 201              {
 202                  $this->_week_align_month($this->first,$this->last);
 203                  $GLOBALS['egw_info']['flags']['app_header'] .= ': '.lang(adodb_date('F',$this->bo->date2ts($this->date))).' '.$this->year;
 204              }
 205              else    // show 2 half month
 206              {
 207                  $this->_week_align_month($this->first,$this->last,15);
 208                  $GLOBALS['egw_info']['flags']['app_header'] .= ': '.lang(adodb_date('F',$this->first)).' / '.lang(adodb_date('F',$this->last)).' '.$this->year;
 209              }
 210          }
 211          elseif ($this->planner_days >= 5)    // weeekview
 212          {
 213              $this->first = $this->datetime->get_weekday_start($this->year,$this->month,$this->day);
 214              $this->last = $this->bo->date2array($this->first);
 215              $this->last['day'] += (int) $this->planner_days - 1;
 216              $this->last['hour'] = 23; $this->last['minute'] = $this->last['sec'] = 59;
 217              unset($this->last['raw']);
 218              $this->last = $this->bo->date2ts($this->last);
 219              $GLOBALS['egw_info']['flags']['app_header'] .= ': '.lang('Week').' '.adodb_date('W',$this->first).': '.$this->bo->long_date($this->first,$this->last);
 220          }
 221          else // dayview
 222          {
 223              $this->first = $this->bo->date2ts($this->date);
 224              $this->last = $this->bo->date2array($this->first);
 225              $this->last['day'] += (int) $this->planner_days - 1;
 226              $this->last['hour'] = 23; $this->last['minute'] = $this->last['sec'] = 59;
 227              unset($this->last['raw']);
 228              $this->last = $this->bo->date2ts($this->last);
 229              $GLOBALS['egw_info']['flags']['app_header'] .= ': '.($this->planner_days == 1 ? lang(date('l',$this->first)).', ' : '').
 230                  $this->bo->long_date($this->first,$this->planner_days > 1 ? $this->last : 0);
 231          }
 232          
 233          $search_params = $this->search_params;
 234          $search_params['daywise'] = false;
 235          $search_params['start'] = $this->first;
 236          $search_params['end'] = $this->last;
 237          $search_params['enum_groups'] = $this->sortby == 'user';
 238          $events = $this->bo->search($search_params);
 239  
 240          if ($this->debug > 0) $this->bo->debug_message('uiviews::planner() date=%1: first=%2, last=%3',False,$this->date,$this->bo->date2string($this->first),$this->bo->date2string($this->last));
 241  
 242          $content =& $this->plannerWidget($events,$this->first,$this->last,$this->sortby == 'user' ? false : (int) $this->cat_id);
 243  
 244          if (!$home)
 245          {
 246              $this->do_header();
 247          
 248              echo $content;
 249          }
 250          return $content;
 251      }
 252  
 253      /**
 254       * Displays the monthview or a multiple week-view
 255       *
 256       * @param int $weeks=0 number of weeks to show, if 0 (default) all weeks of one month are shows
 257       * @param boolean $home=false if true return content suitable for home-page
 258       */
 259      function &month($weeks=0,$home=false)
 260      {
 261          if ($this->debug > 0) $this->bo->debug_message('uiviews::month(weeks=%1) date=%2',True,$weeks,$this->date);
 262  
 263          $this->use_time_grid = $this->cal_prefs['use_time_grid'] == '';    // all views
 264  
 265          if ($weeks)
 266          {
 267              $this->first = $this->datetime->get_weekday_start($this->year,$this->month,$this->day=1);
 268              $this->last = $this->first + $weeks * 7 * DAY_s - 1;
 269          }
 270          else
 271          {
 272              $this->_week_align_month($this->first,$this->last);
 273          }
 274          if ($this->debug > 0) $this->bo->debug_message('uiviews::month(%1) date=%2: first=%3, last=%4',False,$weeks,$this->date,$this->bo->date2string($this->first),$this->bo->date2string($this->last));
 275  
 276          $GLOBALS['egw_info']['flags']['app_header'] .= ': '.lang(adodb_date('F',$this->bo->date2ts($this->date))).' '.$this->year;
 277  
 278          $days =& $this->bo->search(array(
 279              'start'   => $this->first,
 280              'end'     => $this->last,
 281          )+$this->search_params);
 282  
 283          $content = '';
 284          // we add DAY_s/2 to $this->first (using 12h), to deal with daylight saving changes
 285          for ($week_start = $this->first+DAY_s/2; $week_start < $this->last; $week_start += WEEK_s)
 286          {
 287              $week = array();
 288              for ($i = 0; $i < 7; ++$i)
 289              {
 290                  $day_ymd = $this->bo->date2string($week_start+$i*DAY_s);
 291                  $week[$day_ymd] = array_shift($days);
 292              }
 293              $week_view = array(
 294                  'menuaction' => 'calendar.uiviews.week',
 295                  'date' => $this->bo->date2string($week_start),
 296              );
 297              $title = lang('Wk').' '.adodb_date('W',$week_start);
 298              $title = $this->html->a_href($title,$week_view,'',' title="'.lang('Weekview').'"');
 299  
 300              $content .= $this->timeGridWidget($week,60,200,'',$title,0,$week_start+WEEK_s >= $this->last);
 301          }
 302          if (!$home)
 303          {
 304              $this->do_header();
 305          
 306              echo $content;
 307          }
 308          return $content;
 309      }
 310  
 311      /**
 312       * get start and end of a month aligned to full weeks
 313       *
 314       * @param int &$first timestamp 0h of first day of week containing the first of the current month
 315       * @param int &$last timestamp 23:59:59 of last day of week containg the last day of the current month
 316       * @param int $day=1 should the alignment be based on the 1. of the month or an other date, eg. the 15.
 317       */
 318  	function _week_align_month(&$first,&$last,$day=1)
 319      {
 320          $first = $this->datetime->get_weekday_start($this->year,$this->month,$this->day=$day);
 321          if ($day == 1)
 322          {
 323              $last = $this->datetime->get_weekday_start($this->year,$this->month,
 324                  $this->datetime->days_in_month($this->month,$this->year));
 325          }
 326          else
 327          {
 328              $last = $this->datetime->get_weekday_start($this->year,$this->month+1,$day);
 329          }            
 330          // now we need to calculate the end of the last day of that week
 331          // as simple $last += WEEK_s - 1; does NOT work, if daylight saving changes in that week!!!
 332          $last = $this->bo->date2array($last);
 333          $last['day'] += 6; 
 334          $last['hour'] = 23; 
 335          $last['min'] = $last['sec'] = 59;
 336          unset($last['raw']);    // otherwise date2ts does not calc raw new, but uses it
 337          $last = $this->bo->date2ts($last);
 338      }
 339      
 340      /**
 341       * Four days view, everythings done by the week-view code ...
 342       *
 343       * @param boolean $home=false if true return content suitable for home-page
 344       * @return string
 345       */
 346  	function day4($home=false)
 347      {
 348          return $this->week(4,$home);
 349      }
 350  
 351      /**
 352       * Displays the weekview, with 5 or 7 days
 353       *
 354       * @param int $days=0 number of days to show, if 0 (default) the value from the URL or the prefs is used
 355       * @param boolean $home=false if true return content suitable for home-page
 356       */
 357  	function week($days=0,$home=false)
 358      {
 359          $this->use_time_grid = $days != 4 && !in_array($this->cal_prefs['use_time_grid'],array('day','day4')) ||
 360              $days == 4 && $this->cal_prefs['use_time_grid'] != 'day';
 361  
 362          if (!$days)
 363          {
 364              $days = isset($_GET['days']) ? $_GET['days'] : $this->cal_prefs['days_in_weekview'];
 365              if ($days != 5) $days = 7;
 366              if ($days != $this->cal_prefs['days_in_weekview'])    // save the preference
 367              {
 368                  $GLOBALS['egw']->preferences->add('calendar','days_in_weekview',$days);
 369                  $GLOBALS['egw']->preferences->save_repository();
 370                  $this->cal_prefs['days_in_weekview'] = $days;
 371              }
 372          }
 373          if ($this->debug > 0) $this->bo->debug_message('uiviews::week(days=%1) date=%2',True,$days,$this->date);
 374  
 375          if ($days == 4)        // next 4 days view
 376          {
 377              $wd_start = $this->first = $this->bo->date2ts($this->date);
 378              $this->last = $this->first + $days * DAY_s - 1;
 379              $GLOBALS['egw_info']['flags']['app_header'] .= ': '.lang('Four days view').' '.$this->bo->long_date($this->first,$this->last);
 380          }
 381          else
 382          {
 383              $wd_start = $this->first = $this->datetime->get_weekday_start($this->year,$this->month,$this->day);
 384              if ($days == 5)        // no weekend-days
 385              {
 386                  switch($this->cal_prefs['weekdaystarts'])
 387                  {
 388                      case 'Saturday':
 389                          $this->first += DAY_s;
 390                          // fall through
 391                      case 'Sunday':
 392                          $this->first += DAY_s;
 393                          break;
 394                  }
 395              }
 396              $this->last = $this->first + $days * DAY_s - 1;
 397              $GLOBALS['egw_info']['flags']['app_header'] .= ': '.lang('Week').' '.adodb_date('W',$this->first).': '.$this->bo->long_date($this->first,$this->last);
 398          }
 399          //echo "<p>weekdaystarts='".$this->cal_prefs['weekdaystarts']."', get_weekday_start($this->year,$this->month,$this->day)=".date('l Y-m-d',$wd_start).", first=".date('l Y-m-d',$this->first)."</p>\n";
 400  
 401          $search_params = array(
 402                  'start'   => $this->first,
 403                  'end'     => $this->last,
 404              ) + $this->search_params;
 405  
 406          $users = $this->search_params['users'];
 407          if (!is_array($users)) $users = array($users);
 408          
 409          if (count($users) == 1 || count($users) > 3)    // for more then 3 users, show all in one row
 410          {
 411              $content =& $this->timeGridWidget($this->bo->search($search_params),$this->cal_prefs['interval']);
 412          }
 413          else
 414          {
 415              $content = '';
 416              foreach($this->_get_planner_users(false) as $uid => $label)
 417              {
 418                  $search_params['users'] = $uid;
 419                  $content .= '<b>'.$label."</b>\n";
 420                  $content .= $this->timeGridWidget($this->bo->search($search_params),
 421                      count($users) * $this->cal_prefs['interval'],400 / count($users),'','',$uid);
 422              }
 423          }        
 424          if (!$home)
 425          {
 426              $this->do_header();
 427              
 428              echo $content;
 429          }
 430          return $content;
 431      }
 432  
 433      /**
 434       * Displays the dayview
 435       *
 436       * @param boolean $home=false if true return content suitable for home-page
 437       */
 438      function &day($home=false)
 439      {
 440          if ($this->debug > 0) $this->bo->debug_message('uiviews::day() date=%1',True,$this->date);
 441  
 442          $this->last = $this->first = $this->bo->date2ts((string)$this->date);
 443          $GLOBALS['egw_info']['flags']['app_header'] .= ': '.$this->bo->long_date($this->first,0,false,true);
 444          
 445          $this->use_time_grid = true;    // day-view always uses a time-grid, independent what's set in the prefs!
 446          
 447          $this->search_params['end'] = $this->last = $this->first+DAY_s-1;
 448          
 449          if (!$home)
 450          {
 451              $this->do_header();
 452      
 453              $users = $this->search_params['users'];
 454              if (!is_array($users)) $users = array($users);
 455  
 456              // for more then 5 users, show all in one row
 457              if (count($users) == 1 || count($users) > 5) 
 458              {
 459                  $dayEvents =& $this->bo->search($this->search_params);
 460                  $owner = 0;
 461              }
 462              else
 463              {
 464                  $dayEvents = $owner = array();
 465                  $search_params = $this->search_params;
 466                  foreach($this->_get_planner_users(false) as $uid => $label)
 467                  {
 468                      $search_params['users'] = $uid;
 469                      list(,$dayEvents['<b>'.$label.'</b>']) = each($this->bo->search($search_params));
 470                      $owner[] = $uid;
 471                  }
 472              }
 473              $cols = array();
 474              $cols[0] =& $this->timeGridWidget($dayEvents,$this->cal_prefs['interval'],450,'','',$owner);
 475  
 476              // only show todo's for a single user
 477              if (count($users) == 1 && ($todos = $this->get_todos($todo_label)) !== false)
 478              {
 479                  if ($GLOBALS['egw_info']['user']['apps']['infolog'])
 480                  {
 481                      foreach(array('task','phone','note') as $type)
 482                      {
 483                          $todo_label .= '&nbsp;'.$this->html->a_href( $this->html->image('infolog',$type,lang('Add')),'infolog.uiinfolog.edit',array(
 484                              'type' => $type,
 485                              'start_time' => $ts,
 486                          ),' target="_blank" onclick="window.open(this.href,this.target,\'dependent=yes,width=750,height=590,scrollbars=yes,status=yes\'); return false;"');
 487                      }
 488                  }
 489                  $cols[1] = $this->html->div(
 490                      $this->html->div($todo_label,'','calDayTodosHeader th')."\n".
 491                      $this->html->div($todos,'','calDayTodosTable'),'','calDayTodos');
 492                  $cols['.1'] = 'width=30%';
 493                  echo $this->html->table(array(
 494                      0 => $cols,
 495                      '.0' => 'valign="top"'
 496                  ),'class="calDayView"');
 497              }
 498              else
 499              {
 500                  echo $cols[0];
 501              }
 502          }
 503          else
 504          {
 505              return $this->timeGridWidget($this->bo->search($this->search_params),$this->cal_prefs['interval'],300);
 506          }
 507      }
 508  
 509      /**
 510       * Query the open ToDo's via a hook from InfoLog or any other 'calendar_include_todos' provider
 511       *
 512       * @param array/string $todo_label label for the todo-box or array with 2 values: the label and a boolean show_all
 513       *    On return $todo_label contains the label for the todo-box
 514       * @return string/boolean html with a table of open todo's or false if no hook availible
 515       */
 516  	function get_todos(&$todo_label)
 517      {
 518          $todos_from_hook = $GLOBALS['egw']->hooks->process(array(
 519              'location'  => 'calendar_include_todos',
 520              'year'      => $this->year,
 521              'month'     => $this->month,
 522              'day'       => $this->day,
 523              'owner'     => $this->owner    // num. id of the user, not necessary current user
 524          ));
 525  
 526          if(is_array($todo_label))
 527          {
 528              list($label,$showall)=$todo_label;
 529          }
 530          else
 531          {
 532              $label=$todo_label;
 533              $showall=true;
 534          }
 535          $maxshow = (int)$GLOBALS['egw_info']['user']['preferences']['infolog']['mainscreen_maxshow'];
 536          if($maxshow <= 0)
 537          {
 538              $maxshow=10;
 539          }
 540          //print_debug("get_todos(): label=$label; showall=$showall; max=$maxshow");
 541  
 542          $content = $todo_label = '';
 543          if (is_array($todos_from_hook) && count($todos_from_hook))
 544          {
 545              foreach($todos_from_hook as $todos)
 546              {
 547                  $i = 0;
 548                  if (is_array($todos))
 549                  {
 550                      $todo_label = !empty($label) ? $label : lang("open ToDo's:");
 551  
 552                      foreach($todos as $todo)
 553                      {
 554                          if(!$showall && ($i++ > $maxshow))
 555                          {
 556                              break;
 557                          }
 558                          $icons = '';
 559                          foreach($todo['icons'] as $name => $app)
 560                          {
 561                              $icons .= ($icons?' ':'').$GLOBALS['egw']->html->image($app,$name,lang($name),'border="0" width="15" height="15"');
 562                          }
 563                          $class = $class == 'row_on' ? 'row_off' : 'row_on';
 564  
 565                          $content .= " <tr class=\"$class\">\n  <td valign=\"top\" width=\"15%\" nowrap>".
 566                              ($this->bo->printer_friendly?$icons:$GLOBALS['egw']->html->a_href($icons,$todo['view'])).
 567                              "</td>\n  <td>".($this->printer_friendly?$todo['title']:
 568                              $GLOBALS['egw']->html->a_href($todo['title'],$todo['view']))."</td>\n </tr>\n";
 569                          /**
 570                           * ToDo: add delete and closing action
 571                           */
 572                      }
 573                  }
 574              }
 575          }
 576          if (!empty($content))
 577          {
 578              return "<table border=\"0\" width=\"100%\">\n$content</table>\n";
 579          }
 580          return $todo_label ? '' : false;
 581      }
 582          
 583      /**
 584       * Calculates the vertical position based on the time
 585       *
 586       * workday start- and end-time, is taken into account, as well as timeGrids px_m - minutes per pixel param
 587       *
 588       * @param int $time in minutes
 589       * @return float position in percent
 590       */
 591  	function time2pos($time)
 592      {
 593          if ($this->scroll_to_wdstart)    // we display the complete day - thought only workday is visible without scrolling
 594          {
 595              return $this->rowHeight * (1 + $this->extraRows + $time/$this->granularity_m);
 596          }
 597          // time before workday => condensed in the first $this->extraRows rows
 598          if ($this->wd_start > 0 && $time < $this->wd_start)
 599          {
 600              $pos = (1 + $this->extraRows * $time / $this->wd_start) * $this->rowHeight;    // 1 for the header
 601          }
 602          // time after workday => condensed in the last row
 603          elseif ($this->wd_end < 24*60 && $time > $this->wd_end+1*$this->granularity_m)
 604          {
 605              $pos = 100 - ($this->extraRows * $this->rowHeight * (1 - ($time - $this->wd_end) / (24*60 - $this->wd_end)));
 606          }
 607          // time during the workday => 2. row on (= + granularity)
 608          else
 609          {
 610              $pos = $this->rowHeight * (1+$this->extraRows+($time-$this->wd_start)/$this->granularity_m);
 611          }
 612          $pos = round($pos,1);
 613  
 614          if ($this->debug > 3) $this->bo->debug_message('uiviews::time2pos(%1)=%2',False,$time,$pos);
 615  
 616          return $pos;
 617      }
 618  
 619      /**
 620       * Calculates the height of a differenc between 2 times
 621       *
 622       * workday start- and end-time, is taken into account, as well as timeGrids px_m - minutes per pixel param
 623       *
 624       * @param int $start time in minutes
 625       * @param int $end time in minutes
 626       * @param int $minimum=0 minimum height
 627       * @return float height in percent
 628       */
 629  	function times2height($start,$end,$minimum=0)
 630      {
 631          $minimum = $this->rowHeight;
 632          $height = $this->time2pos($end) - $this->time2pos($start);
 633  
 634          if ($this->debug > 3) $this->bo->debug_message('uiviews::times2height(%1,%2,min=%3)=%4',False,$start,$end,$minimum,$height);
 635  
 636          return $height >= $minimum ? $height : $minimum;
 637      }
 638  
 639      /**
 640       * Creates a grid with rows for the time, columns for (multiple) days containing events
 641       *
 642       * Uses the dayColWidget to display each day.
 643       *
 644       * @param $daysEvents array with subarrays of events for each day to show, day as YYYYMMDD as key
 645       * @param int $granularity_m=30 granularity in minutes of the rows
 646       * @param int $height=400 height of the widget
 647       * @param string $indent='' string for correct indention
 648       * @param string $title='' title of the time-grid
 649       * @param int/array $owner=0 owner of the calendar (default 0 = $this->owner) or array with owner for each column
 650       * @param boolean $last=true last timeGrid displayed, default true
 651       */
 652      function &timeGridWidget($daysEvents,$granularity_m=30,$height=400,$indent='',$title='',$owner=0,$last=true)
 653      {
 654          if ($this->debug > 1 || $this->debug==='timeGridWidget') $this->bo->debug_message('uiviews::timeGridWidget(events=%1,granularity_m=%2,height=%3,,title=%4)',True,$daysEvents,$granularity_m,$height,$title);
 655  
 656          // determine if the browser supports scrollIntoView: IE4+, firefox1.0+ and safari2.0+ does
 657          // then show all hours in a div of the size of the workday and scroll to the workday start
 658          // still disabled, as things need to be re-aranged first, to that the column headers are not scrolled
 659          $this->scroll_to_wdstart = false;/*$this->use_time_grid && ($this->html->user_agent == 'msie' || 
 660              $this->html->user_agent == 'mozilla' && $this->html->ua_version >= 5.0 ||
 661              $this->html->user_agent == 'safari' && $this->html->ua_version >= 2.0);*/
 662      
 663          if ($this->scroll_to_wdstart)
 664          {
 665              $this->extraRows = 0;    // no extra rows necessary
 666              $overflow = 'overflow: scroll;';
 667          }
 668          $this->granularity_m = $granularity_m;
 669          $this->display_start = $this->wd_start - ($this->extraRows * $this->granularity_m);
 670          $this->display_end    = $this->wd_end + ($this->extraRows * $this->granularity_m);
 671  
 672          if (!$this->wd_end) $this->wd_end = 1440;
 673          $totalDisplayMinutes    = $this->wd_end - $this->wd_start;
 674          $this->rowsToDisplay    = ($totalDisplayMinutes/$granularity_m)+2+2*$this->extraRows;
 675          $this->rowHeight        = round(100/$this->rowsToDisplay,1);
 676          
 677          // ensure a minimum height of each row
 678          if ($height < ($this->rowsToDisplay+1) * 12)
 679          {
 680              $height = ($this->rowsToDisplay+1) * 12;
 681          }
 682          $html = $indent.'<div class="calTimeGrid" style="height: '.$height.'px;'.$overflow.'">'."\n";
 683  
 684          $html .= $indent."\t".'<div class="calGridHeader" style="height: '.
 685              $this->rowHeight.'%;">'.$title."</div>\n";
 686  
 687          if ($this->use_time_grid)
 688          {
 689              $off = false;    // Off-row means a different bgcolor
 690              $add_links = count($daysEvents) == 1;
 691      
 692              // the hour rows
 693              for($t = $this->scroll_to_wdstart ? 0 : $this->wd_start,$i = 1+$this->extraRows;
 694                  $t <= $this->wd_end || $this->scroll_to_wdstart && $t < 24*60;
 695                  $t += $this->granularity_m,++$i)
 696              {
 697                  $set_id = '';
 698                  if ($t == $this->wd_start)
 699                  {
 700                      list($id) = @each($daysEvents);
 701                      $id = 'wd_start_'.$id;
 702                      $set_id = ' id="'.$id.'"';
 703                  }
 704                  $html .= $indent."\t".'<div'.$set_id.' class="calTimeRow'.($off ? 'Off row_off' : ' row_on').
 705                      '" style="height: '.$this->rowHeight.'%; top:'. $i*$this->rowHeight .'%;">'."\n";
 706                  // show time for full hours, allways for 45min interval and at least on every 3 row
 707                  $time = '';
 708                  static $show = array(
 709                      5  => array(0,15,30,45),
 710                      10 => array(0,30),
 711                      15 => array(0,30),
 712                      45 => array(0,15,30,45),
 713                  );
 714                  if (!isset($show[$this->granularity_m]) ? $t % 60 == 0 : in_array($t % 60,$show[$this->granularity_m]))
 715                  {
 716                      $time = $GLOBALS['egw']->common->formattime(sprintf('%02d',$t/60),sprintf('%02d',$t%60));
 717                  }
 718                  if ($add_links) $time = $this->add_link($time,$this->date,(int) ($t/60),$t%60);
 719                  $html .= $indent."\t\t".'<div class="calTimeRowTime">'.$time."</div>\n";
 720                  $html .= $indent."\t</div>\n";    // calTimeRow
 721                  $off = !$off;
 722              }
 723          }
 724          if (is_array($daysEvents) && count($daysEvents))
 725          {
 726              $numberOfDays    = count($daysEvents);
 727              $dayColWidth    = 100/$numberOfDays;
 728  
 729              $dayCols_width = $width - $this->timeRow_width - 1;
 730  
 731              $html .= $indent."\t".'<div id="calDayCols" class="calDayCols'.
 732                  ($this->use_time_grid ? ($this->bo->common_prefs['timeformat'] == 12 ? '12h' : '') : 'NoTime').'">'."\n";
 733  
 734              if ($this->html->user_agent == 'msie')    // necessary IE hack - stupid thing ...
 735              {
 736                  // Lars Kneschke 2005-08-28
 737                  // why do we use a div in a div which has the same height and width???
 738                  // To make IE6 happy!!! Without the second div you can't use 
 739                  // style="left: 50px; right: 0px;"
 740                  //$html .= '<div style="width=100%; height: 100%;">'."\n";
 741  
 742                  // Ralf Becker 2006-06-19
 743                  // Lars original typo "width=100%; height: 100%;" is important ;-) 
 744                  // means you width: 100% does NOT work, you need no width!
 745                  $html .= '<div style="height: 100%;">'."\n";
 746              }
 747              $dayCol_width = $dayCols_width / count($daysEvents);
 748              $n = 0;
 749              foreach($daysEvents as $day => $events)
 750              {
 751                  $short_title = count($daysEvents) > 1;
 752                  $col_owner = $owner;
 753                  if (!is_numeric($day))
 754                  {
 755                      $short_title = $day;
 756                      $day = $this->date;
 757                      $col_owner = $owner[$n];
 758                  }
 759                  $html .= $this->dayColWidget($day,$events,$n*$dayColWidth,
 760                      $dayColWidth,$indent."\t\t",$short_title,++$on_off & 1,$col_owner);
 761                  ++$n;
 762              }
 763              if ($this->html->user_agent == 'msie') $html .= "</div>\n";
 764  
 765              $html .= $indent."\t</div>\n";    // calDayCols
 766          }
 767          $html .= $indent."</div>\n";    // calTimeGrid
 768          
 769          if ($this->scroll_to_wdstart)
 770          {
 771              $html .= "<script>\n\tdocument.getElementById('$id').scrollIntoView();\n";
 772              if ($last)    // last timeGrid --> scroll whole document back up
 773              {
 774                  $html .= "\tdocument.getElementById('divMain').scrollIntoView();\n";
 775              }
 776              $html .= "</script>\n";
 777          }
 778          return $html;
 779      }
 780  
 781      /**
 782       * Creates (if necessary multiple) columns for the events of a day
 783       *
 784       * Uses the eventColWidget to display each column.
 785       *
 786       * @param string/int $day_ymd date as Ymd
 787       * @param array $events of events to show
 788       * @param int $left start of the widget
 789       * @param int $width width of the widget
 790       * @param string $indent string for correct indention
 791       * @param boolean/string $short_title=True should we add a label (weekday, day) with link to the day-view above each day or string with title
 792       * @param boolean $on_off=false start with row_on or row_off, default false=row_off
 793       * @param int $owner=0 if != 0 owner to add to the add-event link
 794       */
 795  	function dayColWidget($day_ymd,$events,$left,$width,$indent,$short_title=True,$on_off=False,$owner=0)
 796      {
 797          if ($this->debug > 1 || $this->debug==='dayColWidget') $this->bo->debug_message('uiviews::dayColWidget(%1,%2,left=%3,width=%4,)',False,$day_ymd,$events,$left,$width);
 798  
 799          $day_start = $this->bo->date2ts((string)$day_ymd);
 800          
 801          // if daylight saving is switched on or off, correct $day_start
 802          // gives correct times after 2am, times between 0am and 2am are wrong
 803          if(($daylight_diff = $day_start + 12*HOUR_s - ($this->bo->date2ts($day_ymd."T120000"))))
 804          {
 805              $day_start -= $daylight_diff;
 806          }
 807          // sorting the event into columns with none-overlapping events, the events are already sorted by start-time
 808          $eventCols = $col_ends = array();
 809          foreach($events as $event)
 810          {
 811              $event['multiday'] = False;
 812              $event['start_m'] = ($event['start'] - $day_start) / 60;
 813              if ($event['start_m'] < 0)
 814              {
 815                  $event['start_m'] = 0;
 816                  $event['multiday'] = True;
 817              }
 818              $event['end_m'] = ($event['end'] - $day_start) / 60;
 819              if ($event['end_m'] >= 24*60)
 820              {
 821                  $event['end_m'] = 24*60-1;
 822                  $event['multiday'] = True;
 823              }
 824              if ($this->use_time_grid)
 825              {
 826                  for($c = 0; $event['start_m'] < $col_ends[$c]; ++$c);
 827                  $col_ends[$c] = $event['end_m'];
 828              }
 829              else
 830              {
 831                  $c = 0;        // without grid we only use one column
 832              }
 833              $eventCols[$c][] = $event;
 834          }
 835  
 836          $html = $indent.'<div id="calColumn'.$this->calColumnCounter++.'" class="calDayCol" style="left: '.$left.
 837              '%; width: '.$width.'%;">'."\n";
 838  
 839          // Creation of the header-column with date, evtl. holiday-names and a matching background-color
 840          $ts = $this->bo->date2ts((string)$day_ymd);
 841          $title = !is_bool($short_title) ? $short_title :
 842              ($short_title ? lang(adodb_date('l',$ts)).' '.adodb_date('d.',$ts) : $this->bo->long_date($ts,0,false,true));
 843          $day_view = array(
 844              'menuaction' => 'calendar.uiviews.day',
 845              'date' => $day_ymd,
 846          );
 847          if ($short_title === true)
 848          {
 849              $title = $this->html->a_href($title,$day_view,'',
 850                  !isset($this->holidays[$day_ymd])?' title="'.lang('Dayview').'"':'');
 851          }
 852          elseif ($short_title === false)
 853          {
 854              // add arrows to go to the previous and next day (dayview only)
 855              $day_view['date'] = $this->bo->date2string($ts -= 12*HOUR_s);
 856              $title = $this->html->a_href($this->html->image('phpgwapi','left',$this->bo->long_date($ts)),$day_view).' &nbsp; '.$title;
 857              $day_view['date'] = $this->bo->date2string($ts += 48*HOUR_s);
 858              $title .= ' &nbsp; '.$this->html->a_href($this->html->image('phpgwapi','right',$this->bo->long_date($ts)),$day_view);
 859          }
 860          $this->_day_class_holiday($day_ymd,$class,$holidays);
 861          // the weekday and date
 862          $html .= $indent."\t".'<div style="height: '. $this->rowHeight .'%;" class="calDayColHeader '.$class.'"'.($holidays ? ' title="'.$holidays.'"':'').'>'.
 863              $title.(!$short_title && $holidays ? ': '.$holidays : '')."</div>\n";
 864  
 865          if ($this->use_time_grid)
 866          {
 867              // adding divs to click on for each row / time-span
 868              for($t = $this->scroll_to_wdstart ? 0 : $this->wd_start,$i = 1+$this->extraRows;
 869                  $t <= $this->wd_end || $this->scroll_to_wdstart && $t < 24*60;
 870                  $t += $this->granularity_m,++$i)
 871              {
 872                  $linkData = array(
 873                      'menuaction'    =>'calendar.uiforms.edit',
 874                      'date'        => $day_ymd,
 875                      'hour'        => floor($t / 60),
 876                      'minute'    => floor($t % 60),
 877                  );
 878                  if ($owner) $linkData['owner'] = $owner;
 879                  
 880                  $html .= $indent."\t".'<div style="height:'. $this->rowHeight .'%; top: '. $i*$this->rowHeight .
 881                      '%;" class="calAddEvent" onclick="'.$this->popup($GLOBALS['egw']->link('/index.php',$linkData)).';return false;"></div>'."\n";
 882              }
 883          }
 884          // displaying all event columns of the day
 885          foreach($eventCols as $n => $eventCol)
 886          {
 887              $html .= $this->eventColWidget($eventCol,!$n ? 0 : 60-10*(count($eventCols)-$n),
 888                  count($eventCols) == 1 ? 100 : (!$n ? 80 : 50),$indent."\t");
 889          }
 890          $html .= $indent."</div>\n";    // calDayCol
 891  
 892          return $html;
 893      }
 894      
 895      /**
 896       * get the CSS class and holidays for a given day
 897       *
 898       * @param string $day_ymd date
 899       * @param string &$class class to use
 900       * @param string &$holidays commaseparted holidays or empty if none
 901       * @param boolean $only_weekend=false show only the weekend in header-color, otherwise every second days is shown too
 902       */
 903  	function _day_class_holiday($day_ymd,&$class,&$holidays,$only_weekend=false)
 904      {
 905          $class = $holidays = '';
 906          $bday = false;
 907          if (isset($this->holidays[$day_ymd]))
 908          {
 909              foreach($this->holidays[$day_ymd] as $holiday)
 910              {
 911                  if (isset($holiday['birthyear']))
 912                  {
 913                      $bday = true;
 914                  }
 915                  else
 916                  {
 917                      $class = 'calHoliday';
 918                  }
 919                  $holidays[] = $holiday['name'];
 920              }
 921              $holidays = implode(', ',$holidays);
 922          }
 923          if (!$class)
 924          {
 925              if ($day_ymd == $this->bo->date2string($this->bo->now_su))
 926              {
 927                  $class = 'calToday';
 928              }
 929              else
 930              {
 931                  $day = (int) date('w',$this->bo->date2ts((string) $day_ymd));
 932      
 933                  if ($only_weekend)
 934                  {
 935                      $class = $day == 0 || $day == 6 ? 'th' : 'row_off';
 936                  }
 937                  else
 938                  {
 939                      $class = $day & 1 ? 'row_on' : 'th';
 940                  }
 941              }
 942          }
 943          if ($bday) $class .= ' calBirthday';
 944      }
 945  
 946      /**
 947       * Creates colunm for non-overlaping (!) events
 948       *
 949       * Uses the eventWidget to display each event.
 950       *
 951       * @param array $events of events to show
 952       * @param int $left start of the widget
 953       * @param int $width width of the widget
 954       * @param string $indent string for correct indention
 955       */
 956  	function eventColWidget($events,$left,$width,$indent)
 957      {
 958          if ($this->debug > 1 || $this->debug==='eventColWidget') $this->bo->debug_message('uiviews::eventColWidget(%1,left=%2,width=%3,)',False,$events,$left,$width);
 959  
 960          $html = $indent.'<div class="calEventCol" style="left: '.$left.'%; width:'.$width.'%;'.
 961              (!$this->use_time_grid ? ' top: '.$this->rowHeight.'%;' : '').'">'."\n";
 962          foreach($events as $event)
 963          {
 964              $html .= $this->eventWidget($event,$width,$indent."\t");
 965          }
 966          $html .= $indent."</div>\n";
 967  
 968          return $html;
 969      }
 970  
 971      /**
 972       * Shows one event
 973       *
 974       * The display of the event and it's tooltip is done via the event_widget.tpl template
 975       *
 976       * @param $event array with the data of event to show
 977       * @param $width int width of the widget
 978       * @param string $indent string for correct indention
 979       * @param boolean $return_array=false should an array with keys(tooltip,popup,html) be returned or the complete widget as string
 980       * @param string $block='event_widget' template used the render the widget
 981       * @return string/array 
 982       */
 983  	function eventWidget($event,$width,$indent,$return_array=false,$block='event_widget')
 984      {
 985          if ($this->debug > 1 || $this->debug==='eventWidget') $this->bo->debug_message('uiviews::eventWidget(%1,width=%2)',False,$event,$width);
 986  
 987          static $tpl = False;
 988          if (!$tpl)
 989          {
 990              $tpl = $GLOBALS['egw']->template;
 991              $tpl->set_root($GLOBALS['egw']->common->get_tpl_dir('calendar'));
 992              $tpl->set_file('event_widget_t','event_widget.tpl');
 993              $tpl->set_block('event_widget_t','event_widget');
 994              $tpl->set_block('event_widget_t','event_tooltip');
 995              $tpl->set_block('event_widget_t','planner_event');
 996          }
 997          if (($return_array || $event['start_m'] == 0) && $event['end_m'] >= 24*60-1)
 998          {
 999              if ($return_array && $event['end_m'] > 24*60)
1000              {
1001                  $timespan = $this->bo->format_date($event['start'],false).' - '.$this->bo->format_date($event['end']);
1002              }
1003              else
1004              {
1005                  $timespan = lang('all day');
1006              }
1007          }
1008          else
1009          {
1010              $timespan = $this->bo->timespan($event['start_m'],$event['end_m']);
1011          }
1012          $is_private = !$this->bo->check_perms(EGW_ACL_READ,$event);
1013  
1014          $icons = !$is_private ? $this->event_icons($event) : array($this->html->image('calendar','private',lang('private')));
1015          $cats  = $this->bo->categories($event['category'],$color);
1016  
1017          // these values control varius aspects of the geometry of the eventWidget
1018          $small_trigger_width = 120 + 20*count($icons);
1019          $corner_radius=$width > $small_trigger_width ? 10 : 5;
1020          $header_height=$width > $small_trigger_width ? 19 : 12;    // multi_3 icon has a height of 19=16+2*1padding+1border !
1021          if (!$return_array) $height = $this->times2height($event['start_m'],$event['end_m'],$header_height);
1022          //$body_height = max(0,$height - $header_height - $corner_radius);
1023          $border=1;
1024          $headerbgcolor = $color ? $color : '#808080';
1025          // the body-colors (gradient) are calculated from the headercolor, which depends on the cat of an event
1026          $bodybgcolor1 = $this->brighter($headerbgcolor,$headerbgcolor == '#808080' ? 100 : 170);
1027          $bodybgcolor2 = $this->brighter($headerbgcolor,220);
1028          
1029          // seperate each participant types
1030          $part_array = array();
1031          foreach($this->bo->participants($event) as $part_key => $participant)
1032          {
1033              if(is_numeric($part_key))
1034              {
1035                  $part_array[lang('Participants')][$part_key] = $participant;
1036              }
1037              elseif(isset($this->bo->resources[$part_key{0}]))
1038              {
1039                   $part_array[((isset($this->bo->resources[$part_key{0}]['participants_header'])) ? $this->bo->resources[$part_key{0}]['participants_header'] : lang($this->bo->resources[$part_key{0}]['app']))][$part_key] = $participant;
1040              }
1041          }
1042          foreach($part_array as $part_group => $participant)
1043          {
1044              $participants .= $this->add_nonempty($participant,$part_group,True);
1045          }
1046          // as we only deal with percentual widht, we consider only the full dayview (1 colum) as NOT small
1047          $small = $this->view != 'day' || $width < 50;
1048          // $small = $width <= $small_trigger_width
1049  
1050          $small_height = $this->use_time_grid && ( $event['end_m']-$event['start_m'] < 2*$this->granularity_m || 
1051              $event['end_m'] <= $this->wd_start || $event['start_m'] >= $this->wd_end);
1052  
1053          $tpl->set_var(array(
1054              // event-content, some of it displays only if it really has content or is needed
1055              'header_icons' => $small ? '' : implode("",$icons),
1056              'body_icons' => $small ? implode("\n",$icons) : '',
1057              'icons' => implode('',$icons),
1058              'timespan' => $timespan,
1059              'title' => ($title = !$is_private ? $this->html->htmlspecialchars($event['title']) : lang('private')),
1060              'header' => $small_height ? $title : $timespan,
1061              'description' => !$is_private ? nl2br($this->html->htmlspecialchars($event['description'])) : '',
1062              'location'   => !$is_private ? $this->add_nonempty($event['location'],lang('Location')) : '',
1063              'participants' => $participants,
1064              'times' => !$event['multiday'] ? $this->add_nonempty($this->bo->timespan($event['start_m'],$event['end_m'],true),lang('Time')) :
1065                  $this->add_nonempty($this->bo->format_date($event['start']),lang('Start')).
1066                  $this->add_nonempty($this->bo->format_date($event['end']),lang('End')),
1067              'multidaytimes' => !$event['multiday'] ? '' :
1068                  $this->add_nonempty($this->bo->format_date($event['start']),lang('Start')).
1069                  $this->add_nonempty($this->bo->format_date($event['end']),lang('End')),
1070              'category' => !$is_private ? $this->add_nonempty($cats,lang('Category')) : '',
1071              // the tooltip is based on the content of the actual widget, this way it takes no extra bandwidth/volum
1072  //            'tooltip' => $this->html->tooltip(False,False,array('BorderWidth'=>0,'Padding'=>0)),
1073              // various aspects of the geometry or style
1074              'corner_radius'  => $corner_radius.'px',
1075              'header_height' => $header_height.'px',
1076              //'body_height' => $body_height.'px',
1077              'height' => $height,
1078              'width' => ($width-20).'px',
1079              'border' => $border,
1080              'bordercolor' => $headerbgcolor,
1081              'headerbgcolor' => $headerbgcolor,
1082              'bodybackground' => ($background = 'url('.$GLOBALS['egw_info']['server']['webserver_url'].
1083                  '/calendar/inc/gradient.php?color1='.urlencode($bodybgcolor1).'&color2='.urlencode($bodybgcolor2).
1084                  '&width='.$width.') repeat-y '.$bodybgcolor2),
1085              'Small' => $small ? 'Small' : '',    // to use in css class-names
1086              'indent' => $indent."\t",
1087          ));
1088  /* not used at the moment
1089          foreach(array(
1090              'upper_left'=>array('width'=>-$corner_radius,'height'=>$header_height,'border'=>0,'bgcolor'=>$headerbgcolor),
1091              'upper_right'=>array('width'=>$corner_radius,'height'=>$header_height,'border'=>0,'bgcolor'=>$headerbgcolor),
1092              'lower_left'=>array('width'=>-$corner_radius,'height'=>-$corner_radius,'border'=>$border,'color'=>$headerbgcolor,'bgcolor'=>$bodybgcolor1),
1093              'lower_right'=>array('width'=>$corner_radius,'height'=>-$corner_radius,'border'=>$border,'color'=>$headerbgcolor,'bgcolor'=>$bodybgcolor2),
1094          ) as $name => $data)
1095          {
1096              $tpl->set_var($name.'_corner',$GLOBALS['egw_info']['server']['webserver_url'].
1097                  '/calendar/inc/round_corners.php?width='.$data['width'].'&height='.$data['height'].
1098                  '&bgcolor='.urlencode($data['bgcolor']).
1099                  (isset($data['color']) ? '&color='.urlencode($data['color']) : '').
1100                  (isset($data['border']) ? '&border='.urlencode($data['border']) : ''));
1101          }
1102  */
1103          $tooltip = $tpl->fp('tooltip','event_tooltip');
1104          $tpl->set_var('tooltip',$this->html->tooltip($tooltip,False,array('BorderWidth'=>0,'Padding'=>0)));
1105          $html = $tpl->fp('out',$block);
1106  
1107          $view_link = $GLOBALS['egw']->link('/index.php',array('menuaction'=>'calendar.uiforms.view','cal_id'=>$event['id'],'date'=>$this->bo->date2string($event['start'])));
1108          $popup = $is_private ? '' : ' onclick="'.$this->popup($view_link).'; return false;"';
1109          
1110          if ($return_array)
1111          {
1112              return array(
1113                  'tooltip' => $tooltip,
1114                  'popup'   => $popup,
1115                  'html'    => $html,
1116                  'private' => $is_private,
1117                  'color'   => $color,
1118              );
1119          }
1120          $ie_fix = '';
1121          if ($this->html->user_agent == 'msie')    // add a transparent image to make the event "opaque" to mouse events
1122          {
1123              $ie_fix = $indent."\t".$this->html->image('calendar','transparent.gif','',
1124                  $this->html->tooltip($tooltip,False,array('BorderWidth'=>0,'Padding'=>0)).
1125                  ' style="top:0px; left:0px; position:absolute; height:100%; width:100%; z-index:1"') . "\n";
1126          }
1127          if ($this->use_time_grid)
1128          {
1129              $style = 'top: '.$this->time2pos($event['start_m']).'%; height: '.$height.'%;';
1130          }
1131          else
1132          {
1133              $style = 'position: relative; margin-top: 3px;';
1134          }
1135          return $indent.'<div class="calEvent'.($is_private ? 'Private' : '').
1136              '" style="'.$style.' border-color: '.$headerbgcolor.'; background: '.$background.';"'.
1137              $popup.' '.$this->html->tooltip($tooltip,False,array('BorderWidth'=>0,'Padding'=>0)).
1138              '>'."\n".$ie_fix.$html.$indent."</div>\n";
1139      }
1140  
1141  	function add_nonempty($content,$label,$one_per_line=False)
1142      {
1143          if (is_array($content))
1144          {
1145              $content = implode($one_per_line ? ",\n" : ', ',$content);
1146          }
1147          if (!empty($content))
1148          {
1149              return '<span class="calEventLabel">'.$label.'</span>:'.
1150                  ($one_per_line ? '<br>' : ' ').
1151                  nl2br($this->html->htmlspecialchars($content)).'<br>';
1152          }
1153          return '';
1154      }
1155  
1156      /**
1157      * Calculates a brighter color for a given color
1158      *
1159      * @param $rgb string color as #rrggbb value
1160      * @param $decr int value to add to each component, default 64
1161      * @return string the brighter color
1162      */
1163  	function brighter($rgb,$decr=64)
1164      {
1165          if (!preg_match('/^#?([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/',$rgb,$components))
1166          {
1167              return '#ffffff';
1168          }
1169          $brighter = '#';
1170          for ($i = 1; $i <=3; ++$i)
1171          {
1172              $val = hexdec($components[$i]) + $decr;
1173              if ($val > 255) $val = 255;
1174              $brighter .= sprintf('%02x',$val);
1175          }
1176          //echo "brighter($rgb=".print_r($components,True).")=$brighter</p>\n";
1177          return $brighter;
1178      }
1179      
1180      
1181      /**
1182       * Creates a planner view: grid with columns for the time and rows for categories or users
1183       *
1184       * Uses the plannerRowWidget to display rows
1185       *
1186       * @param array $events events to show
1187       * @param mixed $start start-time of the grid
1188       * @param mixed $end end-time of the grid
1189       * @param boolean/int $by_cat rows by sub-categories of $by_cat (cat_id or 0 for upmost level) or by users (false)
1190       * @param string $indent='' string for correct indention
1191       * @return string with widget
1192       */
1193      function &plannerWidget($events,$start,$end,$by_cat=0,$indent='')
1194      {
1195          $content = $indent.'<div class="plannerWidget">'."\n";
1196          
1197          // display the header, containing a headerTitle and multiple headerRows with the scales
1198          $content .= $indent."\t".'<div class="plannerHeader">'."\n";
1199          // display the headerTitle
1200          $title = $by_cat === false ? lang('User') : lang('Category');
1201          $content .= $indent."\t\t".'<div class="plannerHeaderTitle th">'.$title."</div>\n";
1202          
1203          // display the headerRows with the scales
1204          $content .= $indent."\t\t".'<div class="plannerHeaderRows">'."\n";
1205          // set start & end to timestamp and first & last to timestamp of 12h midday, to avoid trouble with daylight saving
1206          foreach(array('start' => 'first','end' => 'last') as $t => $v)
1207          {
1208              $$t = $this->bo->date2ts($$t);
1209              $$v = $this->bo->date2array($$t);
1210              unset(${$v}['raw']);
1211              ${$v}['hour'] = 12;
1212              ${$v}['minute'] = ${$v}['second'] = 0;
1213              ${$v} = $this->bo->date2ts($$v);
1214          }
1215          $days = 1 + (int) round(($last - $first) / DAY_s);    // we have to use round to get the right number if daylight saving changes
1216          if ($days >= 28)    // display the month scale
1217          {
1218              $content .= $this->plannerMonthScale($first,$days,$indent."\t\t\t");
1219          }
1220          if ($days >= 5)    // display the week scale
1221          {
1222              $content .= $this->plannerWeekScale($first,$days,$indent."\t\t\t");
1223          }
1224          $content .= $this->plannerDayScale($first,$days,$indent."\t\t\t");        // day-scale, always displayed
1225          if ($days <= 7)    // display the hour scale
1226          {
1227              $content .= $this->plannerHourScale($start,$days,$indent."\t\t\t");
1228          }
1229          $content .= $indent."\t\t</div>\n";    // end of the plannerHeaderRows
1230          $content .= $indent."\t</div>\n";    // end of the plannerHeader
1231          
1232          // sort the events after user or category
1233          $rows = $sort2label = array();
1234          if ($by_cat === false)    // planner by user
1235          {
1236              $sort2label = $this->_get_planner_users();
1237          }
1238          foreach($events as $key => $event)
1239          {
1240              if ($by_cat === false)    // planner by user
1241              {
1242                  foreach($event['participants'] as $sort => $status)
1243                  {
1244                      // only show if participant has not rejected or user wants to see rejections
1245                      if (isset($sort2label[$sort]) && ($status != 'R' || $this->bo->cal_prefs['show_rejected']))
1246                      {
1247                          $rows[$sort][] =& $events[$key];
1248                      }
1249                  }
1250              }
1251              else    // planner by cat
1252              {
1253                  foreach($this->_get_planner_cats($event['category'],$sort2label,$sort2color) as $sort)
1254                  {
1255                      if (!is_array($rows[$sort])) $rows[$sort] = array();
1256  
1257                      $rows[$sort][] =& $events[$key];
1258                  }
1259              }
1260          }
1261          // display a plannerRowWidget for each row (user or category)
1262          foreach($sort2label as $sort => $label)
1263          {
1264              if (!isset($rows[$sort])) continue;        // dont show empty categories (user-rows get all initialised
1265  
1266              $class = $class == 'row_on' ? 'row_off' : 'row_on';
1267              $content .= $this->plannerRowWidget(isset($rows[$sort]) ? $rows[$sort] : array(),$start,$end,$label,$class,$indent."\t");
1268          }
1269          $content .= $indent."</div>\n";        // end of the plannerWidget
1270          
1271          return $content;
1272      }
1273      
1274      /**
1275       * get all users to display in the planner_by_user
1276       *
1277       * @param boolean $enum_groups=true should groups be returned as there members (eg. planner) or not (day & week)
1278       * @return array with uid => label pairs, first all users alphabetically sorted, then all resources
1279       */
1280  	function _get_planner_users($enum_groups=true)
1281      {
1282          $users = $resources = array();
1283          foreach(explode(',',$this->owner) as $user)
1284          {
1285              if (!is_numeric($user))        // resources
1286              {
1287                  $resources[$user] = $this->bo->participant_name($user);
1288              }
1289              elseif ($enum_groups && $GLOBALS['egw']->accounts->get_type($user) == 'g')    // groups
1290              {
1291                  foreach((array) $GLOBALS['egw']->accounts->member($user) as $data)
1292                  {
1293                      $user = $data['account_id'];
1294                      if ($this->bo->check_perms(EGW_ACL_READ,0,$user))
1295                      {
1296                          $users[$user] = $this->bo->participant_name($user);
1297                      }
1298                  }
1299              }
1300              else    // users
1301              {
1302                  $users[$user] = $this->bo->participant_name($user);
1303              }
1304          }
1305          asort($users);
1306          asort($resources);
1307          
1308          return $users+$resources;
1309      }
1310      
1311      /**
1312       * get all categories used as sort criteria for the planner by category
1313       * 
1314       * the returned cat is as direct sub-category of $this->cat_id or a main (level 1) category if !$this->cat_id
1315       *
1316       * @param string $cats comma-delimited cat_id's or empty for no cat
1317       * @param array &$sort2label labels for the returned cats
1318       * @return array with cat_id's
1319       */
1320  	function _get_planner_cats($cats,&$sort2label)
1321      {
1322          static $cat2sort;
1323          
1324          if (!is_array($cat2sort))
1325          {
1326              $cat2sort = array();
1327              foreach((array)$this->cats->return_array('all',0,false,'','','',true) as $data)
1328              {
1329                  if ($data['parent'] == $this->cat_id || $data['id'] == $this->cat_id)    // cat is a direct sub of $this->cat_id
1330                  {
1331                      $cat2sort[$data['id']] = $data['id'];
1332                      $sort2label[$data['id']] = stripslashes($data['name']);
1333                  }
1334                  elseif(isset($cat2sort[$data['parent']]))    // parent is already in the array => add us with same target
1335                  {
1336                      $cat2sort[$data['id']] = $cat2sort[$data['parent']];
1337                  } 
1338              }
1339          }
1340          $ret = array();
1341          foreach(!is_array($cats) ? explode(',',$cats) : $cats as $cat)
1342          {
1343              if (isset($cat2sort[$cat]) && !in_array($cat2sort[$cat],$ret))
1344              {
1345                  $ret[] = $cat2sort[$cat];
1346              }
1347          }
1348          if (!count($ret))
1349          {
1350              $sort2label[0] = lang('none');
1351              $ret[] = 0;
1352          }
1353          //echo "<p>uiviews::_get_planner_cats($cats=".$this->cats->id2name($cats).") (this->cat_id=$this->cat_id) = ".print_r($ret,true).'='.$this->cats->id2name($ret[0])."</p>\n";
1354          return $ret;
1355      }
1356  
1357      /**
1358       * Creates month scale for the planner
1359       *
1360       * @param int $start start-time (12h) of the scale
1361       * @param int $days number of days to display
1362       * @param string $indent='' string for correct indention
1363       * @return string with scale
1364       */
1365  	function plannerMonthScale($start,$days,$indent)
1366      {
1367          $day_width = round(100 / $days,2);
1368  
1369          $content .= $indent.'<div class="plannerScale">'."\n";
1370          for($t = $start,$left = 0,$i = 0; $i < $days; $t += $days_in_month*DAY_s,$left += $days_in_month*$day_width,$i += $days_in_month)
1371          {
1372              $t_arr = $this->bo->date2array($t);
1373              unset($t_arr['raw']);    // force recalculation
1374              unset($t_arr['full']);
1375              $days_in_month = $this->datetime->days_in_month($t_arr['month'],$t_arr['year']) - ($t_arr['day']-1);
1376              if ($i + $days_in_month > $days)
1377              {
1378                  $days_in_month = $days - $i;
1379              }
1380              if ($days_in_month > 10)
1381              {
1382                  $title = lang(date('F',$t)).' '.$t_arr['year'];
1383                  // previous links
1384                  $prev = $t_arr;
1385                  $prev['day'] = 1;
1386                  if ($prev['month']-- <= 1)
1387                  {
1388                      $prev['month'] = 12;
1389                      $prev['year']--;
1390                  }
1391                  if ($this->bo->date2ts($prev) < $start-20*DAY_s)
1392                  {
1393                      $prev['day'] = $this->day;
1394                      $full = $this->bo->date2string($prev);
1395                      if ($this->day >= 15) $prev = $t_arr;        // we stay in the same month
1396                      $prev['day'] = $this->day < 15 ? 15 : 1;
1397                      $half = $this->bo->date2string($prev);
1398                      $title = $this->html->a_href($this->html->image('phpgwpai','first',lang('back one month'),$options=' alt="<<"'),array(
1399                          'menuaction' => $this->view_menuaction,
1400                          'date'       => $full,
1401                      )) . ' &nbsp; '.
1402                      $this->html->a_href($this->html->image('phpgwpai','left',lang('back half a month'),$options=' alt="<"'),array(
1403                          'menuaction' => $this->view_menuaction,
1404                          'date'       => $half,
1405                      )) . ' &nbsp; '.$title;
1406                  }
1407                  // next links
1408                  $next = $t_arr;
1409                  if ($next['month']++ >= 12)
1410                  {
1411                      $next['month'] = 1;
1412                      $next['year']++;
1413                  }
1414                  // dont show next scales, if there are more then 10 days in the next month or there is no next month
1415                  $days_in_next_month = (int) date('d',$end = $start+$days*DAY_s);
1416                  if ($days_in_next_month <= 10 || date('m',$end) == date('m',$t))
1417                  {
1418                      if ($this->day >= 15) $next = $t_arr;        // we stay in the same month
1419                      $next['day'] = $this->day;
1420                      $full = $this->bo->date2string($next);
1421                      if ($this->day < 15) $next = $t_arr;        // we stay in the same month
1422                      $next['day'] = $this->day < 15 ? 15 : 1;
1423                      $half = $this->bo->date2string($next);
1424                      $title .= ' &nbsp; '.$this->html->a_href($this->html->image('phpgwpai','right',lang('forward half a month'),$options=' alt=">>"'),array(
1425                          'menuaction' => $this->view_menuaction,
1426                          'date'       => $half,
1427                      )). ' &nbsp; '.
1428                      $this->html->a_href($this->html->image('phpgwpai','last',lang('forward one month'),$options=' alt=">>"'),array(
1429                          'menuaction' => $this->view_menuaction,
1430                          'date'       => $full,
1431                      ));
1432                  }
1433              }
1434              else
1435              {
1436                  $title = '&nbsp;';
1437              }
1438              $class = $class == 'row_on' ? 'th' : 'row_on';
1439              $content .= $indent."\t".'<div class="plannerMonthScale '.$class.'" style="left: '.$left.'%; width: '.($day_width*$days_in_month).'%;">'.
1440                  $title."</div>\n";
1441          }
1442          $content .= $indent."</div>\n";        // end of plannerScale
1443  
1444          return $content;
1445      }
1446      
1447      /**
1448       * Creates a week scale for the planner
1449       *
1450       * @param int $start start-time (12h) of the scale
1451       * @param int $days number of days to display
1452       * @param string $indent='' string for correct indention
1453       * @return string with scale
1454       */
1455  	function plannerWeekScale($start,$days,$indent)
1456      {
1457          $week_width = round(100 / $days * ($days <= 7 ? $days : 7),2);
1458  
1459          $content .= $indent.'<div class="plannerScale">'."\n";
1460          for($t = $start,$left = 0,$i = 0; $i < $days; $t += 7*DAY_s,$left += $week_width,$i += 7)
1461          {
1462              $title = lang('Week').' '.date('W',$t);
1463              if ($days > 7)
1464              {
1465                  $title = $this->html->a_href($title,array(
1466                      'menuaction' => 'calendar.uiviews.planner',
1467                      'planner_days' => 7,
1468                      'date'       => date('Ymd',$t),
1469                  ),false,' title="'.$this->html->htmlspecialchars(lang('Weekview')).'"');
1470              }
1471              else
1472              {
1473                  // prev. week
1474                  $title = $this->html->a_href($this->html->image('phpgwpai','first',lang('previous'),$options=' alt="<<"'),array(
1475                      'menuaction' => $this->view_menuaction,
1476                      'date'       => date('Ymd',$t-7*DAY_s),
1477                  )) . ' &nbsp; <b>'.$title;
1478                  // next week
1479                  $title .= '</b> &nbsp; '.$this->html->a_href($this->html->image('phpgwpai','last',lang('next'),$options=' alt=">>"'),array(
1480                      'menuaction' => $this->view_menuaction,
1481                      'date'       => date('Ymd',$t+7*DAY_s),
1482                  ));
1483              }
1484              $class = $class == 'row_on' ? 'th' : 'row_on';
1485              $content .= $indent."\t".'<div class="plannerWeekScale '.$class.'" style="left: '.$left.'%; width: '.$week_width.'%;">'.$title."</div>\n";
1486          }
1487          $content .= $indent."</div>\n";        // end of plannerScale
1488  
1489          return $content;
1490      }
1491      
1492      /**
1493       * Creates day scale for the planner
1494       *
1495       * @param int $start start-time (12h) of the scale
1496       * @param int $days number of days to display
1497       * @param string $indent='' string for correct indention
1498       * @return string with scale
1499       */
1500  	function plannerDayScale($start,$days,$indent)
1501      {
1502          $day_width = round(100 / $days,2);
1503  
1504          $content .= $indent.'<div class="plannerScale'.($days > 3 ? 'Day' : '').'">'."\n";
1505          for($t = $start,$left = 0,$i = 0; $i < $days; $t += DAY_s,$left += $day_width,++$i)
1506          {
1507              $this->_day_class_holiday($this->bo->date2string($t),$class,$holidays,$days > 7);
1508  
1509              if ($days <= 3)
1510              {
1511                  $title = '<b>'.lang(date('l',$t)).', '.date('j',$t).'. '.lang(date('F',$t)).'</b>';
1512              }
1513              elseif ($days <= 7)
1514              {
1515                  $title = lang(date('l',$t)).'<br />'.date('j',$t).'. '.lang(date('F',$t));
1516              }
1517              else
1518              {
1519                  $title = substr(lang(date('D',$t)),0,2).'<br />'.date('j',$t);    
1520              }
1521              if ($days > 1)
1522              {
1523                  $title = $this->html->a_href($title,array(
1524                      'menuaction'   => 'calendar.uiviews.planner',
1525                      'planner_days' => 1,
1526                      'date'         => date('Ymd',$t),
1527                  ),false,strstr($class,'calHoliday') || strstr($class,'calBirthday') ? '' : ' title="'.$this->html->htmlspecialchars(lang('Dayview')).'"');
1528              }
1529              if ($days < 5)
1530              {
1531                  if (!$i)    // prev. day only for the first day
1532                  {
1533                      $title = $this->html->a_href($this->html->image('phpgwpai','first',lang('previous'),$options=' alt="<<"'),array(
1534                          'menuaction' => $this->view_menuaction,
1535                          'date'       => date('Ymd',$start-DAY_s),
1536                      )) . ' &nbsp; '.$title;
1537                  }
1538                  if ($i == $days-1)    // next day only for the last day
1539                  {
1540                      $title .= ' &nbsp; '.$this->html->a_href($this->html->image('phpgwpai','last',lang('next'),$options=' alt=">>"'),array(
1541                          'menuaction' => $this->view_menuaction,
1542                          'date'       => date('Ymd',$start+DAY_s),
1543                      ));
1544                  }
1545              }
1546              $content .= $indent."\t".'<div class="plannerDayScale '.$class.'" style="left: '.$left.'%; width: '.$day_width.'%;"'.
1547                  ($holidays ? ' title="'.$this->html->htmlspecialchars($holidays).'"' : '').'>'.$title."</div>\n";
1548          }
1549          $content .= $indent."</div>\n";        // end of plannerScale
1550  
1551          return $content;
1552      }
1553      
1554      /**
1555       * Creates hour scale for the planner
1556       *
1557       * @param int $start start-time (12h) of the scale
1558       * @param int $days number of days to display
1559       * @param string $indent='' string for correct indention
1560       * @return string with scale
1561       */
1562  	function plannerHourScale($start,$days,$indent)
1563      {
1564          foreach(array(1,2,3,4,6,8,12) as $d)    // numbers dividing 24 without rest
1565          {
1566              if ($d > $days) break;
1567              $decr = $d;
1568          }
1569          $hours = $days * 24;
1570          if ($days == 1)            // for a single day we calculate the hours of a days, to take into account daylight saving changes (23 or 25 hours)
1571          {
1572              $t_arr = $this->bo->date2array($start);
1573              unset($t_arr['raw']);
1574              $t_arr['hour'] = $t_arr['minute'] = $t_arr['second'] = 0;
1575              $s = $this->bo->date2ts($t_arr);
1576              $t_arr['hour'] = 23; $t_arr['minute'] = $t_arr['second'] = 59;
1577              $hours = ($this->bo->date2ts($t_arr) - $s) / HOUR_s;
1578          }
1579          $cell_width = round(100 / $hours * $decr,2);
1580          
1581          $content .= $indent.'<div class="plannerScale">'."\n";
1582          for($t = $start,$left = 0,$i = 0; $i < $hours; $t += $decr*HOUR_s,$left += $cell_width,$i += $decr)
1583          {
1584              $title = date($this->cal_prefs['timeformat'] == 12 ? 'ha' : 'H',$t);
1585  
1586              $class = $class == 'row_on' ? 'th' : 'row_on';
1587              $content .= $indent."\t".'<div class="plannerHourScale '.$class.'" style="left: '.$left.'%; width: '.($cell_width).'%;">'.$title."</div>\n";
1588          }
1589          $content .= $indent."</div>\n";        // end of plannerScale
1590  
1591          return $content;
1592      }
1593      
1594      /**
1595       * Creates a row for one user or category, with a header (user or category name) and (multiple) rows with non-overlapping events
1596       *
1597       * Uses the eventRowWidget to display a row of non-overlapping events
1598       *
1599       * @param array $events to show
1600       * @param int $start start-time of the row
1601       * @param int $end end-time of the row
1602       * @param string $header user or category name for the row-header
1603       * @param string $class additional css class for the row
1604       * @param string $indent='' string for correct indention
1605       * @return string with widget
1606       */
1607  	function plannerRowWidget($events,$start,$end,$header,$class,$indent='')
1608      {
1609          $content = $indent.'<div class="plannerRowWidget '.$class.'">'."\n";
1610  
1611          // display the row-header
1612          $content .= $indent."\t".'<div class="plannerRowHeader">'.$header."</div>\n";
1613          
1614          // sorting the events in non-overlapping rows
1615          $rows = array(array());
1616          $row_end = array();
1617          foreach($events as $n => $event)
1618          {
1619              for($row = 0; (int) $row_end[$row] > $event['start']; ++$row);    // find a "free" row (no other event)
1620              $rows[$row][] =& $events[$n];
1621              $row_end[$row] = $event['end'];
1622          }
1623          //echo $header; _debug_array($rows);
1624          // display the rows
1625          $content .= $indent."\t".'<div class="eventRows">'."\n";
1626          foreach($rows as $row)
1627          {
1628              $content .= $this->eventRowWidget($row,$start,$end,$indent."\t\t");
1629          }
1630          $content .= $indent."\t</div>\n";    // end of the eventRows
1631  
1632          $content .= $indent."</div>\n";        // end of the plannerRowWidget
1633          
1634          return $content;
1635      }
1636  
1637      /**
1638       * Creates a row with non-overlapping events
1639       *
1640       * Uses the plannerEventWidget to display the events
1641       *
1642       * @param array $events non-overlapping events to show
1643       * @param int $start start-time of the row
1644       * @param int $end end-time of the row
1645       * @param string $indent='' string for correct indention
1646       * @return string with widget
1647       */
1648  	function eventRowWidget($events,$start,$end,$indent='')
1649      {
1650          $content = $indent.'<div class="eventRowWidget">'."\n";
1651          
1652          foreach($events as $event)
1653          {
1654              $content .= $this->plannerEventWidget($event,$start,$end,$indent."\t");
1655          }
1656          $content .= $indent."</div>\n";
1657          
1658          return $content;
1659      }
1660      
1661      /**
1662       * Calculate a time-dependent position in the planner
1663       *
1664       * We use a non-linear scale in the planner monthview, which shows the workday start or end
1665       * as start or end of the whole day. This improves the resolution a bit.
1666       *
1667       * @param int $time
1668       * @param int $start start-time of the planner
1669       * @param int $end end-time of the planner
1670       * @return float percentage position between 0-100
1671       */
1672  	function _planner_pos($time,$start,$end)
1673      {
1674          if ($time <= $start) return 0;    // we are left of our scale
1675          if ($time >= $end) return 100;    // we are right of our scale
1676          
1677          if ($this->planner_days)
1678          {
1679              $percent = ($time - $start) / ($end - $start);
1680          }
1681          else    // monthview
1682          {
1683              $t_arr = $this->bo->date2array($time);
1684              $day_start = $this->bo->date2ts((string)$t_arr['full']);
1685              $percent = ($day_start - $start) / ($end - $start);
1686      
1687              $time_of_day = 60 * $t_arr['hour'] + $t_arr['minute'];
1688              if ($time_of_day >= $this->wd_start)
1689              {
1690                  if ($time_of_day > $this->wd_end)
1691                  {
1692                      $day_percentage = 1;
1693                  }
1694                  else
1695                  {
1696                      $day_percentage = ($time_of_day-$this->wd_start) / ($this->wd_end - $this->wd_start);        // between 0 and 1
1697                  }
1698                  $days = ($end - $start) / DAY_s;
1699                  $percent += $day_percentage / $days;
1700              }
1701          }
1702          $percent = round(100 * $percent,2);
1703          
1704          //echo "<p>_planner_pos(".date('Y-m-d H:i',$time).', '.date('Y-m-d H:i',$start).', '.date('Y-m-d H:i',$end).") = $percent</p>\n";
1705          return $percent;
1706      }
1707  
1708      /**
1709       * Displays one event for the planner, using the eventWidget of the other views
1710       *
1711       * @param array $event
1712       * @param int $start start-time of the planner
1713       * @param int $end end-time of the planner
1714       * @return string with widget
1715       */
1716  	function plannerEventWidget($event,$start,$end,$indent='')
1717      {
1718          // some fields set by the dayColWidget for the other views
1719          $day_start = $this->bo->date2ts((string)$this->bo->date2string($event['start']));
1720          $event['start_m'] = ($event['start'] - $day_start) / 60;
1721          $event['end_m'] = round(($event['end'] - $day_start) / 60);
1722          $event['multiday'] = true;
1723  
1724          $data = $this->eventWidget($event,200,$indent,true,'planner_event');
1725          
1726          $left = $this->_planner_pos($event['start'],$start,$end);
1727          $width = $this->_planner_pos($event['end'],$start,$end) - $left;
1728          $color = $data['color'] ? $data['color'] : 'gray';
1729          
1730          return $indent.'<div class="plannerEvent'.($data['private'] ? 'Private' : '').'" style="left: '.$left.
1731              '%; width: '.$width.'%; background-color: '.$color.';"'.$data['popup'].' '.
1732              $this->html->tooltip($data['tooltip'],False,array('BorderWidth'=>0,'Padding'=>0)).'>'."\n".$data['html'].$indent."</div>\n";
1733      }
1734  }


Généré le : Sun Feb 25 17:20:01 2007 par Balluche grâce à PHPXref 0.7