* @copyright (c) 2004-9 by RalfBecker-At-outdoor-training.de
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
/**
* Shared base-class of all calendar UserInterface classes
*
* It manages eg. the state of the controls in the UI and generated the calendar navigation (sidebox-menu)
*
* The new UI, BO and SO classes have a strikt definition, in which time-zone they operate:
* UI only operates in user-time, so there have to be no conversation at all !!!
* BO's functions take and return user-time only (!), they convert internaly everything to servertime, because
* SO operates only on server-time
*
* All permanent debug messages of the calendar-code should done via the debug-message method of the bocal class !!!
*/
class calendar_ui
{
/**
* @var $debug mixed integer level or string function-name
*/
var $debug=false;
/**
* instance of the bocal or bocalupdate class
*
* @var calendar_boupdate
*/
var $bo;
/**
* instance of jscalendar
*
* @var jscalendar
*/
var $jscal;
/**
* Reference to global datetime class
*
* @var egw_datetime
*/
var $datetime;
/**
* Instance of categories class
*
* @var categories
*/
var $categories;
/**
* Reference to global uiaccountsel class
*
* @var uiaccountsel
*/
var $accountsel;
/**
* @var array $common_prefs reference to $GLOBALS['egw_info']['user']['preferences']['common']
*/
var $common_prefs;
/**
* @var array $cal_prefs reference to $GLOBALS['egw_info']['user']['preferences']['calendar']
*/
var $cal_prefs;
/**
* @var int $wd_start user pref. workday start
*/
var $wd_start;
/**
* @var int $wd_start user pref. workday end
*/
var $wd_end;
/**
* @var int $interval_m user pref. interval
*/
var $interval_m;
/**
* @var int $user account_id of loged in user
*/
var $user;
/**
* @var string $date session-state: date (Ymd) of shown view
*/
var $date;
/**
* @var int $cat_it session-state: selected category
*/
var $cat_id;
/**
* @var int $filter session-state: selected filter, at the moment all or hideprivate
*/
var $filter;
/**
* @var int/array $owner session-state: selected owner(s) of shown calendar(s)
*/
var $owner;
/**
* @var string $sortby session-state: filter of planner: 'category' or 'user'
*/
var $sortby;
/**
* @var string $view session-state: selected view
*/
var $view;
/**
* @var string $view menuaction of the selected view
*/
var $view_menuaction;
/**
* @var int $first first day of the shown view
*/
var $first;
/**
* @var int $last last day of the shown view
*/
var $last;
/**
* @var array $states_to_save all states that will be saved to the user prefs
*/
var $states_to_save = array('owner','filter','cat_id','view','sortby','planner_days');
/**
* Constructor
*
* @param boolean $use_boupdate use bocalupdate as parenent instead of bocal
* @param array $set_states=null to manualy set / change one of the states, default NULL = use $_REQUEST
*/
function __construct($use_boupdate=false,$set_states=NULL)
{
if ($use_boupdate)
{
$this->bo = new calendar_boupdate();
}
else
{
$this->bo = new calendar_bo();
}
$this->jscal = $GLOBALS['egw']->jscalendar;
$this->datetime = $GLOBALS['egw']->datetime;
$this->accountsel = $GLOBALS['egw']->uiaccountsel;
$this->categories = new categories($this->user,'calendar');
$this->common_prefs = &$GLOBALS['egw_info']['user']['preferences']['common'];
$this->cal_prefs = &$GLOBALS['egw_info']['user']['preferences']['calendar'];
$this->bo->check_set_default_prefs();
$this->wd_start = 60*$this->cal_prefs['workdaystarts'];
$this->wd_end = 60*$this->cal_prefs['workdayends'];
$this->interval_m = $this->cal_prefs['interval'];
$this->user = $GLOBALS['egw_info']['user']['account_id'];
$this->manage_states($set_states);
$GLOBALS['uical'] = &$this; // make us available for ExecMethod, else it creates a new instance
// calendar does not work with hidden sidebox atm.
unset($GLOBALS['egw_info']['user']['preferences']['common']['auto_hide_sidebox']);
// make sure the hook for export_limit is registered
if (!$GLOBALS['egw']->hooks->hook_exists('export_limit','calendar')) $GLOBALS['egw']->hooks->register_single_app_hook('calendar','export_limit');
}
/**
* Checks and terminates (or returns for home) with a message if $this->owner include a user/resource we have no read-access to
*
* If currentapp == 'home' we return the error instead of terminating with it !!!
*
* @return boolean/string false if there's no error or string with error-message
*/
function check_owners_access()
{
$no_access = $no_access_group = array();
foreach(explode(',',$this->owner) as $owner)
{
$owner = trim($owner);
if (is_numeric($owner) && $GLOBALS['egw']->accounts->get_type($owner) == 'g')
{
foreach($GLOBALS['egw']->accounts->member($owner) as $member)
{
$member = $member['account_id'];
if (!$this->bo->check_perms(EGW_ACL_READ|EGW_ACL_READ_FOR_PARTICIPANTS|EGW_ACL_FREEBUSY,0,$member))
{
$no_access_group[$member] = $this->bo->participant_name($member);
}
}
}
elseif (!$this->bo->check_perms(EGW_ACL_READ|EGW_ACL_READ_FOR_PARTICIPANTS|EGW_ACL_FREEBUSY,0,$owner))
{
$no_access[$owner] = $this->bo->participant_name($owner);
}
}
if (count($no_access))
{
$msg = '
'.lang('Access denied to the calendar of %1 !!!',implode(', ',$no_access))."
\n";
if ($GLOBALS['egw_info']['flags']['currentapp'] == 'home')
{
return $msg;
}
common::egw_header();
if ($GLOBALS['egw_info']['flags']['nonavbar']) parse_navbar();
echo $msg;
common::egw_footer();
common::egw_exit();
}
if (count($no_access_group))
{
$this->bo->warnings['groupmembers'] = lang('Groupmember(s) %1 not included, because you have no access.',implode(', ',$no_access_group));
}
return false;
}
/**
* show the egw-framework plus possible messages ($_GET['msg'] and $this->group_warning from check_owner_access)
*/
function do_header()
{
// Include the jQuery-UI CSS - many more complex widgets use it
$theme = 'redmond';
egw_framework::includeCSS("/phpgwapi/js/jquery/jquery-ui/$theme/jquery-ui-1.10.3.custom.css");
// Load our CSS after jQuery-UI, so we can override it
egw_framework::includeCSS('/etemplate/templates/default/etemplate2.css');
// load etemplate2
egw_framework::validate_file('/etemplate/js/etemplate2.js');
// load our app.js file
egw_framework::validate_file('/calendar/js/app.js');
// tell egw_framework to include wz_tooltip
$GLOBALS['egw_info']['flags']['include_wz_tooltip'] = true;
common::egw_header();
if ($_GET['msg']) echo '
'.html::htmlspecialchars($_GET['msg'])."
\n";
if ($this->bo->warnings) echo '
'.implode(' ',$this->bo->warnings)."
\n";
}
/**
* Manages the states of certain controls in the UI: date shown, category selected, ...
*
* The state of all these controls is updated if they are set in $_REQUEST or $set_states and saved in the session.
* The following states are used:
* - date or year, month, day: the actual date of the period displayed
* - cat_id: the selected category
* - owner: the owner of the displayed calendar
* - save_owner: the overriden owner of the planner
* - filter: the used filter: all or hideprivate
* - sortby: category or user of planner
* - view: the actual view, where dialogs should return to or which they refresh
* @param array $set_states array to manualy set / change one of the states, default NULL = use $_REQUEST
*/
function manage_states($set_states=NULL)
{
$states = $states_session = $GLOBALS['egw']->session->appsession('session_data','calendar');
// retrieve saved states from prefs
if(!$states)
{
$states = unserialize($this->bo->cal_prefs['saved_states']);
}
// only look at _REQUEST, if we are in the calendar (prefs and admin show our sidebox menu too!)
if (is_null($set_states))
{
$set_states = substr($_GET['menuaction'],0,9) == 'calendar.' ? $_REQUEST : array();
}
if (!$states['date'] && $states['year'] && $states['month'] && $states['day'])
{
$states['date'] = $this->bo->date2string($states);
}
foreach(array(
'date' => $this->bo->date2string($this->bo->now_su),
'cat_id' => 0,
'filter' => 'default',
'owner' => $this->user,
'save_owner' => 0,
'sortby' => 'category',
'planner_days'=> 0, // full month
'view' => ($this->bo->cal_prefs['defaultcalendar']?$this->bo->cal_prefs['defaultcalendar']:'day'), // use pref, if exists else use the dayview
'listview_days'=> '', // no range
) as $state => $default)
{
if (isset($set_states[$state]))
{
if ($state == 'owner')
{
// only change the owners of the same resource-type as given in set_state[owner]
$set_owners = explode(',',$set_states['owner']);
if ((string)$set_owners[0] === '0') // set exactly the specified owners (without the 0)
{
if ($set_states['owner'] === '0,r0') // small fix for resources
{
$set_states['owner'] = $default; // --> set default, instead of none
}
else
{
$set_states['owner'] = substr($set_states['owner'],2);
}
}
else // change only the owners of the given type
{
$res_type = is_numeric($set_owners[0]) ? false : $set_owners[0][0];
$owners = explode(',',$states['owner'] ? $states['owner'] : $default);
foreach($owners as $key => $owner)
{
if (!$res_type && is_numeric($owner) || $res_type && $owner[0] == $res_type)
{
unset($owners[$key]);
}
}
if (!$res_type || !in_array($res_type.'0',$set_owners))
{
$owners = array_merge($owners,$set_owners);
}
$set_states['owner'] = implode(',',$owners);
}
}
// for the uiforms class (eg. edit), dont store the (new) owner, as it might change the view
if (substr($_GET['menuaction'],0,25) == 'calendar.calendar_uiforms')
{
$this->owner = $set_states[$state];
continue;
}
$states[$state] = $set_states[$state];
}
elseif (!is_array($states) || !isset($states[$state]))
{
$states[$state] = $default;
}
if ($state == 'date')
{
$date_arr = $this->bo->date2array($states['date']);
foreach(array('year','month','day') as $name)
{
$this->$name = $states[$name] = $date_arr[$name];
}
}
$this->$state = $states[$state];
}
// remove a given calendar from the view
if (isset($_GET['close']) && ($k = array_search($_GET['close'], $owners=explode(',',$this->owner))) !== false)
{
unset($owners[$k]);
$this->owner = $states['owner'] = implode(',',$owners);
}
if (substr($this->view,0,8) == 'planner_')
{
$states['sortby'] = $this->sortby = $this->view == 'planner_cat' ? 'category' : 'user';
$states['view'] = $this->view = 'planner';
}
// set the actual view as return_to
if (isset($_GET['menuaction']))
{
list($app,$class,$func) = explode('.',$_GET['menuaction']);
if ($func == 'index')
{
$func = $this->view; $this->view = 'index'; // switch to the default view
}
}
else // eg. calendar/index.php
{
$func = $this->view;
$class = $this->view == 'listview' ? 'calendar_uilist' : 'calendar_uiviews';
}
if ($class == 'calendar_uiviews' || $class == 'calendar_uilist')
{
// if planner_start_with_group is set in the users prefs: switch owner for planner to planner_start_with_group and back
if ($this->cal_prefs['planner_start_with_group'])
{
if ($this->cal_prefs['planner_start_with_group'] > 0) $this->cal_prefs['planner_start_with_group'] *= -1; // fix old 1.0 pref
if (!$states_session && !$_GET['menuaction']) $this->view = ''; // first call to calendar
if ($func == 'planner' && $this->view != 'planner' && $this->owner == $this->user)
{
//echo "
switched for planner to {$this->cal_prefs['planner_start_with_group']}, view was $this->view, func=$func, owner was $this->owner