[ Index ] |
|
Code source de eGroupWare 1.2.106-2 |
1 <?php 2 /**************************************************************************\ 3 * eGroupWare - ProjectManager - UI list and edit projects * 4 * http://www.egroupware.org * 5 * Written and (c) 2005 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.uiprojectmanager.inc.php 21517 2006-05-13 06:08:17Z ralfbecker $ */ 14 15 include_once (EGW_INCLUDE_ROOT.'/projectmanager/inc/class.boprojectmanager.inc.php'); 16 include_once (EGW_INCLUDE_ROOT.'/etemplate/inc/class.uietemplate.inc.php'); 17 18 /** 19 * ProjectManager UI: list and edit projects 20 * 21 * @package projectmanager 22 * @author RalfBecker-AT-outdoor-training.de 23 * @copyright (c) 2005 by RalfBecker-AT-outdoor-training.de 24 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License 25 */ 26 class uiprojectmanager extends boprojectmanager 27 { 28 /** 29 * @var array $public_functions Functions to call via menuaction 30 */ 31 var $public_functions = array( 32 'index' => true, 33 'edit' => true, 34 'view' => true, 35 ); 36 /** 37 * @var array $status_labels for pm_status, value - label pairs 38 */ 39 var $status_labels; 40 /** 41 * @var array $access_labels for pm_access, value - label pairs 42 */ 43 var $access_labels; 44 /** 45 * @var array $filter_labels for mains- & sub-projects 46 */ 47 var $filter_labels; 48 49 /** 50 * Constructor, calls the constructor of the extended class 51 */ 52 function uiprojectmanager() 53 { 54 $this->boprojectmanager(); 55 56 $this->status_labels = array( 57 'active' => lang('Active'), 58 'nonactive' => lang('Nonactive'), 59 'archive' => lang('Archive'), 60 'template' => lang('Template'), 61 ); 62 $this->access_labels = array( 63 'public' => lang('Public'), 64 'anonym' => lang('Anonymous public'), 65 'private' => lang('Private'), 66 ); 67 $this->filter_labels = array( 68 '' => lang('All'), 69 'mains' => lang('Mainprojects'), 70 'subs' => lang('Subprojects'), 71 ); 72 } 73 74 75 /** 76 * View a project 77 */ 78 function view() 79 { 80 $this->edit(null,true); 81 } 82 83 /** 84 * Edit, add or view a project 85 * 86 * @var array $content content-array if called by process-exec 87 * @var boolean $view only view project, default false, only used on first call !is_array($content) 88 */ 89 function edit($content=null,$view=false) 90 { 91 if ((int) $this->debug >= 1 || $this->debug == 'edit') $this->debug_message("uiprojectmanager::edit(,$view) content=".print_r($content,true)); 92 93 $tpl =& new etemplate('projectmanager.edit'); 94 95 if (is_array($content)) 96 { 97 if ($content['cancel']) 98 { 99 $tpl->location(array( 100 'menuaction' => $content['referer'], 101 )); 102 } 103 if ($content['pm_id']) 104 { 105 $this->read($content['pm_id']); 106 } 107 else 108 { 109 $this->init(); 110 } 111 $view = $content['view'] && !$content['edit'] || !$this->check_acl(EGW_ACL_EDIT); 112 113 if (!$content['view']) // just changed to edit-mode, still counts as view 114 { 115 //echo "content="; _debug_array($content); 116 $this->data_merge($content); 117 //echo "after data_merge data="; _debug_array($this->data); 118 119 // set the data of the pe_summary, if the project-value is unset 120 $pe_summary = $this->pe_summary(); 121 $datasource =& CreateObject('projectmanager.datasource'); 122 foreach($datasource->name2id as $pe_name => $id) 123 { 124 $pm_name = str_replace('pe_','pm_',$pe_name); 125 // check if update is necessary, because a field has be set or changed 126 if (($content[$pm_name] || $pm_name == 'pm_completion' && $content[$pm_name] !== '') && 127 ($content[$pm_name] != $this->data[$pm_name] || !($this->data['pm_overwrite'] & $id))) 128 { 129 //echo "$pm_name set to '".$this->data[$pm_name]."'<br>\n"; 130 $this->data['pm_overwrite'] |= $id; 131 } 132 // or check if a field is no longer set, or the datasource changed => set it from the datasource 133 elseif ((!$content[$pm_name] || $pm_name == 'pm_completion' && $content[$pm_name] === '') && 134 ($this->data['pm_overwrite'] & $id) || 135 !($this->data['pm_overwrite'] & $id) && $this->data[$pm_name] != $pe_summary[$pe_name]) 136 { 137 // if we have a change in the datasource, set pe_synced 138 if ($this->data[$pm_name] != $pe_summary[$name]) 139 { 140 $this->data['pm_synced'] = $this->now_su; 141 } 142 $this->data[$pm_name] = $pe_summary[$pe_name]; 143 //echo "$pm_name re-set to default '".$this->data[$pm_name]."'<br>\n"; 144 $this->data['pm_overwrite'] &= ~$id; 145 } 146 } 147 // process new and changed project-members 148 foreach((array)$content['member'] as $n => $uid) 149 { 150 if (!(int) $content['role'][$n]) 151 { 152 unset($this->data['pm_members'][$uid]); 153 } 154 elseif ((int) $uid) 155 { 156 $this->data['pm_members'][(int)$uid] = array( 157 'member_uid' => (int) $uid, 158 'member_availibility' => empty($content['availibility'][$n]) ? 100.0 : $content['availibility'][$n], 159 'role_id' => (int) $content['role'][$n], 160 ); 161 if ($GLOBALS['egw_info']['user']['apps']['admin'] && $content['general_avail'][$n]) 162 { 163 $this->set_availibility($uid,$content['general_avail'][$n]); 164 } 165 } 166 } 167 } 168 //echo "uiprojectmanager::edit(): data="; _debug_array($this->data); 169 170 if (($content['save'] || $content['apply']) && $this->check_acl(EGW_ACL_EDIT)) 171 { 172 // generate project-number, taking into account a given parent-project 173 if (empty($this->data['pm_number'])) 174 { 175 $parent_number = ''; 176 if ($content['add_link']) 177 { 178 list($app,$app_id) = explode(':',$content['add_link'],2); 179 if ($app == 'projectmanager' && ($parent = $this->search(array('pm_id'=>$app_id),'pm_number'))) 180 { 181 $parent_number = $parent[0]['pm_number']; 182 } 183 } 184 $this->generate_pm_number(true,$parent_number); 185 } 186 if ($this->not_unique()) 187 { 188 $msg = lang('Error: project-ID already exist, choose an other one or have one generated by leaving it emtpy !!!'); 189 unset($content['save']); // dont exit 190 } 191 elseif ($this->save() != 0) 192 { 193 $msg = lang('Error: saving the project (%1) !!!',$this->db->Error); 194 unset($content['save']); // dont exit 195 } 196 else 197 { 198 $msg = lang('Project saved'); 199 200 // create project already linked to a parent, in that case param of link-call need to be swaped 201 // as we want the new project to be the sub of the given project 202 if ($content['add_link']) 203 { 204 list($app,$app_id) = explode(':',$content['add_link'],2); 205 $this->link->link($app,$app_id,'projectmanager',$this->data['pm_id']); 206 } 207 // writing links for new entry, existing ones are handled by the widget itself 208 if (!$content['pm_id'] && is_array($content['link_to']['to_id'])) 209 { 210 $this->link->link('projectmanager',$this->data['pm_id'],$content['link_to']['to_id']); 211 } 212 if ($content['template'] && $this->copy($content['template'],2)) 213 { 214 $msg = lang('Template including elment-tree saved as new project'); 215 unset($content['template']); 216 } 217 } 218 } 219 if ($content['save']) 220 { 221 $tpl->location(array( 222 'menuaction' => $content['referer'], 223 'msg' => $msg, 224 )); 225 } 226 if ($content['delete'] && $this->check_acl(EGW_ACL_DELETE)) 227 { 228 // all delete are done by index 229 return $this->index(array('nm'=>array('rows'=>array( 230 'delete' => array($this->data['pm_id']=>true) 231 )))); 232 } 233 $referer = $content['referer']; 234 $template = $content['template']; 235 } 236 else 237 { 238 $referer = preg_match('/menuaction=([^&]+)/',$_SERVER['HTTP_REFERER'],$matches) ? $matches[1] : 'projectmanager.uiprojectmanager.index'; 239 240 if ((int) $_GET['pm_id']) 241 { 242 $this->read((int) $_GET['pm_id']); 243 } 244 // for a new sub-project set some data from the parent 245 elseif ($_GET['link_app'] == 'projectmanager' && (int) $_GET['link_id'] && $this->read((int) $_GET['link_id'])) 246 { 247 if (!$this->check_acl(EGW_ACL_READ)) // no read-rights for the parent, eg. someone edited the url 248 { 249 $tpl->location(array( 250 'menuaction' => $referer, 251 'msg' => lang('Permission denied !!!'), 252 )); 253 } 254 else 255 { 256 $this->generate_pm_number(true,$this->data['pm_number']); 257 foreach(array('pm_id','pm_title','pm_description','pm_creator','pm_created','pm_modified','pm_modifier','pm_real_start','pm_real_end','pm_completion','pm_status','pm_used_time','pm_planned_time','pm_used_budget','pm_planned_budget') as $key) 258 { 259 unset($this->data[$key]); 260 } 261 include_once (EGW_INCLUDE_ROOT.'/projectmanager/inc/class.datasource.inc.php'); 262 $this->data['pm_overwrite'] &= PM_PLANNED_START | PM_PLANNED_END; 263 } 264 } 265 elseif((int)$_GET['template'] && $this->read((int) $_GET['template'])) 266 { 267 if (!$this->check_acl(EGW_ACL_READ)) // no read-rights for the template, eg. someone edited the url 268 { 269 $tpl->location(array( 270 'menuaction' => $referer, 271 'msg' => lang('Permission denied !!!'), 272 )); 273 } 274 // we do only stage 1 of the copy, so if the user hits cancel everythings Ok 275 $this->copy($template = (int) $_GET['template'],1); 276 } 277 if ($this->data['pm_id']) 278 { 279 if (!$this->check_acl(EGW_ACL_READ)) 280 { 281 $tpl->location(array( 282 'menuaction' => $referer, 283 'msg' => lang('Permission denied !!!'), 284 )); 285 } 286 if (!$this->check_acl(EGW_ACL_EDIT)) $view = true; 287 } 288 // no pm-number set, generate one 289 if (!$this->data['pm_number']) $this->generate_pm_number(true); 290 } 291 if (!$pe_summary) $pe_summary = $this->pe_summary(); 292 293 if (!isset($content['add_link']) && !$this->data->pm_id && isset($_GET['link_app']) && isset($_GET['link_id']) && 294 preg_match('/^[a-z_0-9-]+:[:a-z_0-9-]+$/i',$_GET['link_app'].':'.$_GET['link_id'])) // gard against XSS 295 { 296 $add_link = $_GET['link_app'].':'.$_GET['link_id']; 297 } 298 else 299 { 300 $add_link = $content['add_link']; 301 } 302 $content = $this->data + array( 303 'msg' => $msg, 304 'general|description|members|accounting|custom|links' => !$content['general|description|members|accounting|custom|links'] && 305 !$view && $tpl->html->user_agent == 'mozilla' ? 'projectmanager.edit.description' : 306 $content['general|description|members|accounting|custom|links'], 307 'view' => $view, 308 'ds' => $pe_summary, 309 'link_to' => array( 310 'to_id' => $content['link_to']['to_id'] ? $content['link_to']['to_id'] : $this->data['pm_id'], 311 'to_app' => 'projectmanager', 312 ), 313 'duration_format' => ','.$this->config['duration_format'], 314 'no_budget' => !$this->check_acl(EGW_ACL_BUDGET,0,true) || in_array($this->data['pm_accounting_type'],array('status','times')), 315 ); 316 if ($add_link && !is_array($content['link_to']['to_id'])) 317 { 318 list($app,$app_id) = explode(':',$add_link,2); 319 $this->link->link('projectmanager',$content['link_to']['to_id'],$app,$app_id); 320 } 321 $content['links'] = $content['link_to']; 322 323 // empty not explicitly in the project set values 324 if (!is_object($datasource)) $datasource =& CreateObject('projectmanager.datasource'); 325 foreach($datasource->name2id as $pe_name => $id) 326 { 327 $pm_name = str_replace('pe_','pm_',$pe_name); 328 if (!($this->data['pm_overwrite'] & $id) && $pm_name != 'pm_title') 329 { 330 $content[$pm_name] = $preserv[$pm_name] = ''; 331 } 332 } 333 $readonlys = array( 334 'delete' => !$this->data['pm_id'] || !$this->check_acl(EGW_ACL_DELETE), 335 'edit' => !$view || !$this->check_acl(EGW_ACL_EDIT), 336 'general|description|members|accounting|custom|links' => array( 337 'accounting' => !$this->check_acl(EGW_ACL_BUDGET) && // disable the tab, if no budget rights and no owner or coordinator 338 ($this->config['accounting_types'] && count(explode(',',$this->config['accounting_types'])) == 1 || 339 !($this->data['pm_creator'] == $this->user || $this->data['pm_members'][$this->user]['role_id'] == 1)), 340 'custom' => !count($this->customfields), // only show customfields tab, if there are some 341 ), 342 'customfields' => $view, 343 'general_avail[1]' => !$GLOBALS['egw_info']['user']['apps']['admin'], 344 ); 345 if (!$this->check_acl(EGW_ACL_EDIT_BUDGET)) 346 { 347 $readonlys['pm_planned_budget'] = $readonlys['pm_used_budget'] = true; 348 } 349 $n = 2; 350 foreach((array)$this->data['pm_members'] as $uid => $data) 351 { 352 $content['role'][$n] = $data['role_id']; 353 $content['member'][$n] = $data['member_uid']; 354 $content['availibility'][$n] = empty($data['member_availibility']) ? 100.0 : $data['member_availibility']; 355 if (!is_array($general_avail)) $general_avail = $this->get_availibility(); 356 $content['general_avail'][$n] = empty($general_avail[$uid]) ? 100.0 : $general_avail[$uid]; 357 $readonlys["general_avail[$n]"] = $view || !$GLOBALS['egw_info']['user']['apps']['admin']; 358 $readonlys["role[$n]"] = $readonlys["availibility[$n]"] = $view; 359 ++$n; 360 } 361 //_debug_array($content); 362 $preserv = $this->data + array( 363 'view' => $view, 364 'add_link' => $add_link, 365 'member' => $content['member'], 366 'referer' => $referer, 367 'template' => $template, 368 ); 369 $this->instanciate('roles'); 370 371 $sel_options = array( 372 'pm_status' => &$this->status_labels, 373 'pm_access' => &$this->access_labels, 374 'role' => $this->roles->query_list(array( 375 'label' => 'role_title', 376 'title' => 'role_description', 377 ),'role_id',array( 378 'pm_id' => array(0,(int)$this->data['pm_id']) 379 )), 380 'pm_accounting_type' => array( 381 'status' => 'No accounting, only status', 382 'times' => 'No accounting, only times and status', 383 'budget' => 'Budget (no pricelist)', 384 'pricelist' => 'Budget and pricelist', 385 ), 386 ); 387 if ($this->config['accounting_types']) // only allow the configured types 388 { 389 $allowed = explode(',',$this->config['accounting_types']); 390 foreach($sel_options['pm_accounting_type'] as $key => $label) 391 { 392 if (!in_array($key,$allowed)) unset($sel_options['pm_accounting_type'][$key]); 393 } 394 if (count($sel_options['pm_accounting_type']) == 1) 395 { 396 $readonlys['pm_accounting_type'] = true; 397 } 398 } 399 if ($view) 400 { 401 foreach($this->db_cols as $name) 402 { 403 $readonlys[$name] = true; 404 } 405 $readonlys['save'] = $readonlys['apply'] = true; 406 407 // add fields not stored in the main-table 408 $readonlys['pm_members'] = $readonlys['edit_roles'] = true; 409 410 $readonlys['links'] = $readonlys['link_to'] = true; 411 } 412 $GLOBALS['egw_info']['flags']['app_header'] = lang('projectmanager') . ' - ' . 413 ($this->data['pm_id'] ? ($view ? lang('View project') : lang('Edit project')) : lang('Add project')); 414 $tpl->exec('projectmanager.uiprojectmanager.edit',$content,$sel_options,$readonlys,$preserv); 415 } 416 417 /** 418 * query projects for nextmatch in the projects-list 419 * 420 * reimplemented from so_sql to disable action-buttons based on the acl and make some modification on the data 421 * 422 * @param array $query 423 * @param array &$rows returned rows/cups 424 * @param array &$readonlys eg. to disable buttons based on acl 425 */ 426 function get_rows($query,&$rows,&$readonlys) 427 { 428 $GLOBALS['egw']->session->appsession('project_list','projectmanager',$query); 429 430 // handle nextmatch filters like col_filters 431 foreach(array('cat_id' => 'cat_id','filter2' => 'pm_status') as $nm_name => $pm_name) 432 { 433 unset($query['col_filter'][$pm_name]); 434 if ($query[$nm_name]) $query['col_filter'][$pm_name] = $query[$nm_name]; 435 } 436 $query['col_filter']['subs_or_mains'] = $query['filter']; 437 438 $total = parent::get_rows($query,$rows,$readonlys,true,true); 439 440 $readonlys = array(); 441 foreach($rows as $n => $val) 442 { 443 $row =& $rows[$n]; 444 if (!$this->check_acl(EGW_ACL_EDIT,$row)) 445 { 446 $readonlys["edit[$row[pm_id]]"] = true; 447 } 448 if (!$this->check_acl(EGW_ACL_DELETE,$row)) 449 { 450 $readonlys["delete[$row[pm_id]]"] = true; 451 } 452 } 453 if ((int) $this->debug >= 2 || $this->debug == 'get_rows') 454 { 455 $this->debug_message("uiprojectmanager::get_rows(".print_r($query,true).") total=$total, rows =".print_r($rows,true)."\nreadonlys=".print_r($readonlys,true)); 456 } 457 return $total; 458 } 459 460 /** 461 * List existing projects 462 * 463 * @param array $content=null 464 * @param string $msg='' 465 */ 466 function index($content=null,$msg='') 467 { 468 if ((int) $this->debug >= 1 || $this->debug == 'index') $this->debug_message("uiprojectmanager::index(,$msg) content=".print_r($content,true)); 469 470 $tpl =& new etemplate('projectmanager.list'); 471 472 if ($_GET['msg']) $msg = $_GET['msg']; 473 474 if ($content['add']) 475 { 476 $tpl->location(array( 477 'menuaction' => 'projectmanager.uiprojectmanager.edit', 478 'template' => $content['template'], 479 )); 480 } 481 if ($content['delete_checked'] || $content['gantt_checked']) 482 { 483 $checked = $content['nm']['rows']['checked']; 484 if (!is_array($checked) || !count($checked)) 485 { 486 $msg = lang('You need to select a project first'); 487 } 488 else 489 { 490 if ($content['gantt_checked']) 491 { 492 $tpl->location(array( 493 'menuaction' => 'projectmanager.ganttchart.show', 494 'pm_id' => implode(',',$checked), 495 )); 496 } 497 // delete all checked 498 $deleted = $no_perms = 0; 499 foreach($checked as $pm_id) 500 { 501 if ($this->read($pm_id) && !$this->check_acl(EGW_ACL_DELETE)) 502 { 503 $no_perms++; 504 } 505 else 506 { 507 $this->delete($pm_id); 508 $deleted++; 509 } 510 } 511 $msg = $no_perms ? lang('%1 times permission denied, %2 projects deleted',$no_perms,$deleted) : 512 lang('%1 projects deleted',$deleted); 513 } 514 } 515 $content = $content['nm']['rows']; 516 517 if ($content['view'] || $content['edit'] || $content['delete'] || $content['ganttchart']) 518 { 519 foreach(array('view','edit','delete','ganttchart') as $action) 520 { 521 if ($content[$action]) 522 { 523 list($pm_id) = each($content[$action]); 524 break; 525 } 526 } 527 //echo "<p>uiprojectmanger::index() action='$action', pm_id='$pm_id'</p>\n"; 528 switch($action) 529 { 530 case 'ganttchart': 531 $tpl->location(array( 532 'menuaction' => 'projectmanager.ganttchart.show', 533 'pm_id' => $pm_id, 534 )); 535 break; 536 case 'view': 537 case 'edit': 538 $tpl->location(array( 539 'menuaction' => 'projectmanager.uiprojectmanager.'.$action, 540 'pm_id' => $pm_id, 541 )); 542 break; 543 544 case 'delete': 545 if ($this->read($pm_id) && !$this->check_acl(EGW_ACL_DELETE)) 546 { 547 $msg = lang('Permission denied !!!'); 548 } 549 else 550 { 551 $msg = $this->delete($pm_id) ? lang('Project deleted') : 552 lang('Error: deleting project !!!'); 553 } 554 break; 555 } 556 } 557 $content = array( 558 'nm' => $GLOBALS['egw']->session->appsession('project_list','projectmanager'), 559 'msg' => $msg, 560 ); 561 if (!is_array($content['nm'])) 562 { 563 $content['nm'] = array( 564 'get_rows' => 'projectmanager.uiprojectmanager.get_rows', 565 'filter2' => 'active',// I initial value for the filter 566 'options-filter2'=> $this->status_labels, 567 'filter2_no_lang'=> True,// I set no_lang for filter (=dont translate the options) 568 'filter' => 'mains', 569 'filter_label' => lang('Filter'),// I label for filter (optional) 570 'options-filter' => $this->filter_labels, 571 'filter_no_lang' => True,// I set no_lang for filter (=dont translate the options) 572 // 'bottom_too' => True,// I show the nextmatch-line (arrows, filters, search, ...) again after the rows 573 'order' => 'pm_modified',// IO name of the column to sort after (optional for the sortheaders) 574 'sort' => 'DESC',// IO direction of the sort: 'ASC' or 'DESC' 575 ); 576 } 577 $templates = array(); 578 foreach((array)$this->search(array( 579 'pm_status' => 'template', 580 ),$this->table_name.'.pm_id AS pm_id,pm_number,pm_title','pm_number','','',False,'OR') as $template) 581 { 582 $templates[$template['pm_id']] = array( 583 'label' => $template['pm_number'], 584 'title' => $template['pm_title'], 585 ); 586 } 587 $GLOBALS['egw_info']['flags']['app_header'] = lang('projectmanager').' - '.lang('Projectlist'); 588 $tpl->exec('projectmanager.uiprojectmanager.index',$content,array( 589 'template' => $templates, 590 )); 591 } 592 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 17:20:01 2007 | par Balluche grâce à PHPXref 0.7 |