Automatic installer.php lang files by installer_builder (20070726)
[moodle-linuxchix.git] / grade / lib.php
blob7e4f66f11f69f0840d0ef8d94eec74483c641f44
1 <?php //$Id$
3 require_once $CFG->libdir.'/gradelib.php';
5 /**
6 * Print grading plugin selection popup form.
8 * @param int $courseid id of course
9 * @param string $active_type type of plugin on current page - import, export, report or edit
10 * @param string $active_plugin active plugin type - grader, user, cvs, ...
11 * @param boolean $return return as string
12 * @return nothing or string if $return true
14 function print_grade_plugin_selector($courseid, $active_type, $active_plugin, $return=false) {
15 global $CFG;
17 $context = get_context_instance(CONTEXT_COURSE, $courseid);
19 $menu = array();
21 $active = '';
23 /// report plugins with its special structure
24 if ($reports = get_list_of_plugins('grade/report', 'CVS')) { // Get all installed reports
25 foreach ($reports as $key => $plugin) { // Remove ones we can't see
26 if (!has_capability('gradereport/'.$plugin.':view', $context)) {
27 unset($reports[$key]);
31 $reportnames = array();
32 if (!empty($reports)) {
33 foreach ($reports as $plugin) {
34 $url = 'report/'.$plugin.'/index.php?id='.$courseid;
35 if ($active_type == 'report' and $active_plugin == $plugin ) {
36 $active = $url;
38 $reportnames[$url] = get_string('modulename', 'gradereport_'.$plugin, NULL, $CFG->dirroot.'/grade/report/'.$plugin.'lang/');
40 asort($reportnames);
42 if (!empty($reportnames)) {
43 $menu['reportgroup']='--'.get_string('reportplugins', 'grades');
44 $menu = $menu+$reportnames;
47 /// standard import plugins
48 if ($imports = get_list_of_plugins('grade/import', 'CVS')) { // Get all installed import plugins
49 foreach ($imports as $key => $plugin) { // Remove ones we can't see
50 if (!has_capability('gradeimport/'.$plugin.':view', $context)) {
51 unset($imports[$key]);
55 $importnames = array();
56 if (!empty($imports)) {
57 foreach ($imports as $plugin) {
58 $url = 'import/'.$plugin.'/index.php?id='.$courseid;
59 if ($active_type == 'import' and $active_plugin == $plugin ) {
60 $active = $url;
62 $importnames[$url] = get_string('modulename', 'gradeimport_'.$plugin, NULL, $CFG->dirroot.'/grade/import/'.$plugin.'lang/');
64 asort($importnames);
66 if (!empty($importnames)) {
67 $menu['importgroup']='--'.get_string('importplugins', 'grades');
68 $menu = $menu+$importnames;
71 /// standard export plugins
72 if ($exports = get_list_of_plugins('grade/export', 'CVS')) { // Get all installed export plugins
73 foreach ($exports as $key => $plugin) { // Remove ones we can't see
74 if (!has_capability('gradeexport/'.$plugin.':view', $context)) {
75 unset($exports[$key]);
79 $exportnames = array();
80 if (!empty($exports)) {
81 foreach ($exports as $plugin) {
82 $url = 'export/'.$plugin.'/index.php?id='.$courseid;
83 if ($active_type == 'export' and $active_plugin == $plugin ) {
84 $active = $url;
86 $exportnames[$url] = get_string('modulename', 'gradeexport_'.$plugin, NULL, $CFG->dirroot.'/grade/export/'.$plugin.'lang/');
88 asort($exportnames);
90 if (!empty($exportnames)) {
91 $menu['exportgroup']='--'.get_string('exportplugins', 'grades');
92 $menu = $menu+$exportnames;
95 /// editing scripts - not real plugins
96 if (has_capability('moodle/grade:manage', $context)) {
97 $menu['edit']='--'.get_string('edit');
98 $url = 'edit/tree.php?id='.$courseid;
99 if ($active_type == 'edit' and $active_plugin == 'tree' ) {
100 $active = $url;
102 $menu[$url] = get_string('edittree', 'grades');
105 /// finally print/return the popup form
106 return popup_form($CFG->wwwroot.'/grade/', $menu, 'choosepluginreport', $active, 'choose', '', '', $return, 'self', get_string('view'));
110 * Utility class used for return tracking when using edit and other forms in grade plugins
112 class grade_plugin_return {
113 var $type;
114 var $plugin;
115 var $courseid;
116 var $userid;
117 var $page;
120 * Constructor
121 * @param array $params - associative array with return parameters, if null parameter are taken from _GET or _POST
123 function grade_plugin_return ($params=null) {
124 if (empty($params)) {
125 $this->type = optional_param('gpr_type', null, PARAM_SAFEDIR);
126 $this->plugin = optional_param('gpr_plugin', null, PARAM_SAFEDIR);
127 $this->courseid = optional_param('gpr_courseid', null, PARAM_INT);
128 $this->userid = optional_param('gpr_userid', null, PARAM_INT);
129 $this->page = optional_param('gpr_page', null, PARAM_INT);
131 } else {
132 foreach ($params as $key=>$value) {
133 if (array_key_exists($key, $this)) {
134 $this->$key = $value;
141 * Returns return parameters as options array suitable for buttons.
142 * @return array options
144 function get_options() {
145 if (empty($this->type)) {
146 return array();
149 $params = array();
151 if (!empty($this->plugin)) {
152 $params['plugin'] = $this->plugin;
155 if (!empty($this->courseid)) {
156 $params['id'] = $this->courseid;
159 if (!empty($this->userid)) {
160 $params['userid'] = $this->userid;
163 if (!empty($this->page)) {
164 $params['page'] = $this->page;
167 return $params;
171 * Returns return url
172 * @param string $default default url when params not set
173 * @return string url
175 function get_return_url($default, $extras=null) {
176 global $CFG;
178 if ($this->type == 'edit') {
179 return $CFG->wwwroot.'/grade/edit/tree.php?id='.$this->courseid;
182 if (empty($this->type) or empty($this->plugin)) {
183 return $default;
186 $url = $CFG->wwwroot.'/grade/'.$this->type.'/'.$this->plugin.'/index.php';
187 $glue = '?';
189 if (!empty($this->courseid)) {
190 $url .= $glue.'id='.$this->courseid;
191 $glue = '&amp;';
194 if (!empty($this->userid)) {
195 $url .= $glue.'userid='.$this->userid;
196 $glue = '&amp;';
199 if (!empty($this->page)) {
200 $url .= $glue.'page='.$this->page;
201 $glue = '&amp;';
204 if (!empty($extras)) {
205 foreach($extras as $key=>$value) {
206 $url .= $glue.$key.'='.$value;
207 $glue = '&amp;';
211 return $url;
215 * Returns string with hidden return tracking form elements.
216 * @return string
218 function get_form_fields() {
219 if (empty($this->type)) {
220 return '';
223 $result = '<input type="hidden" name="gpr_type" value="'.$this->type.'" />';
225 if (!empty($this->plugin)) {
226 $result .= '<input type="hidden" name="gpr_plugin" value="'.$this->plugin.'" />';
229 if (!empty($this->courseid)) {
230 $result .= '<input type="hidden" name="gpr_courseid" value="'.$this->courseid.'" />';
233 if (!empty($this->userid)) {
234 $result .= '<input type="hidden" name="gpr_userid" value="'.$this->userid.'" />';
237 if (!empty($this->page)) {
238 $result .= '<input type="hidden" name="gpr_page" value="'.$this->page.'" />';
243 * Add hidden elements into mform
244 * @param object $mform moodle form object
245 * @return void
247 function add_mform_elements(&$mform) {
248 if (empty($this->type)) {
249 return;
252 $mform->addElement('hidden', 'gpr_type', $this->type);
253 $mform->setType('gpr_type', PARAM_SAFEDIR);
255 if (!empty($this->plugin)) {
256 $mform->addElement('hidden', 'gpr_plugin', $this->plugin);
257 $mform->setType('gpr_plugin', PARAM_SAFEDIR);
260 if (!empty($this->courseid)) {
261 $mform->addElement('hidden', 'gpr_courseid', $this->courseid);
262 $mform->setType('gpr_courseid', PARAM_INT);
265 if (!empty($this->userid)) {
266 $mform->addElement('hidden', 'gpr_userid', $this->userid);
267 $mform->setType('gpr_userid', PARAM_INT);
270 if (!empty($this->page)) {
271 $mform->addElement('hidden', 'gpr_page', $this->page);
272 $mform->setType('gpr_page', PARAM_INT);
277 * Add return tracking params into url
278 * @param string $url
279 * @return string $url with erturn tracking params
281 function add_url_params($url) {
282 if (empty($this->type)) {
283 return $url;
286 if (strpos($url, '?') === false) {
287 $url .= '?gpr_type='.$this->type;
288 } else {
289 $url .= '&amp;gpr_type='.$this->type;
292 if (!empty($this->plugin)) {
293 $url .= '&amp;gpr_plugin='.$this->plugin;
296 if (!empty($this->courseid)) {
297 $url .= '&amp;gpr_courseid='.$this->courseid;
300 if (!empty($this->userid)) {
301 $url .= '&amp;gpr_userid='.$this->userid;
304 if (!empty($this->page)) {
305 $url .= '&amp;gpr_page='.$this->page;
308 return $url;
314 * This class represents a complete tree of categories, grade_items and final grades,
315 * organises as an array primarily, but which can also be converted to other formats.
316 * It has simple method calls with complex implementations, allowing for easy insertion,
317 * deletion and moving of items and categories within the tree.
319 class grade_tree {
322 * The basic representation of the tree as a hierarchical, 3-tiered array.
323 * @var object $top_element
325 var $top_element;
328 * A string of GET URL variables, namely courseid and sesskey, used in most URLs built by this class.
329 * @var string $commonvars
331 var $commonvars;
334 * 2D array of grade items and categories
336 var $levels;
339 * Course context
341 var $context;
344 * Constructor, retrieves and stores a hierarchical array of all grade_category and grade_item
345 * objects for the given courseid. Full objects are instantiated.
346 * and renumbering.
347 * @param int $courseid
348 * @param boolean $fillers include fillers and colspans, make the levels var "rectangular"
349 * @param boolean $category_grade_last category grade item is the last child
350 * @param array $collapsed array of collapsed categories
352 function grade_tree($courseid, $fillers=true, $category_grade_last=false, $collapsed=null) {
353 global $USER, $CFG;
355 $this->courseid = $courseid;
356 $this->commonvars = "&amp;sesskey=$USER->sesskey&amp;id=$this->courseid";
357 $this->levels = array();
358 $this->context = get_context_instance(CONTEXT_COURSE, $courseid);
360 // get course grade tree
361 $this->top_element = grade_category::fetch_course_tree($courseid, true);
363 // collapse the categories if requested
364 if (!empty($collapsed)) {
365 grade_tree::category_collapse($this->top_element, $collapsed);
368 // move category item to last position in category
369 if ($category_grade_last) {
370 grade_tree::category_grade_last($this->top_element);
373 if ($fillers) {
374 // inject fake categories == fillers
375 grade_tree::inject_fillers($this->top_element, 0);
376 // add colspans to categories and fillers
377 grade_tree::inject_colspans($this->top_element);
380 grade_tree::fill_levels($this->levels, $this->top_element, 0);
384 * Static recursive helper - removes items from collapsed categories
385 * @static
386 * @param array $element The seed of the recursion
387 * @param array $collapsed array of collapsed categories
388 * @return void
390 function category_collapse(&$element, $collapsed) {
391 if ($element['type'] != 'category') {
392 return;
394 if (empty($element['children']) or count($element['children']) < 2) {
395 return;
398 if (in_array($element['object']->id, $collapsed)) {
399 $category_item = reset($element['children']); //keep only category item
400 $element['children'] = array(key($element['children'])=>$category_item);
402 } else {
403 foreach ($element['children'] as $sortorder=>$child) {
404 grade_tree::category_collapse($element['children'][$sortorder], $collapsed);
410 * Static recursive helper - makes the grade_item for category the last children
411 * @static
412 * @param array $element The seed of the recursion
413 * @return void
415 function category_grade_last(&$element) {
416 if (empty($element['children'])) {
417 return;
419 if (count($element['children']) < 2) {
420 return;
422 $category_item = reset($element['children']);
423 $order = key($element['children']);
424 unset($element['children'][$order]);
425 $element['children'][$order] =& $category_item;
426 foreach ($element['children'] as $sortorder=>$child) {
427 grade_tree::category_grade_last($element['children'][$sortorder]);
432 * Static recursive helper - fills the levels array, useful when accessing tree elements of one level
433 * @static
434 * @param int $levels
435 * @param array $element The seed of the recursion
436 * @param int $depth
437 * @return void
439 function fill_levels(&$levels, &$element, $depth) {
440 if (!array_key_exists($depth, $levels)) {
441 $levels[$depth] = array();
444 // prepare unique identifier
445 if ($element['type'] == 'category') {
446 $element['eid'] = 'c'.$element['object']->id;
447 } else if (in_array($element['type'], array('item', 'courseitem', 'categoryitem'))) {
448 $element['eid'] = 'i'.$element['object']->id;
451 $levels[$depth][] =& $element;
452 $depth++;
453 if (empty($element['children'])) {
454 return;
456 $prev = 0;
457 foreach ($element['children'] as $sortorder=>$child) {
458 grade_tree::fill_levels($levels, $element['children'][$sortorder], $depth);
459 $element['children'][$sortorder]['prev'] = $prev;
460 $element['children'][$sortorder]['next'] = 0;
461 if ($prev) {
462 $element['children'][$prev]['next'] = $sortorder;
464 $prev = $sortorder;
469 * Static recursive helper - makes full tree (all leafes are at the same level)
471 function inject_fillers(&$element, $depth) {
472 $depth++;
474 if (empty($element['children'])) {
475 return $depth;
477 $chdepths = array();
478 $chids = array_keys($element['children']);
479 $last_child = end($chids);
480 $first_child = reset($chids);
482 foreach ($chids as $chid) {
483 $chdepths[$chid] = grade_tree::inject_fillers($element['children'][$chid], $depth);
485 arsort($chdepths);
487 $maxdepth = reset($chdepths);
488 foreach ($chdepths as $chid=>$chd) {
489 if ($chd == $maxdepth) {
490 continue;
492 for ($i=0; $i < $maxdepth-$chd; $i++) {
493 if ($chid == $first_child) {
494 $type = 'fillerfirst';
495 } else if ($chid == $last_child) {
496 $type = 'fillerlast';
497 } else {
498 $type = 'filler';
500 $oldchild =& $element['children'][$chid];
501 $element['children'][$chid] = array('object'=>'filler', 'type'=>$type, 'eid'=>'', 'depth'=>$element['object']->depth,'children'=>array($oldchild));
505 return $maxdepth;
509 * Static recursive helper - add colspan information into categories
511 function inject_colspans(&$element) {
512 if (empty($element['children'])) {
513 return 1;
515 $count = 0;
516 foreach ($element['children'] as $key=>$child) {
517 $count += grade_tree::inject_colspans($element['children'][$key]);
519 $element['colspan'] = $count;
520 return $count;
524 * Parses the array in search of a given eid and returns a element object with
525 * information about the element it has found.
526 * @param int $eid
527 * @return object element
529 function locate_element($eid) {
530 if (strpos($eid, 'g') === 0) {
531 // it is a grade construct a new object
532 $id = (int)substr($eid, 1);
533 if (!$grade = grade_grade::fetch(array('id'=>$id))) {
534 return null;
536 //extra security check - the grade item must be in this tree
537 if (!$item_el = $this->locate_element('i'.$grade->itemid)) {
538 return null;
540 $grade->grade_item =& $item_el['object']; // this may speedup grade_grade methods!
541 return array('eid'=>'g'.$id,'object'=>$grade, 'type'=>'grade');
544 // it is a category or item
545 foreach ($this->levels as $row) {
546 foreach ($row as $element) {
547 if ($element['type'] == 'filler') {
548 continue;
550 if ($element['eid'] == $eid) {
551 return $element;
556 return null;
560 * Return edit icon for give element
561 * @param object $element
562 * @return string
564 function get_edit_icon($element, $gpr) {
565 global $CFG;
567 if (!has_capability('moodle/grade:manage', $this->context)) {
568 return '';
571 static $stredit = null;
572 if (is_null($stredit)) {
573 $stredit = get_string('edit');
576 $object = $element['object'];
577 $overlib = '';
579 switch ($element['type']) {
580 case 'item':
581 case 'categoryitem':
582 case 'courseitem':
583 if (empty($object->outcomeid)) {
584 $url = $CFG->wwwroot.'/grade/edit/item.php?courseid='.$this->courseid.'&amp;id='.$object->id;
585 } else {
586 $url = $CFG->wwwroot.'/grade/edit/outcomeitem.php?courseid='.$this->courseid.'&amp;id='.$object->id;
588 $url = $gpr->add_url_params($url);
589 break;
591 case 'category':
592 $url = $CFG->wwwroot.'/grade/edit/category.php?courseid='.$this->courseid.'&amp;id='.$object->id;
593 $url = $gpr->add_url_params($url);
594 break;
596 case 'grade':
597 //TODO: improve dealing with new grades
598 $url = $CFG->wwwroot.'/grade/edit/grade.php?courseid='.$this->courseid.'&amp;id='.$object->id;
599 $url = $gpr->add_url_params($url);
600 if (!empty($object->feedback)) {
601 $feedback = format_text($object->feedback, $object->feedbackformat);
602 $function = "return overlib('".s(ltrim($object->feedback)."', FULLHTML);");
603 $overlib = 'onmouseover="'.$function.'" onmouseout="return nd();"';
605 break;
607 default:
608 $url = null;
611 if ($url) {
612 return '<a href="'.$url.'"><img '.$overlib.' src="'.$CFG->pixpath.'/t/edit.gif" class="iconsmall" alt="'.$stredit.'" title="'.$stredit.'"/></a>';
614 } else {
615 return '';
620 * Return hiding icon for give element
621 * @param object $element
622 * @return string
624 function get_hiding_icon($element, $gpr) {
625 global $CFG;
627 if (!has_capability('moodle/grade:manage', $this->context) and !has_capability('moodle/grade:hide', $this->context)) {
628 return '';
631 static $strshow = null;
632 static $strhide = null;
633 if (is_null($strshow)) {
634 $strshow = get_string('show');
635 $strhide = get_string('hide');
638 if ($element['object']->is_hidden()) {
639 $url = $CFG->wwwroot.'/grade/edit/action.php?id='.$this->courseid.'&amp;action=show&amp;sesskey='.sesskey().'&amp;eid='.$element['eid'];
640 $url = $gpr->add_url_params($url);
641 $action = '<a href="'.$url.'"><img src="'.$CFG->pixpath.'/t/show.gif" class="iconsmall" alt="'.$strshow.'" title="'.$strshow.'"/></a>';
643 } else {
644 $url = $CFG->wwwroot.'/grade/edit/action.php?id='.$this->courseid.'&amp;action=hide&amp;sesskey='.sesskey().'&amp;eid='.$element['eid'];
645 $url = $gpr->add_url_params($url);
646 $action = '<a href="'.$url.'"><img src="'.$CFG->pixpath.'/t/hide.gif" class="iconsmall" alt="'.$strhide.'" title="'.$strhide.'"/></a>';
648 return $action;
652 * Return locking icon for give element
653 * @param object $element
654 * @return string
656 function get_locking_icon($element, $gpr) {
657 global $CFG;
659 static $strunlock = null;
660 static $strlock = null;
661 if (is_null($strunlock)) {
662 $strunlock = get_string('unlock', 'grades');
663 $strlock = get_string('lock', 'grades');
666 if ($element['object']->is_locked()) {
667 if (!has_capability('moodle/grade:manage', $this->context) and !has_capability('moodle/grade:unlock', $this->context)) {
668 return '';
670 $url = $CFG->wwwroot.'/grade/edit/action.php?id='.$this->courseid.'&amp;action=unlock&amp;sesskey='.sesskey().'&amp;eid='.$element['eid'];
671 $url = $gpr->add_url_params($url);
672 $action = '<a href="'.$url.'"><img src="'.$CFG->pixpath.'/t/unlock.gif" class="iconsmall" alt="'.$strunlock.'" title="'.$strunlock.'"/></a>';
674 } else {
675 if (!has_capability('moodle/grade:manage', $this->context) and !has_capability('moodle/grade:lock', $this->context)) {
676 return '';
678 $url = $CFG->wwwroot.'/grade/edit/action.php?id='.$this->courseid.'&amp;action=lock&amp;sesskey='.sesskey().'&amp;eid='.$element['eid'];
679 $url = $gpr->add_url_params($url);
680 $action = '<a href="'.$url.'"><img src="'.$CFG->pixpath.'/t/lock.gif" class="iconsmall" alt="'.$strlock.'" title="'.$strlock.'"/></a>';
682 return $action;
686 * Return calculation icon for given element
687 * @param object $element
688 * @return string
690 function get_calculation_icon($element, $gpr) {
691 global $CFG;
692 if (!has_capability('moodle/grade:manage', $this->context)) {
693 return '';
696 $calculation_icon = '';
698 $type = $element['type'];
699 $object = $element['object'];
701 if ($type == 'item' or $type == 'courseitem' or $type == 'categoryitem') {
702 $streditcalculation = get_string('editcalculation', 'grades');
704 // show calculation icon only when calculation possible
705 if (!$object->is_normal_item() and ($object->gradetype == GRADE_TYPE_SCALE or $object->gradetype == GRADE_TYPE_VALUE)) {
706 $url = $CFG->wwwroot.'/grade/edit/calculation.php?courseid='.$this->courseid.'&amp;id='.$object->id;
707 $url = $gpr->add_url_params($url);
708 $calculation_icon = '<a href="'. $url.'"><img src="'.$CFG->pixpath.'/t/calc.gif" class="iconsmall" alt="'
709 . $streditcalculation.'" title="'.$streditcalculation.'" /></a>'. "\n";
713 return $calculation_icon;