3 // This file is part of Moodle - http://moodle.org/
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 class grade_edit_tree {
19 public $columns = array();
22 * @var object $gtree @see grade/lib.php
27 * @var grade_plugin_return @see grade/lib.php
32 * @var string $moving The eid of the category or item being moved
36 public $deepest_level;
38 public $uses_extra_credit = false;
40 public $uses_weight = false;
44 public $categories = array();
48 public function __construct($gtree, $moving=false, $gpr) {
49 global $USER, $OUTPUT, $COURSE;
51 $this->gtree = $gtree;
52 $this->moving = $moving;
54 $this->deepest_level = $this->get_deepest_level($this->gtree->top_element);
56 $this->columns = array(grade_edit_tree_column::factory('name', array('deepest_level' => $this->deepest_level)),
57 grade_edit_tree_column::factory('aggregation', array('flag' => true)));
59 if ($this->uses_weight) {
60 $this->columns[] = grade_edit_tree_column::factory('weight', array('adv' => 'aggregationcoef'));
62 if ($this->uses_extra_credit) {
63 $this->columns[] = grade_edit_tree_column::factory('extracredit', array('adv' => 'aggregationcoef'));
66 $this->columns[] = grade_edit_tree_column::factory('range'); // This is not a setting... How do we deal with it?
67 $this->columns[] = grade_edit_tree_column::factory('aggregateonlygraded', array('flag' => true));
68 $this->columns[] = grade_edit_tree_column::factory('aggregatesubcats', array('flag' => true));
69 $this->columns[] = grade_edit_tree_column::factory('aggregateoutcomes', array('flag' => true));
70 $this->columns[] = grade_edit_tree_column::factory('droplow', array('flag' => true));
71 $this->columns[] = grade_edit_tree_column::factory('keephigh', array('flag' => true));
72 $this->columns[] = grade_edit_tree_column::factory('multfactor', array('adv' => true));
73 $this->columns[] = grade_edit_tree_column::factory('plusfactor', array('adv' => true));
74 $this->columns[] = grade_edit_tree_column::factory('actions');
75 $this->columns[] = grade_edit_tree_column::factory('select');
77 $mode = ($USER->gradeediting[$COURSE->id]) ? 'advanced' : 'simple';
80 if ($mode == 'simple') {
81 $widthstyle = ' style="width:auto;" ';
84 $this->table = new html_table();
85 $this->table->id = "grade_edit_tree_table";
86 $this->table->cellpadding = 5;
87 $this->table->attributes['class'] = 'generaltable ' . $mode;
88 $this->table->style = $widthstyle;
90 foreach ($this->columns as $column) {
91 if (!($this->moving && $column->hide_when_moving) && !$column->is_hidden($mode)) {
92 $this->table->head[] = $column->get_header_cell();
97 $this->table->data = $this->build_html_tree($this->gtree->top_element, true, array(), 0, $rowcount);
101 * Recursive function for building the table holding the grade categories and items,
102 * with CSS indentation and styles.
104 * @param array $element The current tree element being rendered
105 * @param boolean $totals Whether or not to print category grade items (category totals)
106 * @param array $parents An array of parent categories for the current element (used for indentation and row classes)
108 * @return string HTML
110 public function build_html_tree($element, $totals, $parents, $level, &$row_count) {
111 global $CFG, $COURSE, $USER, $OUTPUT;
113 $object = $element['object'];
114 $eid = $element['eid'];
115 $object->name = $this->gtree->get_element_header($element, true, true, false);
116 $object->stripped_name = $this->gtree->get_element_header($element, false, false, false);
118 $is_category_item = false;
119 if ($element['type'] == 'categoryitem' || $element['type'] == 'courseitem') {
120 $is_category_item = true;
123 $rowclasses = array();
124 foreach ($parents as $parent_eid) {
125 $rowclasses[] = $parent_eid;
130 if (!$is_category_item) {
131 $actions .= $this->gtree->get_edit_icon($element, $this->gpr);
134 $actions .= $this->gtree->get_calculation_icon($element, $this->gpr);
136 if ($element['type'] == 'item' or ($element['type'] == 'category' and $element['depth'] > 1)) {
137 if ($this->element_deletable($element)) {
138 $aurl = new moodle_url('index.php', array('id' => $COURSE->id, 'action' => 'delete', 'eid' => $eid, 'sesskey' => sesskey()));
139 $actions .= $OUTPUT->action_icon($aurl, new pix_icon('t/delete', get_string('delete')));
142 $aurl = new moodle_url('index.php', array('id' => $COURSE->id, 'action' => 'moveselect', 'eid' => $eid, 'sesskey' => sesskey()));
143 $actions .= $OUTPUT->action_icon($aurl, new pix_icon('t/move', get_string('move')));
146 $actions .= $this->gtree->get_hiding_icon($element, $this->gpr);
147 $actions .= $this->gtree->get_locking_icon($element, $this->gpr);
149 $mode = ($USER->gradeediting[$COURSE->id]) ? 'advanced' : 'simple';
151 $returnrows = array();
154 $id = required_param('id', PARAM_INT);
156 /// prepare move target if needed
159 /// print the list items now
160 if ($this->moving == $eid) {
161 // do not diplay children
162 $cell = new html_table_cell();
164 $cell->attributes['class'] = $element['type'] . ' moving';
165 $cell->text = $object->name.' ('.get_string('move').')';
166 return array(new html_table_row(array($cell)));
169 if ($element['type'] == 'category') {
171 $this->categories[$object->id] = $object->stripped_name;
172 $category = grade_category::fetch(array('id' => $object->id));
173 $item = $category->get_grade_item();
175 // Add aggregation coef input if not a course item and if parent category has correct aggregation type
176 $dimmed = ($item->is_hidden()) ? 'dimmed' : '';
178 // Before we print the category's row, we must find out how many rows will appear below it (for the filler cell's rowspan)
179 $aggregation_position = grade_get_setting($COURSE->id, 'aggregationposition', $CFG->grade_aggregationposition);
180 $category_total_data = null; // Used if aggregationposition is set to "last", so we can print it last
182 $html_children = array();
186 foreach($element['children'] as $child_el) {
189 if (empty($child_el['object']->itemtype)) {
190 $child_el['object']->itemtype = false;
193 if (($child_el['object']->itemtype == 'course' || $child_el['object']->itemtype == 'category') && !$totals) {
197 $child_eid = $child_el['eid'];
200 if ($child_el['object']->itemtype == 'course' || $child_el['object']->itemtype == 'category') {
201 $first = array('first' => 1);
205 if ($this->moving && $this->moving != $child_eid) {
207 $strmove = get_string('move');
208 $strmovehere = get_string('movehere');
209 $actions = ''; // no action icons when moving
211 $aurl = new moodle_url('index.php', array('id' => $COURSE->id, 'action' => 'move', 'eid' => $this->moving, 'moveafter' => $child_eid, 'sesskey' => sesskey()));
213 $aurl->params($first);
216 $cell = new html_table_cell();
219 $icon = new pix_icon('movehere', $strmovehere, null, array('class'=>'movetarget'));
220 $cell->text = $OUTPUT->action_icon($aurl, $icon);
222 $moveto = new html_table_row(array($cell));
225 $newparents = $parents;
226 $newparents[] = $eid;
229 $child_row_count = 0;
231 // If moving, do not print course and category totals, but still print the moveto target box
232 if ($this->moving && ($child_el['object']->itemtype == 'course' || $child_el['object']->itemtype == 'category')) {
233 $html_children[] = $moveto;
234 } elseif ($child_el['object']->itemtype == 'course' || $child_el['object']->itemtype == 'category') {
235 // We don't build the item yet because we first need to know the deepest level of categories (for category/name colspans)
236 $category_total_item = $this->build_html_tree($child_el, $totals, $newparents, $level, $child_row_count);
237 if (!$aggregation_position) {
238 $html_children = array_merge($html_children, $category_total_item);
241 $html_children = array_merge($html_children, $this->build_html_tree($child_el, $totals, $newparents, $level, $child_row_count));
242 if (!empty($moveto)) {
243 $html_children[] = $moveto;
251 $row_count += $child_row_count;
253 // If the child is a category, increment row_count by one more (for the extra coloured row)
254 if ($child_el['type'] == 'category') {
259 // Print category total at the end if aggregation position is "last" (1)
260 if (!empty($category_total_item) && $aggregation_position) {
261 $html_children = array_merge($html_children, $category_total_item);
264 // Determine if we are at the root
265 if (isset($element['object']->grade_item) && $element['object']->grade_item->is_course_item()) {
269 $row_count_offset = 0;
271 if (empty($category_total_item) && !$this->moving) {
272 $row_count_offset = -1;
275 $levelclass = "level$level";
279 $courseclass = 'coursecategory';
282 $row = new html_table_row();
283 $row->attributes['class'] = $courseclass . ' category ' . $dimmed;
284 foreach ($rowclasses as $class) {
285 $row->attributes['class'] .= ' ' . $class;
288 $headercell = new html_table_cell();
289 $headercell->header = true;
290 $headercell->scope = 'row';
291 $headercell->attributes['title'] = $object->stripped_name;
292 $headercell->attributes['class'] = 'cell rowspan ' . $levelclass;
293 $headercell->rowspan = $row_count+1+$row_count_offset;
294 $row->cells[] = $headercell;
296 foreach ($this->columns as $column) {
297 if (!($this->moving && $column->hide_when_moving) && !$column->is_hidden($mode)) {
298 $row->cells[] = $column->get_category_cell($category, $levelclass, array('id' => $id, 'name' => $object->name, 'level' => $level, 'actions' => $actions, 'eid' => $eid));
302 $returnrows[] = $row;
304 $returnrows = array_merge($returnrows, $html_children);
306 // Print a coloured row to show the end of the category accross the table
307 $endcell = new html_table_cell();
308 $endcell->colspan = (19 - $level);
309 $endcell->attributes['class'] = 'colspan ' . $levelclass;
311 $returnrows[] = new html_table_row(array($endcell));;
313 } else { // Dealing with a grade item
315 $item = grade_item::fetch(array('id' => $object->id));
316 $element['type'] = 'item';
317 $element['object'] = $item;
319 $categoryitemclass = '';
320 if ($item->itemtype == 'category') {
321 $categoryitemclass = 'categoryitem';
324 $dimmed = ($item->is_hidden()) ? "dimmed_text" : "";
325 $gradeitemrow = new html_table_row();
326 $gradeitemrow->attributes['class'] = $categoryitemclass . ' item ' . $dimmed;
327 foreach ($rowclasses as $class) {
328 $gradeitemrow->attributes['class'] .= ' ' . $class;
331 foreach ($this->columns as $column) {
332 if (!($this->moving && $column->hide_when_moving) && !$column->is_hidden($mode)) {
333 $gradeitemrow->cells[] = $column->get_item_cell($item, array('id' => $id, 'name' => $object->name, 'level' => $level, 'actions' => $actions,
334 'element' => $element, 'eid' => $eid, 'itemtype' => $object->itemtype));
338 $returnrows[] = $gradeitemrow;
346 * Given a grade_item object, returns a labelled input if an aggregation coefficient (weight or extra credit) applies to it.
347 * @param grade_item $item
348 * @param string type "extra" or "weight": the type of the column hosting the weight input
349 * @return string HTML
351 function get_weight_input($item, $type) {
354 if (!is_object($item) || get_class($item) !== 'grade_item') {
355 throw new Exception('grade_edit_tree::get_weight_input($item) was given a variable that is not of the required type (grade_item object)');
359 if ($item->is_course_item()) {
363 $parent_category = $item->get_parent_category();
364 $parent_category->apply_forced_settings();
365 $aggcoef = $item->get_coefstring();
367 if ((($aggcoef == 'aggregationcoefweight' || $aggcoef == 'aggregationcoef') && $type == 'weight') ||
368 ($aggcoef == 'aggregationcoefextraweight' && $type == 'extra')) {
369 return '<input type="text" size="6" id="aggregationcoef_'.$item->id.'" name="aggregationcoef_'.$item->id.'"
370 value="'.grade_edit_tree::format_number($item->aggregationcoef).'" />';
371 } elseif ($aggcoef == 'aggregationcoefextrasum' && $type == 'extra') {
372 $checked = ($item->aggregationcoef > 0) ? 'checked="checked"' : '';
373 return '<input type="hidden" name="extracredit_'.$item->id.'" value="0" />
374 <input type="checkbox" id="extracredit_'.$item->id.'" name="extracredit_'.$item->id.'" value="1" '."$checked />\n";
380 //Trim's trailing zeros
381 //Used on the 'categories and items' page for grade items settings like aggregation co-efficient
382 //Grader report has its own decimal place settings so they are handled elsewhere
383 function format_number($number) {
384 $formatted = rtrim(format_float($number, 4),'0');
385 if (substr($formatted, -1)=='.') { //if last char is the decimal point
392 * Given an element of the grade tree, returns whether it is deletable or not (only manual grade items are deletable)
394 * @param array $element
397 function element_deletable($element) {
400 if ($element['type'] != 'item') {
404 $grade_item = $element['object'];
406 if ($grade_item->itemtype != 'mod' or $grade_item->is_outcome_item() or $grade_item->gradetype == GRADE_TYPE_NONE) {
410 $modinfo = get_fast_modinfo($COURSE);
411 if (!isset($modinfo->instances[$grade_item->itemmodule][$grade_item->iteminstance])) {
412 // module does not exist
420 * Given the grade tree and an array of element ids (e.g. c15, i42), and expecting the 'moveafter' URL param,
421 * moves the selected items to the requested location. Then redirects the user to the given $returnurl
423 * @param object $gtree The grade tree (a recursive representation of the grade categories and grade items)
425 * @param string $returnurl
427 function move_elements($eids, $returnurl) {
428 $moveafter = required_param('moveafter', PARAM_INT);
430 if (!is_array($eids)) {
431 $eids = array($eids);
434 if(!$after_el = $this->gtree->locate_element("c$moveafter")) {
435 print_error('invalidelementid', '', $returnurl);
438 $after = $after_el['object'];
440 $sortorder = $after->get_sortorder();
442 foreach ($eids as $eid) {
443 if (!$element = $this->gtree->locate_element($eid)) {
444 print_error('invalidelementid', '', $returnurl);
446 $object = $element['object'];
448 $object->set_parent($parent->id);
449 $object->move_after_sortorder($sortorder);
453 redirect($returnurl, '', 0);
457 * Recurses through the entire grade tree to find and return the maximum depth of the tree.
458 * This should be run only once from the root element (course category), and is used for the
459 * indentation of the Name column's cells (colspan)
461 * @param array $element An array of values representing a grade tree's element (all grade items in this case)
462 * @param int $level The level of the current recursion
463 * @param int $deepest_level A value passed to each subsequent level of recursion and incremented if $level > $deepest_level
464 * @return int Deepest level
466 function get_deepest_level($element, $level=0, $deepest_level=1) {
467 $object = $element['object'];
470 $coefstring = $element['object']->get_coefstring();
471 if ($element['type'] == 'category') {
472 if ($coefstring == 'aggregationcoefweight') {
473 $this->uses_weight = true;
474 } elseif ($coefstring == 'aggregationcoefextraweight' || $coefstring == 'aggregationcoefextrasum') {
475 $this->uses_extra_credit = true;
478 foreach($element['children'] as $child_el) {
479 if ($level > $deepest_level) {
480 $deepest_level = $level;
482 $deepest_level = $this->get_deepest_level($child_el, $level, $deepest_level);
486 return $deepest_level;
490 abstract class grade_edit_tree_column {
493 public $forced_hidden;
494 public $advanced_hidden;
495 public $hide_when_moving = true;
497 * html_table_cell object used as a template for header cells in all categories.
498 * It must be cloned before being used.
499 * @var html_table_cell $headercell
503 * html_table_cell object used as a template for category cells in all categories.
504 * It must be cloned before being used.
505 * @var html_table_cell $categorycell
507 public $categorycell;
509 * html_table_cell object used as a template for item cells in all categories.
510 * It must be cloned before being used.
511 * @var html_table_cell $itemcell
515 public static function factory($name, $params=array()) {
516 $class_name = "grade_edit_tree_column_$name";
517 if (class_exists($class_name)) {
518 return new $class_name($params);
522 public abstract function get_header_cell();
524 public abstract function get_category_cell($category, $levelclass, $params);
526 public abstract function get_item_cell($item, $params);
528 public abstract function is_hidden($mode='simple');
530 public function __construct() {
531 $this->headercell = new html_table_cell();
532 $this->headercell->header = true;
533 $this->headercell->style = 'whitespace: normal;';
534 $this->headercell->attributes['class'] = 'header';
536 $this->categorycell = new html_table_cell();
537 $this->categorycell->attributes['class'] = 'cell';
539 $this->itemcell = new html_table_cell();
540 $this->itemcell->attributes['class'] = 'cell';
544 abstract class grade_edit_tree_column_category extends grade_edit_tree_column {
549 public function __construct($name) {
551 $this->forced = (int)$CFG->{"grade_$name"."_flag"} & 1;
552 $this->advanced = (int)$CFG->{"grade_$name"."_flag"} & 2;
553 parent::__construct();
556 public function is_hidden($mode='simple') {
558 if ($mode == 'simple') {
559 return $this->advanced;
560 } elseif ($mode == 'advanced') {
561 if ($this->forced && $CFG->grade_hideforcedsettings) {
570 class grade_edit_tree_column_name extends grade_edit_tree_column {
571 public $forced = false;
572 public $hidden = false;
573 public $forced_hidden = false;
574 public $advanced_hidden = false;
575 public $deepest_level = 1;
576 public $hide_when_moving = false;
578 public function __construct($params) {
579 if (empty($params['deepest_level'])) {
580 throw new Exception('Tried to instantiate a grade_edit_tree_column_name object without the "deepest_level" param!');
583 $this->deepest_level = $params['deepest_level'];
584 parent::__construct();
587 public function get_header_cell() {
588 $headercell = clone($this->headercell);
589 $headercell->attributes['class'] .= ' name';
590 $headercell->colspan = $this->deepest_level + 1;
591 $headercell->text = get_string('name');
595 public function get_category_cell($category, $levelclass, $params) {
597 if (empty($params['name']) || empty($params['level'])) {
598 throw new Exception('Array key (name or level) missing from 3rd param of grade_edit_tree_column_name::get_category_cell($category, $levelclass, $params)');
600 $categorycell = clone($this->categorycell);
601 $categorycell->attributes['class'] .= ' name ' . $levelclass;
602 $categorycell->colspan = ($this->deepest_level +1) - $params['level'];
603 $categorycell->text = $OUTPUT->heading($params['name'], 4);
604 return $categorycell;
607 public function get_item_cell($item, $params) {
610 if (empty($params['element']) || empty($params['name']) || empty($params['level'])) {
611 throw new Exception('Array key (name, level or element) missing from 2nd param of grade_edit_tree_column_name::get_item_cell($item, $params)');
614 $name = $params['name'];
616 $itemcell = clone($this->itemcell);
617 $itemcell->attributes['class'] .= ' name';
618 $itemcell->colspan = ($this->deepest_level + 1) - $params['level'];
619 $itemcell->text = $name;
623 public function is_hidden($mode='simple') {
628 class grade_edit_tree_column_aggregation extends grade_edit_tree_column_category {
630 public function __construct($params) {
631 parent::__construct('aggregation');
634 public function get_header_cell() {
636 $headercell = clone($this->headercell);
637 $headercell->text = get_string('aggregation', 'grades').$OUTPUT->help_icon('aggregation', 'grades');
641 public function get_category_cell($category, $levelclass, $params) {
642 global $CFG, $OUTPUT;
643 if (empty($params['id'])) {
644 throw new Exception('Array key (id) missing from 3rd param of grade_edit_tree_column_aggregation::get_category_cell($category, $levelclass, $params)');
647 $options = array(GRADE_AGGREGATE_MEAN => get_string('aggregatemean', 'grades'),
648 GRADE_AGGREGATE_WEIGHTED_MEAN => get_string('aggregateweightedmean', 'grades'),
649 GRADE_AGGREGATE_WEIGHTED_MEAN2 => get_string('aggregateweightedmean2', 'grades'),
650 GRADE_AGGREGATE_EXTRACREDIT_MEAN => get_string('aggregateextracreditmean', 'grades'),
651 GRADE_AGGREGATE_MEDIAN => get_string('aggregatemedian', 'grades'),
652 GRADE_AGGREGATE_MIN => get_string('aggregatemin', 'grades'),
653 GRADE_AGGREGATE_MAX => get_string('aggregatemax', 'grades'),
654 GRADE_AGGREGATE_MODE => get_string('aggregatemode', 'grades'),
655 GRADE_AGGREGATE_SUM => get_string('aggregatesum', 'grades'));
657 $visible = explode(',', $CFG->grade_aggregations_visible);
658 foreach ($options as $constant => $string) {
659 if (!in_array($constant, $visible) && $constant != $category->aggregation) {
660 unset($options[$constant]);
665 $aggregation = $options[$category->aggregation];
667 $attributes = array();
668 $attributes['id'] = 'aggregation_'.$category->id;
669 $aggregation = html_writer::select($options, 'aggregation_'.$category->id, $category->aggregation, null, $attributes);
670 $action = new component_action('change', 'update_category_aggregation', array('courseid' => $params['id'], 'category' => $category->id, 'sesskey' => sesskey()));
671 $OUTPUT->add_action_handler($action, 'aggregation_'.$category->id);
674 $categorycell = clone($this->categorycell);
675 $categorycell->attributes['class'] .= ' ' . $levelclass;
676 $categorycell->text = $aggregation;
677 return $categorycell;
681 public function get_item_cell($item, $params) {
682 $itemcell = clone($this->itemcell);
683 $itemcell->text = ' - ';
688 class grade_edit_tree_column_extracredit extends grade_edit_tree_column {
690 public function get_header_cell() {
692 $headercell = clone($this->headercell);
693 $headercell->text = get_string('aggregationcoefextra', 'grades').$OUTPUT->help_icon('aggregationcoefextra', 'grades');
697 public function get_category_cell($category, $levelclass, $params) {
698 $item = $category->get_grade_item();
699 $categorycell = clone($this->categorycell);
700 $categorycell->attributes['class'] .= ' ' . $levelclass;
701 $categorycell->text = grade_edit_tree::get_weight_input($item, 'extra');
702 return $categorycell;
705 public function get_item_cell($item, $params) {
706 if (empty($params['element'])) {
707 throw new Exception('Array key (element) missing from 2nd param of grade_edit_tree_column_weightorextracredit::get_item_cell($item, $params)');
710 $itemcell = clone($this->itemcell);
711 $itemcell->text = ' ';
713 if (!in_array($params['element']['object']->itemtype, array('courseitem', 'categoryitem', 'category'))) {
714 $itemcell->text = grade_edit_tree::get_weight_input($item, 'extra');
720 public function is_hidden($mode='simple') {
722 if ($mode == 'simple') {
723 return strstr($CFG->grade_item_advanced, 'aggregationcoef');
724 } elseif ($mode == 'advanced') {
730 class grade_edit_tree_column_weight extends grade_edit_tree_column {
732 public function get_header_cell() {
734 $headercell = clone($this->headercell);
735 $headercell->text = get_string('weightuc', 'grades').$OUTPUT->help_icon('aggregationcoefweight', 'grades');
739 public function get_category_cell($category, $levelclass, $params) {
741 $item = $category->get_grade_item();
742 $categorycell = clone($this->categorycell);
743 $categorycell->attributes['class'] .= ' ' . $levelclass;
744 $categorycell->text = grade_edit_tree::get_weight_input($item, 'weight');
745 return $categorycell;
748 public function get_item_cell($item, $params) {
749 if (empty($params['element'])) {
750 throw new Exception('Array key (element) missing from 2nd param of grade_edit_tree_column_weightorextracredit::get_item_cell($item, $params)');
752 $itemcell = clone($this->itemcell);
753 $itemcell->text = ' ';
755 if (!in_array($params['element']['object']->itemtype, array('courseitem', 'categoryitem', 'category'))) {
756 $itemcell->text = grade_edit_tree::get_weight_input($item, 'weight');
762 public function is_hidden($mode='simple') {
764 if ($mode == 'simple') {
765 return strstr($CFG->grade_item_advanced, 'aggregationcoef');
766 } elseif ($mode == 'advanced') {
772 class grade_edit_tree_column_range extends grade_edit_tree_column {
774 public function get_header_cell() {
775 $headercell = clone($this->headercell);
776 $headercell->text = get_string('maxgrade', 'grades');
780 public function get_category_cell($category, $levelclass, $params) {
781 $categorycell = clone($this->categorycell);
782 $categorycell->attributes['class'] .= ' range ' . $levelclass;
783 $categorycell->text = ' - ';
784 return $categorycell;
787 public function get_item_cell($item, $params) {
790 // If the parent aggregation is Sum of Grades, this cannot be changed
791 $parent_cat = $item->get_parent_category();
792 if ($parent_cat->aggregation == GRADE_AGGREGATE_SUM) {
793 $grademax = format_float($item->grademax, $item->get_decimals());
794 } elseif ($item->gradetype == GRADE_TYPE_SCALE) {
795 $scale = $DB->get_record('scale', array('id' => $item->scaleid));
796 $scale_items = explode(',', $scale->scale);
797 $grademax = end($scale_items) . ' (' . count($scale_items) . ')';
798 } elseif ($item->is_external_item()) {
799 $grademax = format_float($item->grademax, $item->get_decimals());
801 $grademax = '<input type="text" size="4" id="grademax'.$item->id.'" name="grademax_'.$item->id.'" value="'.format_float($item->grademax, $item->get_decimals()).'" />';
804 $itemcell = clone($this->itemcell);
805 $itemcell->text = $grademax;
809 public function is_hidden($mode='simple') {
811 if ($mode == 'simple') {
812 return strstr($CFG->grade_item_advanced, 'grademax');
813 } elseif ($mode == 'advanced') {
819 class grade_edit_tree_column_aggregateonlygraded extends grade_edit_tree_column_category {
821 public function __construct($params) {
822 parent::__construct('aggregateonlygraded');
825 public function get_header_cell() {
827 $headercell = clone($this->headercell);
828 $headercell->style .= 'width: 40px;';
829 $headercell->text = get_string('aggregateonlygraded', 'grades')
830 . $OUTPUT->help_icon('aggregateonlygraded', 'grades');
834 public function get_category_cell($category, $levelclass, $params) {
835 $onlygradedcheck = ($category->aggregateonlygraded == 1) ? 'checked="checked"' : '';
836 $hidden = '<input type="hidden" name="aggregateonlygraded_'.$category->id.'" value="0" />';
837 $aggregateonlygraded ='<input type="checkbox" id="aggregateonlygraded_'.$category->id.'" name="aggregateonlygraded_'.$category->id.'" value="1" '.$onlygradedcheck . ' />';
840 $aggregateonlygraded = ($category->aggregateonlygraded) ? get_string('yes') : get_string('no');
843 $categorycell = clone($this->categorycell);
844 $categorycell->attributes['class'] .= ' ' . $levelclass;
845 $categorycell->text = $hidden.$aggregateonlygraded;
846 return $categorycell;
849 public function get_item_cell($item, $params) {
850 $itemcell = clone($this->itemcell);
851 $itemcell->text = ' - ';
856 class grade_edit_tree_column_aggregatesubcats extends grade_edit_tree_column_category {
858 public function __construct($params) {
859 parent::__construct('aggregatesubcats');
862 public function get_header_cell() {
864 $headercell = clone($this->headercell);
865 $headercell->style .= 'width: 40px;';
866 $headercell->text = get_string('aggregatesubcats', 'grades')
867 .$OUTPUT->old_help_icon('aggregatesubcats', 'aggregatesubcats', 'grade');
871 public function get_category_cell($category, $levelclass, $params) {
872 $subcatscheck = ($category->aggregatesubcats == 1) ? 'checked="checked"' : '';
873 $hidden = '<input type="hidden" name="aggregatesubcats_'.$category->id.'" value="0" />';
874 $aggregatesubcats = '<input type="checkbox" id="aggregatesubcats_'.$category->id.'" name="aggregatesubcats_'.$category->id.'" value="1" ' . $subcatscheck.' />';
877 $aggregatesubcats = ($category->aggregatesubcats) ? get_string('yes') : get_string('no');
880 $categorycell = clone($this->categorycell);
881 $categorycell->attributes['class'] .= ' ' . $levelclass;
882 $categorycell->text = $hidden.$aggregatesubcats;
883 return $categorycell;
887 public function get_item_cell($item, $params) {
888 $itemcell = clone($this->itemcell);
889 $itemcell->text = ' - ';
894 class grade_edit_tree_column_aggregateoutcomes extends grade_edit_tree_column_category {
896 public function __construct($params) {
897 parent::__construct('aggregateoutcomes');
900 public function get_header_cell() {
902 $headercell = clone($this->headercell);
903 $headercell->style .= 'width: 40px;';
904 $headercell->text = get_string('aggregateoutcomes', 'grades')
905 .$OUTPUT->help_icon('aggregateoutcomes', 'grades');
909 public function get_category_cell($category, $levelclass, $params) {
910 $outcomescheck = ($category->aggregateoutcomes == 1) ? 'checked="checked"' : '';
911 $hidden = '<input type="hidden" name="aggregateoutcomes_'.$category->id.'" value="0" />';
912 $aggregateoutcomes = '<input type="checkbox" id="aggregateoutcomes_'.$category->id.'" name="aggregateoutcomes_'.$category->id.'" value="1" ' . $outcomescheck.' />';
915 $aggregateoutcomes = ($category->aggregateoutcomes) ? get_string('yes') : get_string('no');
918 $categorycell = clone($this->categorycell);
919 $categorycell->attributes['class'] .= ' ' . $levelclass;
920 $categorycell->text = $hidden.$aggregateoutcomes;
921 return $categorycell;
924 public function get_item_cell($item, $params) {
925 $itemcell = clone($this->itemcell);
926 $itemcell->text = ' - ';
930 public function is_hidden($mode='simple') {
932 if ($CFG->enableoutcomes) {
933 return parent::is_hidden($mode);
940 class grade_edit_tree_column_droplow extends grade_edit_tree_column_category {
942 public function __construct($params) {
943 parent::__construct('droplow');
946 public function get_header_cell() {
948 $headercell = clone($this->headercell);
949 $headercell->text = get_string('droplow', 'grades').$OUTPUT->help_icon('droplow', 'grades');
953 public function get_category_cell($category, $levelclass, $params) {
954 $droplow = '<input type="text" size="3" id="droplow_'.$category->id.'" name="droplow_'.$category->id.'" value="'.$category->droplow.'" />';
957 $droplow = $category->droplow;
960 $categorycell = clone($this->categorycell);
961 $categorycell->attributes['class'] .= ' ' . $levelclass;
962 $categorycell->text = $droplow;
963 return $categorycell;
966 public function get_item_cell($item, $params) {
967 $itemcell = clone($this->itemcell);
968 $itemcell->text = ' - ';
973 class grade_edit_tree_column_keephigh extends grade_edit_tree_column_category {
975 public function __construct($params) {
976 parent::__construct('keephigh');
979 public function get_header_cell() {
981 $headercell = clone($this->headercell);
982 $headercell->text = get_string('keephigh', 'grades').$OUTPUT->old_help_icon('keephigh', 'keephigh', 'grade');
986 public function get_category_cell($category, $levelclass, $params) {
987 $keephigh = '<input type="text" size="3" id="keephigh_'.$category->id.'" name="keephigh_'.$category->id.'" value="'.$category->keephigh.'" />';
990 $keephigh = $category->keephigh;
993 $categorycell = clone($this->categorycell);
994 $categorycell->attributes['class'] .= ' ' . $levelclass;
995 $categorycell->text = $keephigh;
996 return $categorycell;
999 public function get_item_cell($item, $params) {
1000 $itemcell = clone($this->itemcell);
1001 $itemcell->text = ' - ';
1006 class grade_edit_tree_column_multfactor extends grade_edit_tree_column {
1008 public function __construct($params) {
1009 parent::__construct();
1012 public function get_header_cell() {
1014 $headercell = clone($this->headercell);
1015 $headercell->text = get_string('multfactor', 'grades').$OUTPUT->help_icon('multfactor', 'grades');
1019 public function get_category_cell($category, $levelclass, $params) {
1020 $categorycell = clone($this->categorycell);
1021 $categorycell->attributes['class'] .= ' ' . $levelclass;
1022 $categorycell->text = ' - ';
1023 return $categorycell;
1026 public function get_item_cell($item, $params) {
1029 $itemcell = clone($this->itemcell);
1030 if (!$item->is_raw_used()) {
1031 $itemcell->text = ' ';
1035 $multfactor = '<input type="text" size="4" id="multfactor'.$item->id.'" name="multfactor_'.$item->id.'" value="'.grade_edit_tree::format_number($item->multfactor).'" />';
1037 $itemcell->text = $multfactor;
1041 public function is_hidden($mode='simple') {
1043 if ($mode == 'simple') {
1044 return strstr($CFG->grade_item_advanced, 'multfactor');
1045 } elseif ($mode == 'advanced') {
1051 class grade_edit_tree_column_plusfactor extends grade_edit_tree_column {
1053 public function get_header_cell() {
1055 $headercell = clone($this->headercell);
1056 $headercell->text = get_string('plusfactor', 'grades').$OUTPUT->help_icon('plusfactor', 'grades');
1060 public function get_category_cell($category, $levelclass, $params) {
1061 $categorycell = clone($this->categorycell);
1062 $categorycell->attributes['class'] .= ' ' . $levelclass;
1063 $categorycell->text = ' - ';
1064 return $categorycell;
1068 public function get_item_cell($item, $params) {
1071 $itemcell = clone($this->itemcell);
1072 if (!$item->is_raw_used()) {
1073 $itemcell->text = ' ';
1077 $plusfactor = '<input type="text" size="4" id="plusfactor_'.$item->id.'" name="plusfactor_'.$item->id.'" value="'.grade_edit_tree::format_number($item->plusfactor).'" />';
1079 $itemcell->text = $plusfactor;
1084 public function is_hidden($mode='simple') {
1086 if ($mode == 'simple') {
1087 return strstr($CFG->grade_item_advanced, 'plusfactor');
1088 } elseif ($mode == 'advanced') {
1094 class grade_edit_tree_column_actions extends grade_edit_tree_column {
1096 public function __construct($params) {
1097 parent::__construct();
1100 public function get_header_cell() {
1101 $headercell = clone($this->headercell);
1102 $headercell->attributes['class'] .= ' actions';
1103 $headercell->text = get_string('actions');
1107 public function get_category_cell($category, $levelclass, $params) {
1109 if (empty($params['actions'])) {
1110 throw new Exception('Array key (actions) missing from 3rd param of grade_edit_tree_column_actions::get_category_actions($category, $levelclass, $params)');
1113 $categorycell = clone($this->categorycell);
1114 $categorycell->attributes['class'] .= ' ' . $levelclass;
1115 $categorycell->text = $params['actions'];
1116 return $categorycell;
1119 public function get_item_cell($item, $params) {
1120 if (empty($params['actions'])) {
1121 throw new Exception('Array key (actions) missing from 2nd param of grade_edit_tree_column_actions::get_item_cell($item, $params)');
1123 $itemcell = clone($this->itemcell);
1124 $itemcell->attributes['class'] .= ' actions';
1125 $itemcell->text = $params['actions'];
1129 public function is_hidden($mode='simple') {
1134 class grade_edit_tree_column_select extends grade_edit_tree_column {
1136 public function get_header_cell() {
1137 $headercell = clone($this->headercell);
1138 $headercell->attributes['class'] .= ' selection';
1139 $headercell->text = get_string('select');
1143 public function get_category_cell($category, $levelclass, $params) {
1145 if (empty($params['eid'])) {
1146 throw new Exception('Array key (eid) missing from 3rd param of grade_edit_tree_column_select::get_category_cell($category, $levelclass, $params)');
1148 $selectall = new action_link(new moodle_url('#'), get_string('all'), new component_action('click', 'togglecheckboxes', array('eid' => $params['eid'], 'check' => true)));
1149 $selectnone = new action_link(new moodle_url('#'), get_string('none'), new component_action('click', 'togglecheckboxes', array('eid' => $params['eid'], 'check' => false)));
1151 $categorycell = clone($this->categorycell);
1152 $categorycell->attributes['class'] .= ' last ' . $levelclass;
1153 $categorycell->style .= 'text-align: center;';
1154 $categorycell->text = $OUTPUT->render($selectall) . '<br />' . $OUTPUT->render($selectnone);
1155 return $categorycell;
1158 public function get_item_cell($item, $params) {
1159 if (empty($params['itemtype']) || empty($params['eid'])) {
1160 error('Array key (itemtype or eid) missing from 2nd param of grade_edit_tree_column_select::get_item_cell($item, $params)');
1164 if ($params['itemtype'] != 'course' && $params['itemtype'] != 'category') {
1165 $itemselect = '<input class="itemselect" type="checkbox" name="select_'.$params['eid'].'" onchange="toggleCategorySelector();"/>'; // TODO: convert to YUI handler
1167 return '<td class="cell last selection">' . $itemselect . '</td>';
1170 public function is_hidden($mode='simple') {