00001 <?php if(!function_exists('startedIndexPhp')) { header("location:../index.php"); exit();}
00002 # streber - a php based project management system
00003 # Copyright (c) 2005 Thomas Mann - thomas@pixtur.de
00004 # Distributed under the terms and conditions of the GPL as stated in docs/license.txt
00005
00006
00007 require_once(confGet('DIR_STREBER') . 'db/class_issue.inc.php');
00008 require_once(confGet('DIR_STREBER') . 'lists/list_tasks.inc.php');
00009
00010
00021 class ListBlock_milestones extends ListBlock
00022 {
00023
00024 public $filters= array(); # assoc arry of ListFilters
00025 public $active_block_function = 'grouped'; #@@@ HACK
00026 public $tasks_assigned_to= NULL;
00027
00028 public $tasks_open;
00029 public $tasks_closed;
00030 public $num_open;
00031 public $num_completed;
00032 public $num_closed;
00033 public $sum_completion_min;
00034 public $sum_completion_max;
00035 public $sum_estimated_min;
00036 public $sum_estimated_max;
00037
00038 public function __construct($args=NULL)
00039 {
00040 parent::__construct($args);
00041
00042 global $PH;
00043 $this->id='tasks';
00044 $this->class='milestones';
00045 $this->bg_style='bg_projects';
00046 $this->no_items_html=NULL;
00047 $this->title = __("Milestones");
00048
00049
00050 ### columns ###
00051 $this->add_col( new ListBlockColSelect());
00052
00053 $this->add_col( new ListBlockCol_MilestoneName( array('use_short_names'=>false,'indention'=>true)));
00054 $this->add_col( new listBlockCol_MilestoneDate());
00055
00056 $this->add_col( new ListBlockCol_MilestoneTasksGraph());
00057 $this->add_col( new ListBlockCol_TaskAssignedTo(array('use_short_names'=>false )));
00058
00059 $this->add_col( new ListBlockColPubLevel());
00060
00061
00062 ### functions ###
00063 $this->add_function(new ListFunction(array(
00064 'target'=>$PH->getPage('taskEdit')->id,
00065 'name' =>__('Edit'),
00066 'id' =>'taskEdit',
00067 'icon' =>'edit',
00068 'context_menu'=>'submit',
00069 )));
00070
00071 ### functions ###
00072 $this->add_function(new ListFunction(array(
00073 'target'=>$PH->getPage('tasksDelete')->id,
00074 'name' =>__('Delete'),
00075 'id' =>'taskDelete',
00076 'icon' =>'delete',
00077 'context_menu'=>'submit',
00078 )));
00079
00080 $this->add_function(new ListFunction(array(
00081 'target'=>$PH->getPage('itemsAsBookmark')->id,
00082 'name' =>__('Mark as bookmark'),
00083 'id' =>'itemsAsBookmark',
00084 'context_menu'=>'submit',
00085 )));
00086
00087 }
00088
00092 public function render_list(&$tasks=NULL)
00093 {
00094 global $PH;
00095 require_once(confGet('DIR_STREBER') . 'render/render_wiki.inc.php');
00096
00097 $this->render_header();
00098
00099 $style='';
00100 if(!$tasks && $this->no_items_html) {
00101 $this->render_tfoot_empty();
00102 }
00103 else {
00104
00105 ### render table lines ###
00106 $this->render_thead();
00107 $count_estimated=0;
00108
00109 $last_group= NULL;
00110 foreach($tasks as $t) {
00111
00112
00113 ### get subtasks if expanded
00114 $this->tasks_open= Task::getAll(array(
00115 'for_milestone' => $t->id,
00116 'status_min' => STATUS_NEW,
00117 'status_max' => STATUS_COMPLETED,
00118 'project' => $t->project,
00119 'show_folders' => false,
00120 ));
00121 $this->tasks_closed= Task::getAll(array(
00122 'for_milestone' => $t->id,
00123 'status_min' => STATUS_APPROVED,
00124 'status_max' => STATUS_CLOSED,
00125 'project' => $t->project,
00126 'show_folders' => false,
00127 ));
00128
00129
00130 $this->num_closed= count($this->tasks_closed);
00131 $this->num_open = count($this->tasks_open);
00132
00133
00134 $this->num_completed= 0;
00135 $this->sum_estimated_min= 0;
00136 $this->sum_estimated_max= 0;
00137 $this->sum_completion_min= 0;
00138 $this->sum_completion_max= 0;
00139
00140 foreach($this->tasks_open as $tt) {
00141 $this->sum_estimated_min+= $tt->estimated;
00142 $this->sum_estimated_max+= $tt->estimated_max
00143 ? $tt->estimated_max
00144 : $tt->estimated;
00145
00146
00147 if($tt->status > STATUS_BLOCKED) {
00148 $this->num_completed++;
00149 $this->sum_completion_min+= $tt->estimated;
00150 $this->sum_completion_max+= $tt->estimated_max;
00151 }
00152 else {
00153 $this->sum_completion_min+= $tt->estimated * $tt->completion / 100;
00154 }
00155 }
00156
00157 foreach($this->tasks_closed as $tt) {
00158
00159 $this->sum_estimated_min+= $tt->estimated;
00160 $this->sum_estimated_max+= $tt->estimated_max
00161 ? $tt->estimated_max
00162 : $tt->estimated;
00163
00164 $this->sum_completion_min+= $tt->estimated;
00165 $this->sum_completion_max+= $tt->estimated_max;
00166 }
00167
00168
00169 if($this->groupings && $this->active_block_function == 'grouped') {
00170 $gr= $this->groupings->active_grouping_key;
00171
00172 if($last_group != $t->$gr) {
00173 echo '<tr class=group><td colspan='. count($this->columns) .'>'. $this->groupings->active_grouping_obj->render($t).'</td></tr>';
00174 $last_group = $t->$gr;
00175 }
00176 }
00177
00178 ### done ###
00179 if(@intval($t->status) >= STATUS_COMPLETED) {
00180 $style_row= $style . ' isDone';
00181 }
00182 else {
00183 $style_row= $style;
00184 $count_estimated+=$t->estimated;
00185 }
00186 $this->render_trow(&$t,$style_row);
00187
00188 }
00189 $this->render_tfoot();
00190 }
00191 }
00192
00193
00194 public function print_automatic($project=NULL, $parent_task=NULL)
00195 {
00196 global $PH;
00197 global $auth;
00198
00199 $this->query_options['is_milestone']=1;
00200 if(!isset($this->query_options['status_max'])) {
00201 $this->query_options['status_max']=STATUS_COMPLETED;
00202 };
00203
00204 if($project) {
00205 $this->query_options['project']= $project->id;
00206 }
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 #if(!$this->active_block_function=$this->getBlockStyleFromCookie()) {
00218 # $this->active_block_function = 'list';
00219 #}
00220
00221
00222 ### add filter options ###
00223 #foreach($this->filters as $f) {
00224 # foreach($f->getQuerryAttributes() as $k=>$v) {
00225 # $this->query_options[$k]= $v;
00226 # }
00227 #}
00228
00229 $sort_cookie= "sort_{$PH->cur_page->id}_{$this->id}_{$this->active_block_function}";
00230 if($sort= get($sort_cookie)) {
00231 $this->query_options['order_by']= asCleanString($sort);
00232 }
00233
00234 {
00235
00236 if($this->tasks_assigned_to) {
00237 $this->query_options['assigned_to_person']= $this->tasks_assigned_to;
00238 }
00239 $this->query_options['show_folders'] = false;
00240
00241 unset($this->columns['date_closed']);
00242 # unset($this->columns['pub_level']);
00243 unset($this->columns['estimated']);
00244 }
00245
00246 if($auth->cur_user->user_rights & RIGHT_VIEWALL) {
00247 $this->query_options['visible_only']=false;
00248 }
00249
00250 $tasks= Task::getAll($this->query_options);
00251
00252 $this->render_list(&$tasks);
00253 }
00254 }
00255
00256
00257 class ListBlockCol_MilestoneName extends ListBlockCol
00258 {
00259 public $key='name';
00260
00261 public function __construct($args=NULL) {
00262 parent::__construct($args);
00263 $this->width='90%';
00264 $this->name=__('Milestone');
00265 $this->id='name';
00266 }
00267
00268 function render_tr(&$task, $style="")
00269 {
00270
00271 global $PH;
00272 if(!isset($task) || !is_object($task)) {
00273 trigger_error("ListBlock->render_tr() called without valid object", E_USER_WARNING);
00274 return;
00275 }
00276
00277 global $g_wiki_project;
00278 $g_wiki_project= $task->project;
00279
00280
00281 $html_link= '<b>'. $task->getLink(false) .'</b>';
00282 $buffer= '';
00283
00284
00285 ### collapsed view ###
00286 if($task->view_collapsed) {
00287 $buffer.= $PH->getLink('taskToggleViewCollapsed',"<img src=\"". getThemeFile("img/toggle_folder_closed.gif") . "\">",array('tsk'=>$task->id),NULL, true)
00288 . $html_link;
00289 }
00290 ### expanded view ###
00291 else {
00292
00293 $buffer.= $PH->getLink('taskToggleViewCollapsed',"<img src=\"" . getThemeFile("img/toggle_folder_open.gif") . "\">",array('tsk'=>$task->id),NULL, true)
00294 . $html_link
00295 . '<br>'
00296 . wiki2html($task->description, $task->project);
00297 }
00298 echo '<td>'. $buffer .'</td>';
00299 }
00300 }
00301
00302
00303
00304 class ListBlockCol_MilestoneDate extends ListBlockCol
00305 {
00306 public $key='planned_end';
00307
00308 public function __construct($args=NULL) {
00309 parent::__construct($args);
00310 $this->width='15%';
00311 $this->name=__('Planned for');
00312 $this->id='planned_end';
00313 }
00314
00315 function render_tr(&$task, $style="")
00316 {
00317
00318 global $PH;
00319 if(!isset($task) || !is_object($task)) {
00320 trigger_error("ListBlock->render_tr() called without valid object", E_USER_WARNING);
00321 return;
00322 }
00323
00324
00325 ### days left ###
00326 $due_str=$task->planned_end;
00327 $html_due= '';
00328
00329 if($due_str == "0000-00-00" || $due_str == "0000-00-00 00:00:00") {
00330 $html_due ='';
00331 }
00332 else {
00333 $due_days= floor( (strToGMTime($task->planned_end) - time())/24/60/60)+1;
00334 if($due_days == 0) {
00335 $html_due=__("Due Today");
00336 }
00337 else if($due_days<0) {
00338 $class='overDue';
00339 $html_due= '<span class=overdue>'
00340 . sprintf(__("%s days late"), -$due_days)
00341 . '</span>';
00342 }
00343 else {
00344 $html_due= sprintf(__("%s days left"), $due_days);
00345 }
00346 }
00347
00348
00349
00350 $buffer = renderDateHtml($task->planned_end);
00351
00352 if($html_due && $task->status < STATUS_CLOSED) {
00353 $buffer.= '<br><span class=sub>('. $html_due .')</span>';
00354 }
00355
00356 if($this->parent_block->sum_estimated_max) {
00357 $buffer.= '<br><span class=sub>'
00358 . sprintf(__('%s required'), renderEstimatedDuration(
00359 ($this->parent_block->sum_estimated_max + $this->parent_block->sum_estimated_min)/2
00360 -
00361 ($this->parent_block->sum_completion_max + $this->parent_block->sum_completion_min)/2
00362 ))
00363 . '</span>';
00364 }
00365
00366 echo '<td class=nowrap>'. $buffer .'</td>';
00367 }
00368 }
00369
00370
00371 class ListBlockCol_MilestoneTasksGraph extends ListBlockCol
00372 {
00373
00374 public function __construct($args=NULL)
00375 {
00376 parent::__construct($args);
00377 $this->name= __('Tasks open','columnheader');
00378 }
00379
00380
00381 function render_tr(&$obj, $style="")
00382 {
00383 if(!isset($obj) || !$obj instanceof Task) {
00384 trigger_error("ListBlock->render_tr() called without valid object", E_USER_WARNING);
00385 return;
00386 }
00387
00388 global $PH;
00389
00394 if($this->parent_block->num_open == 0 && $this->parent_block->num_closed == 0) {
00395 echo "<td></td>";
00396 }
00397 else {
00398 $width= 150;
00399 if($this->parent_block->num_open + $this->parent_block->num_closed) {
00400 $width_closed= floor($width * ($this->parent_block->num_closed) / ($this->parent_block->num_open + $this->parent_block->num_closed));
00401 $width_completed= floor($width * ($this->parent_block->num_completed) / ($this->parent_block->num_open + $this->parent_block->num_closed));
00402 if($width_completed + $width_closed > $width) {
00403 $width_completed = $width - $width_closed;
00404 }
00405
00406 }
00407 else {
00408 $width_closed= 0;
00409 $width_completed= 0;
00410 }
00411
00412
00413 echo "<td>";
00414 echo "<div style='width:" .($width+2). "px;height:10px;border:1px solid #ccc;background-color:#fff;'>";
00415
00416 if($width_closed) {
00417 echo "<div style='float:left;width:{$width_closed}px;height:10px;background-color:#90BC54;'></div>";
00418 }
00419 if($width_completed) {
00420 echo "<div style='float:left;width:{$width_completed}px;height:10px;background-color:#CEE98B;;border-left:1px solid #fff;'></div>";
00421 }
00422
00423 echo "</div>";
00424
00425 if(!$obj->view_collapsed) {
00426 echo $PH->getLink('projViewTasks', $this->parent_block->num_closed." ". __("closed"),
00427 array(
00428 'prj' => $obj->project,
00429 'for_milestone'=>$obj->id,
00430 'preset' =>'closed_tasks',
00431 ))
00432 . " / "
00433 . $PH->getLink('projViewTasks', ($this->parent_block->num_open - $this->parent_block->num_completed)." ". __("open"),
00434 array(
00435 'prj' => $obj->project,
00436 'for_milestone'=>$obj->id,
00437 'preset' =>'next_milestone',
00438 ))
00439 . '<br>';
00440 if( $this->parent_block->sum_estimated_min) {
00441 echo renderEstimationGraph($this->parent_block->sum_estimated_min, $this->parent_block->sum_estimated_max, ($this->parent_block->sum_completion_min/ $this->parent_block->sum_estimated_min) * 100);
00442 }
00443 }
00444
00445 echo "</td>";
00446 }
00447 }
00448 }
00449
00450
00451
00452
00453 ?>