PageRenderTime 79ms CodeModel.GetById 4ms app.highlight 62ms RepoModel.GetById 1ms app.codeStats 1ms

/grade/lib.php

https://bitbucket.org/bmbrands/swets
PHP | 2509 lines | 1705 code | 257 blank | 547 comment | 314 complexity | 7ffc0bbce945897a71ac25bcbb57bef3 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2
   3// This file is part of Moodle - http://moodle.org/
   4//
   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.
   9//
  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.
  14//
  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/>.
  17
  18/**
  19 * Functions used by gradebook plugins and reports.
  20 *
  21 * @package   moodlecore
  22 * @copyright 2009 Petr Skoda and Nicolas Connault
  23 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24 */
  25
  26require_once $CFG->libdir.'/gradelib.php';
  27
  28/**
  29 * This class iterates over all users that are graded in a course.
  30 * Returns detailed info about users and their grades.
  31 *
  32 * @author Petr Skoda <skodak@moodle.org>
  33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34 */
  35class graded_users_iterator {
  36    public $course;
  37    public $grade_items;
  38    public $groupid;
  39    public $users_rs;
  40    public $grades_rs;
  41    public $gradestack;
  42    public $sortfield1;
  43    public $sortorder1;
  44    public $sortfield2;
  45    public $sortorder2;
  46
  47    /**
  48     * Constructor
  49     *
  50     * @param object $course A course object
  51     * @param array  $grade_items array of grade items, if not specified only user info returned
  52     * @param int    $groupid iterate only group users if present
  53     * @param string $sortfield1 The first field of the users table by which the array of users will be sorted
  54     * @param string $sortorder1 The order in which the first sorting field will be sorted (ASC or DESC)
  55     * @param string $sortfield2 The second field of the users table by which the array of users will be sorted
  56     * @param string $sortorder2 The order in which the second sorting field will be sorted (ASC or DESC)
  57     */
  58    public function graded_users_iterator($course, $grade_items=null, $groupid=0,
  59                                          $sortfield1='lastname', $sortorder1='ASC',
  60                                          $sortfield2='firstname', $sortorder2='ASC') {
  61        $this->course      = $course;
  62        $this->grade_items = $grade_items;
  63        $this->groupid     = $groupid;
  64        $this->sortfield1  = $sortfield1;
  65        $this->sortorder1  = $sortorder1;
  66        $this->sortfield2  = $sortfield2;
  67        $this->sortorder2  = $sortorder2;
  68
  69        $this->gradestack  = array();
  70    }
  71
  72    /**
  73     * Initialise the iterator
  74     * @return boolean success
  75     */
  76    public function init() {
  77        global $CFG, $DB;
  78
  79        $this->close();
  80
  81        grade_regrade_final_grades($this->course->id);
  82        $course_item = grade_item::fetch_course_item($this->course->id);
  83        if ($course_item->needsupdate) {
  84            // can not calculate all final grades - sorry
  85            return false;
  86        }
  87
  88        $coursecontext = get_context_instance(CONTEXT_COURSE, $this->course->id);
  89        $relatedcontexts = get_related_contexts_string($coursecontext);
  90
  91        list($gradebookroles_sql, $params) =
  92            $DB->get_in_or_equal(explode(',', $CFG->gradebookroles), SQL_PARAMS_NAMED, 'grbr');
  93
  94        //limit to users with an active enrolment
  95        list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext);
  96
  97        $params = array_merge($params, $enrolledparams);
  98
  99        if ($this->groupid) {
 100            $groupsql = "INNER JOIN {groups_members} gm ON gm.userid = u.id";
 101            $groupwheresql = "AND gm.groupid = :groupid";
 102            // $params contents: gradebookroles
 103            $params['groupid'] = $this->groupid;
 104        } else {
 105            $groupsql = "";
 106            $groupwheresql = "";
 107        }
 108
 109        if (empty($this->sortfield1)) {
 110            // we must do some sorting even if not specified
 111            $ofields = ", u.id AS usrt";
 112            $order   = "usrt ASC";
 113
 114        } else {
 115            $ofields = ", u.$this->sortfield1 AS usrt1";
 116            $order   = "usrt1 $this->sortorder1";
 117            if (!empty($this->sortfield2)) {
 118                $ofields .= ", u.$this->sortfield2 AS usrt2";
 119                $order   .= ", usrt2 $this->sortorder2";
 120            }
 121            if ($this->sortfield1 != 'id' and $this->sortfield2 != 'id') {
 122                // user order MUST be the same in both queries,
 123                // must include the only unique user->id if not already present
 124                $ofields .= ", u.id AS usrt";
 125                $order   .= ", usrt ASC";
 126            }
 127        }
 128
 129        // $params contents: gradebookroles and groupid (for $groupwheresql)
 130        $users_sql = "SELECT u.* $ofields
 131                        FROM {user} u
 132                        JOIN ($enrolledsql) je ON je.id = u.id
 133                             $groupsql
 134                        JOIN (
 135                                  SELECT DISTINCT ra.userid
 136                                    FROM {role_assignments} ra
 137                                   WHERE ra.roleid $gradebookroles_sql
 138                                     AND ra.contextid $relatedcontexts
 139                             ) rainner ON rainner.userid = u.id
 140                         WHERE u.deleted = 0
 141                             $groupwheresql
 142                    ORDER BY $order";
 143        $this->users_rs = $DB->get_recordset_sql($users_sql, $params);
 144
 145        if (!empty($this->grade_items)) {
 146            $itemids = array_keys($this->grade_items);
 147            list($itemidsql, $grades_params) = $DB->get_in_or_equal($itemids, SQL_PARAMS_NAMED, 'items');
 148            $params = array_merge($params, $grades_params);
 149            // $params contents: gradebookroles, enrolledparams, groupid (for $groupwheresql) and itemids
 150
 151            $grades_sql = "SELECT g.* $ofields
 152                             FROM {grade_grades} g
 153                             JOIN {user} u ON g.userid = u.id
 154                             JOIN ($enrolledsql) je ON je.id = u.id
 155                                  $groupsql
 156                             JOIN (
 157                                      SELECT DISTINCT ra.userid
 158                                        FROM {role_assignments} ra
 159                                       WHERE ra.roleid $gradebookroles_sql
 160                                         AND ra.contextid $relatedcontexts
 161                                  ) rainner ON rainner.userid = u.id
 162                              WHERE u.deleted = 0
 163                              AND g.itemid $itemidsql
 164                              $groupwheresql
 165                         ORDER BY $order, g.itemid ASC";
 166            $this->grades_rs = $DB->get_recordset_sql($grades_sql, $params);
 167        } else {
 168            $this->grades_rs = false;
 169        }
 170
 171        return true;
 172    }
 173
 174    /**
 175     * Returns information about the next user
 176     * @return mixed array of user info, all grades and feedback or null when no more users found
 177     */
 178    function next_user() {
 179        if (!$this->users_rs) {
 180            return false; // no users present
 181        }
 182
 183        if (!$this->users_rs->valid()) {
 184            if ($current = $this->_pop()) {
 185                // this is not good - user or grades updated between the two reads above :-(
 186            }
 187
 188            return false; // no more users
 189        } else {
 190            $user = $this->users_rs->current();
 191            $this->users_rs->next();
 192        }
 193
 194        // find grades of this user
 195        $grade_records = array();
 196        while (true) {
 197            if (!$current = $this->_pop()) {
 198                break; // no more grades
 199            }
 200
 201            if (empty($current->userid)) {
 202                break;
 203            }
 204
 205            if ($current->userid != $user->id) {
 206                // grade of the next user, we have all for this user
 207                $this->_push($current);
 208                break;
 209            }
 210
 211            $grade_records[$current->itemid] = $current;
 212        }
 213
 214        $grades = array();
 215        $feedbacks = array();
 216
 217        if (!empty($this->grade_items)) {
 218            foreach ($this->grade_items as $grade_item) {
 219                if (array_key_exists($grade_item->id, $grade_records)) {
 220                    $feedbacks[$grade_item->id]->feedback       = $grade_records[$grade_item->id]->feedback;
 221                    $feedbacks[$grade_item->id]->feedbackformat = $grade_records[$grade_item->id]->feedbackformat;
 222                    unset($grade_records[$grade_item->id]->feedback);
 223                    unset($grade_records[$grade_item->id]->feedbackformat);
 224                    $grades[$grade_item->id] = new grade_grade($grade_records[$grade_item->id], false);
 225                } else {
 226                    $feedbacks[$grade_item->id]->feedback       = '';
 227                    $feedbacks[$grade_item->id]->feedbackformat = FORMAT_MOODLE;
 228                    $grades[$grade_item->id] =
 229                        new grade_grade(array('userid'=>$user->id, 'itemid'=>$grade_item->id), false);
 230                }
 231            }
 232        }
 233
 234        $result = new stdClass();
 235        $result->user      = $user;
 236        $result->grades    = $grades;
 237        $result->feedbacks = $feedbacks;
 238        return $result;
 239    }
 240
 241    /**
 242     * Close the iterator, do not forget to call this function.
 243     * @return void
 244     */
 245    function close() {
 246        if ($this->users_rs) {
 247            $this->users_rs->close();
 248            $this->users_rs = null;
 249        }
 250        if ($this->grades_rs) {
 251            $this->grades_rs->close();
 252            $this->grades_rs = null;
 253        }
 254        $this->gradestack = array();
 255    }
 256
 257
 258    /**
 259     * _push
 260     *
 261     * @param grade_grade $grade Grade object
 262     *
 263     * @return void
 264     */
 265    function _push($grade) {
 266        array_push($this->gradestack, $grade);
 267    }
 268
 269
 270    /**
 271     * _pop
 272     *
 273     * @return object current grade object
 274     */
 275    function _pop() {
 276        global $DB;
 277        if (empty($this->gradestack)) {
 278            if (empty($this->grades_rs) || !$this->grades_rs->valid()) {
 279                return null; // no grades present
 280            }
 281
 282            $current = $this->grades_rs->current();
 283
 284            $this->grades_rs->next();
 285
 286            return $current;
 287        } else {
 288            return array_pop($this->gradestack);
 289        }
 290    }
 291}
 292
 293/**
 294 * Print a selection popup form of the graded users in a course.
 295 *
 296 * @deprecated since 2.0
 297 *
 298 * @param int    $course id of the course
 299 * @param string $actionpage The page receiving the data from the popoup form
 300 * @param int    $userid   id of the currently selected user (or 'all' if they are all selected)
 301 * @param int    $groupid id of requested group, 0 means all
 302 * @param int    $includeall bool include all option
 303 * @param bool   $return If true, will return the HTML, otherwise, will print directly
 304 * @return null
 305 */
 306function print_graded_users_selector($course, $actionpage, $userid=0, $groupid=0, $includeall=true, $return=false) {
 307    global $CFG, $USER, $OUTPUT;
 308    return $OUTPUT->render(grade_get_graded_users_select(substr($actionpage, 0, strpos($actionpage, '/')), $course, $userid, $groupid, $includeall));
 309}
 310
 311function grade_get_graded_users_select($report, $course, $userid, $groupid, $includeall) {
 312    global $USER;
 313
 314    if (is_null($userid)) {
 315        $userid = $USER->id;
 316    }
 317
 318    $menu = array(); // Will be a list of userid => user name
 319    $gui = new graded_users_iterator($course, null, $groupid);
 320    $gui->init();
 321    $label = get_string('selectauser', 'grades');
 322    if ($includeall) {
 323        $menu[0] = get_string('allusers', 'grades');
 324        $label = get_string('selectalloroneuser', 'grades');
 325    }
 326    while ($userdata = $gui->next_user()) {
 327        $user = $userdata->user;
 328        $menu[$user->id] = fullname($user);
 329    }
 330    $gui->close();
 331
 332    if ($includeall) {
 333        $menu[0] .= " (" . (count($menu) - 1) . ")";
 334    }
 335    $select = new single_select(new moodle_url('/grade/report/'.$report.'/index.php', array('id'=>$course->id)), 'userid', $menu, $userid);
 336    $select->label = $label;
 337    $select->formid = 'choosegradeuser';
 338    return $select;
 339}
 340
 341/**
 342 * Print grading plugin selection popup form.
 343 *
 344 * @param array   $plugin_info An array of plugins containing information for the selector
 345 * @param boolean $return return as string
 346 *
 347 * @return nothing or string if $return true
 348 */
 349function print_grade_plugin_selector($plugin_info, $active_type, $active_plugin, $return=false) {
 350    global $CFG, $OUTPUT, $PAGE;
 351
 352    $menu = array();
 353    $count = 0;
 354    $active = '';
 355
 356    foreach ($plugin_info as $plugin_type => $plugins) {
 357        if ($plugin_type == 'strings') {
 358            continue;
 359        }
 360
 361        $first_plugin = reset($plugins);
 362
 363        $sectionname = $plugin_info['strings'][$plugin_type];
 364        $section = array();
 365
 366        foreach ($plugins as $plugin) {
 367            $link = $plugin->link->out(false);
 368            $section[$link] = $plugin->string;
 369            $count++;
 370            if ($plugin_type === $active_type and $plugin->id === $active_plugin) {
 371                $active = $link;
 372            }
 373        }
 374
 375        if ($section) {
 376            $menu[] = array($sectionname=>$section);
 377        }
 378    }
 379
 380    // finally print/return the popup form
 381    if ($count > 1) {
 382        $select = new url_select($menu, $active, null, 'choosepluginreport');
 383
 384        if ($return) {
 385            return $OUTPUT->render($select);
 386        } else {
 387            echo $OUTPUT->render($select);
 388        }
 389    } else {
 390        // only one option - no plugin selector needed
 391        return '';
 392    }
 393}
 394
 395/**
 396 * Print grading plugin selection tab-based navigation.
 397 *
 398 * @param string  $active_type type of plugin on current page - import, export, report or edit
 399 * @param string  $active_plugin active plugin type - grader, user, cvs, ...
 400 * @param array   $plugin_info Array of plugins
 401 * @param boolean $return return as string
 402 *
 403 * @return nothing or string if $return true
 404 */
 405function grade_print_tabs($active_type, $active_plugin, $plugin_info, $return=false) {
 406    global $CFG, $COURSE;
 407
 408    if (!isset($currenttab)) { //TODO: this is weird
 409        $currenttab = '';
 410    }
 411
 412    $tabs = array();
 413    $top_row  = array();
 414    $bottom_row = array();
 415    $inactive = array($active_plugin);
 416    $activated = array();
 417
 418    $count = 0;
 419    $active = '';
 420
 421    foreach ($plugin_info as $plugin_type => $plugins) {
 422        if ($plugin_type == 'strings') {
 423            continue;
 424        }
 425
 426        // If $plugins is actually the definition of a child-less parent link:
 427        if (!empty($plugins->id)) {
 428            $string = $plugins->string;
 429            if (!empty($plugin_info[$active_type]->parent)) {
 430                $string = $plugin_info[$active_type]->parent->string;
 431            }
 432
 433            $top_row[] = new tabobject($plugin_type, $plugins->link, $string);
 434            continue;
 435        }
 436
 437        $first_plugin = reset($plugins);
 438        $url = $first_plugin->link;
 439
 440        if ($plugin_type == 'report') {
 441            $url = $CFG->wwwroot.'/grade/report/index.php?id='.$COURSE->id;
 442        }
 443
 444        $top_row[] = new tabobject($plugin_type, $url, $plugin_info['strings'][$plugin_type]);
 445
 446        if ($active_type == $plugin_type) {
 447            foreach ($plugins as $plugin) {
 448                $bottom_row[] = new tabobject($plugin->id, $plugin->link, $plugin->string);
 449                if ($plugin->id == $active_plugin) {
 450                    $inactive = array($plugin->id);
 451                }
 452            }
 453        }
 454    }
 455
 456    $tabs[] = $top_row;
 457    $tabs[] = $bottom_row;
 458
 459    if ($return) {
 460        return print_tabs($tabs, $active_type, $inactive, $activated, true);
 461    } else {
 462        print_tabs($tabs, $active_type, $inactive, $activated);
 463    }
 464}
 465
 466/**
 467 * grade_get_plugin_info
 468 *
 469 * @param int    $courseid The course id
 470 * @param string $active_type type of plugin on current page - import, export, report or edit
 471 * @param string $active_plugin active plugin type - grader, user, cvs, ...
 472 *
 473 * @return array
 474 */
 475function grade_get_plugin_info($courseid, $active_type, $active_plugin) {
 476    global $CFG, $SITE;
 477
 478    $context = get_context_instance(CONTEXT_COURSE, $courseid);
 479
 480    $plugin_info = array();
 481    $count = 0;
 482    $active = '';
 483    $url_prefix = $CFG->wwwroot . '/grade/';
 484
 485    // Language strings
 486    $plugin_info['strings'] = grade_helper::get_plugin_strings();
 487
 488    if ($reports = grade_helper::get_plugins_reports($courseid)) {
 489        $plugin_info['report'] = $reports;
 490    }
 491
 492    //showing grade categories and items make no sense if we're not within a course
 493    if ($courseid!=$SITE->id) {
 494        if ($edittree = grade_helper::get_info_edit_structure($courseid)) {
 495            $plugin_info['edittree'] = $edittree;
 496        }
 497    }
 498
 499    if ($scale = grade_helper::get_info_scales($courseid)) {
 500        $plugin_info['scale'] = array('view'=>$scale);
 501    }
 502
 503    if ($outcomes = grade_helper::get_info_outcomes($courseid)) {
 504        $plugin_info['outcome'] = $outcomes;
 505    }
 506
 507    if ($letters = grade_helper::get_info_letters($courseid)) {
 508        $plugin_info['letter'] = $letters;
 509    }
 510
 511    if ($imports = grade_helper::get_plugins_import($courseid)) {
 512        $plugin_info['import'] = $imports;
 513    }
 514
 515    if ($exports = grade_helper::get_plugins_export($courseid)) {
 516        $plugin_info['export'] = $exports;
 517    }
 518
 519    foreach ($plugin_info as $plugin_type => $plugins) {
 520        if (!empty($plugins->id) && $active_plugin == $plugins->id) {
 521            $plugin_info['strings']['active_plugin_str'] = $plugins->string;
 522            break;
 523        }
 524        foreach ($plugins as $plugin) {
 525            if (is_a($plugin, 'grade_plugin_info')) {
 526                if ($active_plugin == $plugin->id) {
 527                    $plugin_info['strings']['active_plugin_str'] = $plugin->string;
 528                }
 529            }
 530        }
 531    }
 532
 533    //hide course settings if we're not in a course
 534    if ($courseid!=$SITE->id) {
 535        if ($setting = grade_helper::get_info_manage_settings($courseid)) {
 536            $plugin_info['settings'] = array('course'=>$setting);
 537        }
 538    }
 539
 540    // Put preferences last
 541    if ($preferences = grade_helper::get_plugins_report_preferences($courseid)) {
 542        $plugin_info['preferences'] = $preferences;
 543    }
 544
 545    foreach ($plugin_info as $plugin_type => $plugins) {
 546        if (!empty($plugins->id) && $active_plugin == $plugins->id) {
 547            $plugin_info['strings']['active_plugin_str'] = $plugins->string;
 548            break;
 549        }
 550        foreach ($plugins as $plugin) {
 551            if (is_a($plugin, 'grade_plugin_info')) {
 552                if ($active_plugin == $plugin->id) {
 553                    $plugin_info['strings']['active_plugin_str'] = $plugin->string;
 554                }
 555            }
 556        }
 557    }
 558
 559    return $plugin_info;
 560}
 561
 562/**
 563 * A simple class containing info about grade plugins.
 564 * Can be subclassed for special rules
 565 *
 566 * @package moodlecore
 567 * @copyright 2009 Nicolas Connault
 568 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 569 */
 570class grade_plugin_info {
 571    /**
 572     * A unique id for this plugin
 573     *
 574     * @var mixed
 575     */
 576    public $id;
 577    /**
 578     * A URL to access this plugin
 579     *
 580     * @var mixed
 581     */
 582    public $link;
 583    /**
 584     * The name of this plugin
 585     *
 586     * @var mixed
 587     */
 588    public $string;
 589    /**
 590     * Another grade_plugin_info object, parent of the current one
 591     *
 592     * @var mixed
 593     */
 594    public $parent;
 595
 596    /**
 597     * Constructor
 598     *
 599     * @param int $id A unique id for this plugin
 600     * @param string $link A URL to access this plugin
 601     * @param string $string The name of this plugin
 602     * @param object $parent Another grade_plugin_info object, parent of the current one
 603     *
 604     * @return void
 605     */
 606    public function __construct($id, $link, $string, $parent=null) {
 607        $this->id = $id;
 608        $this->link = $link;
 609        $this->string = $string;
 610        $this->parent = $parent;
 611    }
 612}
 613
 614/**
 615 * Prints the page headers, breadcrumb trail, page heading, (optional) dropdown navigation menu and
 616 * (optional) navigation tabs for any gradebook page. All gradebook pages MUST use these functions
 617 * in favour of the usual print_header(), print_header_simple(), print_heading() etc.
 618 * !IMPORTANT! Use of tabs.php file in gradebook pages is forbidden unless tabs are switched off at
 619 * the site level for the gradebook ($CFG->grade_navmethod = GRADE_NAVMETHOD_DROPDOWN).
 620 *
 621 * @param int     $courseid Course id
 622 * @param string  $active_type The type of the current page (report, settings,
 623 *                             import, export, scales, outcomes, letters)
 624 * @param string  $active_plugin The plugin of the current page (grader, fullview etc...)
 625 * @param string  $heading The heading of the page. Tries to guess if none is given
 626 * @param boolean $return Whether to return (true) or echo (false) the HTML generated by this function
 627 * @param string  $bodytags Additional attributes that will be added to the <body> tag
 628 * @param string  $buttons Additional buttons to display on the page
 629 *
 630 * @return string HTML code or nothing if $return == false
 631 */
 632function print_grade_page_head($courseid, $active_type, $active_plugin=null,
 633                               $heading = false, $return=false,
 634                               $buttons=false, $shownavigation=true) {
 635    global $CFG, $OUTPUT, $PAGE;
 636
 637    $plugin_info = grade_get_plugin_info($courseid, $active_type, $active_plugin);
 638
 639    // Determine the string of the active plugin
 640    $stractive_plugin = ($active_plugin) ? $plugin_info['strings']['active_plugin_str'] : $heading;
 641    $stractive_type = $plugin_info['strings'][$active_type];
 642
 643    if (empty($plugin_info[$active_type]->id) || !empty($plugin_info[$active_type]->parent)) {
 644        $title = $PAGE->course->fullname.': ' . $stractive_type . ': ' . $stractive_plugin;
 645    } else {
 646        $title = $PAGE->course->fullname.': ' . $stractive_plugin;
 647    }
 648
 649    if ($active_type == 'report') {
 650        $PAGE->set_pagelayout('report');
 651    } else {
 652        $PAGE->set_pagelayout('admin');
 653    }
 654    $PAGE->set_title(get_string('grades') . ': ' . $stractive_type);
 655    $PAGE->set_heading($title);
 656    if ($buttons instanceof single_button) {
 657        $buttons = $OUTPUT->render($buttons);
 658    }
 659    $PAGE->set_button($buttons);
 660    grade_extend_settings($plugin_info, $courseid);
 661
 662    $returnval = $OUTPUT->header();
 663    if (!$return) {
 664        echo $returnval;
 665    }
 666
 667    // Guess heading if not given explicitly
 668    if (!$heading) {
 669        $heading = $stractive_plugin;
 670    }
 671
 672    if ($shownavigation) {
 673        if ($CFG->grade_navmethod == GRADE_NAVMETHOD_COMBO || $CFG->grade_navmethod == GRADE_NAVMETHOD_DROPDOWN) {
 674            $returnval .= print_grade_plugin_selector($plugin_info, $active_type, $active_plugin, $return);
 675        }
 676        $returnval .= $OUTPUT->heading($heading);
 677        if ($CFG->grade_navmethod == GRADE_NAVMETHOD_COMBO || $CFG->grade_navmethod == GRADE_NAVMETHOD_TABS) {
 678            $returnval .= grade_print_tabs($active_type, $active_plugin, $plugin_info, $return);
 679        }
 680    }
 681
 682    if ($return) {
 683        return $returnval;
 684    }
 685}
 686
 687/**
 688 * Utility class used for return tracking when using edit and other forms in grade plugins
 689 *
 690 * @package moodlecore
 691 * @copyright 2009 Nicolas Connault
 692 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 693 */
 694class grade_plugin_return {
 695    public $type;
 696    public $plugin;
 697    public $courseid;
 698    public $userid;
 699    public $page;
 700
 701    /**
 702     * Constructor
 703     *
 704     * @param array $params - associative array with return parameters, if null parameter are taken from _GET or _POST
 705     */
 706    public function grade_plugin_return($params = null) {
 707        if (empty($params)) {
 708            $this->type     = optional_param('gpr_type', null, PARAM_SAFEDIR);
 709            $this->plugin   = optional_param('gpr_plugin', null, PARAM_SAFEDIR);
 710            $this->courseid = optional_param('gpr_courseid', null, PARAM_INT);
 711            $this->userid   = optional_param('gpr_userid', null, PARAM_INT);
 712            $this->page     = optional_param('gpr_page', null, PARAM_INT);
 713
 714        } else {
 715            foreach ($params as $key=>$value) {
 716                if (property_exists($this, $key)) {
 717                    $this->$key = $value;
 718                }
 719            }
 720        }
 721    }
 722
 723    /**
 724     * Returns return parameters as options array suitable for buttons.
 725     * @return array options
 726     */
 727    public function get_options() {
 728        if (empty($this->type)) {
 729            return array();
 730        }
 731
 732        $params = array();
 733
 734        if (!empty($this->plugin)) {
 735            $params['plugin'] = $this->plugin;
 736        }
 737
 738        if (!empty($this->courseid)) {
 739            $params['id'] = $this->courseid;
 740        }
 741
 742        if (!empty($this->userid)) {
 743            $params['userid'] = $this->userid;
 744        }
 745
 746        if (!empty($this->page)) {
 747            $params['page'] = $this->page;
 748        }
 749
 750        return $params;
 751    }
 752
 753    /**
 754     * Returns return url
 755     *
 756     * @param string $default default url when params not set
 757     * @param array  $extras Extra URL parameters
 758     *
 759     * @return string url
 760     */
 761    public function get_return_url($default, $extras=null) {
 762        global $CFG;
 763
 764        if (empty($this->type) or empty($this->plugin)) {
 765            return $default;
 766        }
 767
 768        $url = $CFG->wwwroot.'/grade/'.$this->type.'/'.$this->plugin.'/index.php';
 769        $glue = '?';
 770
 771        if (!empty($this->courseid)) {
 772            $url .= $glue.'id='.$this->courseid;
 773            $glue = '&amp;';
 774        }
 775
 776        if (!empty($this->userid)) {
 777            $url .= $glue.'userid='.$this->userid;
 778            $glue = '&amp;';
 779        }
 780
 781        if (!empty($this->page)) {
 782            $url .= $glue.'page='.$this->page;
 783            $glue = '&amp;';
 784        }
 785
 786        if (!empty($extras)) {
 787            foreach ($extras as $key=>$value) {
 788                $url .= $glue.$key.'='.$value;
 789                $glue = '&amp;';
 790            }
 791        }
 792
 793        return $url;
 794    }
 795
 796    /**
 797     * Returns string with hidden return tracking form elements.
 798     * @return string
 799     */
 800    public function get_form_fields() {
 801        if (empty($this->type)) {
 802            return '';
 803        }
 804
 805        $result  = '<input type="hidden" name="gpr_type" value="'.$this->type.'" />';
 806
 807        if (!empty($this->plugin)) {
 808            $result .= '<input type="hidden" name="gpr_plugin" value="'.$this->plugin.'" />';
 809        }
 810
 811        if (!empty($this->courseid)) {
 812            $result .= '<input type="hidden" name="gpr_courseid" value="'.$this->courseid.'" />';
 813        }
 814
 815        if (!empty($this->userid)) {
 816            $result .= '<input type="hidden" name="gpr_userid" value="'.$this->userid.'" />';
 817        }
 818
 819        if (!empty($this->page)) {
 820            $result .= '<input type="hidden" name="gpr_page" value="'.$this->page.'" />';
 821        }
 822    }
 823
 824    /**
 825     * Add hidden elements into mform
 826     *
 827     * @param object &$mform moodle form object
 828     *
 829     * @return void
 830     */
 831    public function add_mform_elements(&$mform) {
 832        if (empty($this->type)) {
 833            return;
 834        }
 835
 836        $mform->addElement('hidden', 'gpr_type', $this->type);
 837        $mform->setType('gpr_type', PARAM_SAFEDIR);
 838
 839        if (!empty($this->plugin)) {
 840            $mform->addElement('hidden', 'gpr_plugin', $this->plugin);
 841            $mform->setType('gpr_plugin', PARAM_SAFEDIR);
 842        }
 843
 844        if (!empty($this->courseid)) {
 845            $mform->addElement('hidden', 'gpr_courseid', $this->courseid);
 846            $mform->setType('gpr_courseid', PARAM_INT);
 847        }
 848
 849        if (!empty($this->userid)) {
 850            $mform->addElement('hidden', 'gpr_userid', $this->userid);
 851            $mform->setType('gpr_userid', PARAM_INT);
 852        }
 853
 854        if (!empty($this->page)) {
 855            $mform->addElement('hidden', 'gpr_page', $this->page);
 856            $mform->setType('gpr_page', PARAM_INT);
 857        }
 858    }
 859
 860    /**
 861     * Add return tracking params into url
 862     *
 863     * @param moodle_url $url A URL
 864     *
 865     * @return string $url with return tracking params
 866     */
 867    public function add_url_params(moodle_url $url) {
 868        if (empty($this->type)) {
 869            return $url;
 870        }
 871
 872        $url->param('gpr_type', $this->type);
 873
 874        if (!empty($this->plugin)) {
 875            $url->param('gpr_plugin', $this->plugin);
 876        }
 877
 878        if (!empty($this->courseid)) {
 879            $url->param('gpr_courseid' ,$this->courseid);
 880        }
 881
 882        if (!empty($this->userid)) {
 883            $url->param('gpr_userid', $this->userid);
 884        }
 885
 886        if (!empty($this->page)) {
 887            $url->param('gpr_page', $this->page);
 888        }
 889
 890        return $url;
 891    }
 892}
 893
 894/**
 895 * Function central to gradebook for building and printing the navigation (breadcrumb trail).
 896 *
 897 * @param string $path The path of the calling script (using __FILE__?)
 898 * @param string $pagename The language string to use as the last part of the navigation (non-link)
 899 * @param mixed  $id Either a plain integer (assuming the key is 'id') or
 900 *                   an array of keys and values (e.g courseid => $courseid, itemid...)
 901 *
 902 * @return string
 903 */
 904function grade_build_nav($path, $pagename=null, $id=null) {
 905    global $CFG, $COURSE, $PAGE;
 906
 907    $strgrades = get_string('grades', 'grades');
 908
 909    // Parse the path and build navlinks from its elements
 910    $dirroot_length = strlen($CFG->dirroot) + 1; // Add 1 for the first slash
 911    $path = substr($path, $dirroot_length);
 912    $path = str_replace('\\', '/', $path);
 913
 914    $path_elements = explode('/', $path);
 915
 916    $path_elements_count = count($path_elements);
 917
 918    // First link is always 'grade'
 919    $PAGE->navbar->add($strgrades, new moodle_url('/grade/index.php', array('id'=>$COURSE->id)));
 920
 921    $link = null;
 922    $numberofelements = 3;
 923
 924    // Prepare URL params string
 925    $linkparams = array();
 926    if (!is_null($id)) {
 927        if (is_array($id)) {
 928            foreach ($id as $idkey => $idvalue) {
 929                $linkparams[$idkey] = $idvalue;
 930            }
 931        } else {
 932            $linkparams['id'] = $id;
 933        }
 934    }
 935
 936    $navlink4 = null;
 937
 938    // Remove file extensions from filenames
 939    foreach ($path_elements as $key => $filename) {
 940        $path_elements[$key] = str_replace('.php', '', $filename);
 941    }
 942
 943    // Second level links
 944    switch ($path_elements[1]) {
 945        case 'edit': // No link
 946            if ($path_elements[3] != 'index.php') {
 947                $numberofelements = 4;
 948            }
 949            break;
 950        case 'import': // No link
 951            break;
 952        case 'export': // No link
 953            break;
 954        case 'report':
 955            // $id is required for this link. Do not print it if $id isn't given
 956            if (!is_null($id)) {
 957                $link = new moodle_url('/grade/report/index.php', $linkparams);
 958            }
 959
 960            if ($path_elements[2] == 'grader') {
 961                $numberofelements = 4;
 962            }
 963            break;
 964
 965        default:
 966            // If this element isn't among the ones already listed above, it isn't supported, throw an error.
 967            debugging("grade_build_nav() doesn't support ". $path_elements[1] .
 968                    " as the second path element after 'grade'.");
 969            return false;
 970    }
 971    $PAGE->navbar->add(get_string($path_elements[1], 'grades'), $link);
 972
 973    // Third level links
 974    if (empty($pagename)) {
 975        $pagename = get_string($path_elements[2], 'grades');
 976    }
 977
 978    switch ($numberofelements) {
 979        case 3:
 980            $PAGE->navbar->add($pagename, $link);
 981            break;
 982        case 4:
 983            if ($path_elements[2] == 'grader' AND $path_elements[3] != 'index.php') {
 984                $PAGE->navbar->add(get_string('pluginname', 'gradereport_grader'), new moodle_url('/grade/report/grader/index.php', $linkparams));
 985            }
 986            $PAGE->navbar->add($pagename);
 987            break;
 988    }
 989
 990    return '';
 991}
 992
 993/**
 994 * General structure representing grade items in course
 995 *
 996 * @package moodlecore
 997 * @copyright 2009 Nicolas Connault
 998 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 999 */
1000class grade_structure {
1001    public $context;
1002
1003    public $courseid;
1004
1005    /**
1006    * Reference to modinfo for current course (for performance, to save
1007    * retrieving it from courseid every time). Not actually set except for
1008    * the grade_tree type.
1009    * @var course_modinfo
1010    */
1011    public $modinfo;
1012
1013    /**
1014     * 1D array of grade items only
1015     */
1016    public $items;
1017
1018    /**
1019     * Returns icon of element
1020     *
1021     * @param array &$element An array representing an element in the grade_tree
1022     * @param bool  $spacerifnone return spacer if no icon found
1023     *
1024     * @return string icon or spacer
1025     */
1026    public function get_element_icon(&$element, $spacerifnone=false) {
1027        global $CFG, $OUTPUT;
1028
1029        switch ($element['type']) {
1030            case 'item':
1031            case 'courseitem':
1032            case 'categoryitem':
1033                $is_course   = $element['object']->is_course_item();
1034                $is_category = $element['object']->is_category_item();
1035                $is_scale    = $element['object']->gradetype == GRADE_TYPE_SCALE;
1036                $is_value    = $element['object']->gradetype == GRADE_TYPE_VALUE;
1037                $is_outcome  = !empty($element['object']->outcomeid);
1038
1039                if ($element['object']->is_calculated()) {
1040                    $strcalc = get_string('calculatedgrade', 'grades');
1041                    return '<img src="'.$OUTPUT->pix_url('i/calc') . '" class="icon itemicon" title="'.
1042                            s($strcalc).'" alt="'.s($strcalc).'"/>';
1043
1044                } else if (($is_course or $is_category) and ($is_scale or $is_value)) {
1045                    if ($category = $element['object']->get_item_category()) {
1046                        switch ($category->aggregation) {
1047                            case GRADE_AGGREGATE_MEAN:
1048                            case GRADE_AGGREGATE_MEDIAN:
1049                            case GRADE_AGGREGATE_WEIGHTED_MEAN:
1050                            case GRADE_AGGREGATE_WEIGHTED_MEAN2:
1051                            case GRADE_AGGREGATE_EXTRACREDIT_MEAN:
1052                                $stragg = get_string('aggregation', 'grades');
1053                                return '<img src="'.$OUTPUT->pix_url('i/agg_mean') . '" ' .
1054                                        'class="icon itemicon" title="'.s($stragg).'" alt="'.s($stragg).'"/>';
1055                            case GRADE_AGGREGATE_SUM:
1056                                $stragg = get_string('aggregation', 'grades');
1057                                return '<img src="'.$OUTPUT->pix_url('i/agg_sum') . '" ' .
1058                                        'class="icon itemicon" title="'.s($stragg).'" alt="'.s($stragg).'"/>';
1059                        }
1060                    }
1061
1062                } else if ($element['object']->itemtype == 'mod') {
1063                    //prevent outcomes being displaying the same icon as the activity they are attached to
1064                    if ($is_outcome) {
1065                        $stroutcome = s(get_string('outcome', 'grades'));
1066                        return '<img src="'.$OUTPUT->pix_url('i/outcomes') . '" ' .
1067                            'class="icon itemicon" title="'.$stroutcome.
1068                            '" alt="'.$stroutcome.'"/>';
1069                    } else {
1070                        $strmodname = get_string('modulename', $element['object']->itemmodule);
1071                        return '<img src="'.$OUTPUT->pix_url('icon',
1072                            $element['object']->itemmodule) . '" ' .
1073                            'class="icon itemicon" title="' .s($strmodname).
1074                            '" alt="' .s($strmodname).'"/>';
1075                    }
1076                } else if ($element['object']->itemtype == 'manual') {
1077                    if ($element['object']->is_outcome_item()) {
1078                        $stroutcome = get_string('outcome', 'grades');
1079                        return '<img src="'.$OUTPUT->pix_url('i/outcomes') . '" ' .
1080                                'class="icon itemicon" title="'.s($stroutcome).
1081                                '" alt="'.s($stroutcome).'"/>';
1082                    } else {
1083                        $strmanual = get_string('manualitem', 'grades');
1084                        return '<img src="'.$OUTPUT->pix_url('t/manual_item') . '" '.
1085                                'class="icon itemicon" title="'.s($strmanual).
1086                                '" alt="'.s($strmanual).'"/>';
1087                    }
1088                }
1089                break;
1090
1091            case 'category':
1092                $strcat = get_string('category', 'grades');
1093                return '<img src="'.$OUTPUT->pix_url('f/folder') . '" class="icon itemicon" ' .
1094                        'title="'.s($strcat).'" alt="'.s($strcat).'" />';
1095        }
1096
1097        if ($spacerifnone) {
1098            return $OUTPUT->spacer().' ';
1099        } else {
1100            return '';
1101        }
1102    }
1103
1104    /**
1105     * Returns name of element optionally with icon and link
1106     *
1107     * @param array &$element An array representing an element in the grade_tree
1108     * @param bool  $withlink Whether or not this header has a link
1109     * @param bool  $icon Whether or not to display an icon with this header
1110     * @param bool  $spacerifnone return spacer if no icon found
1111     *
1112     * @return string header
1113     */
1114    public function get_element_header(&$element, $withlink=false, $icon=true, $spacerifnone=false) {
1115        $header = '';
1116
1117        if ($icon) {
1118            $header .= $this->get_element_icon($element, $spacerifnone);
1119        }
1120
1121        $header .= $element['object']->get_name();
1122
1123        if ($element['type'] != 'item' and $element['type'] != 'categoryitem' and
1124            $element['type'] != 'courseitem') {
1125            return $header;
1126        }
1127
1128        if ($withlink) {
1129            $url = $this->get_activity_link($element);
1130            if ($url) {
1131                $a = new stdClass();
1132                $a->name = get_string('modulename', $element['object']->itemmodule);
1133                $title = get_string('linktoactivity', 'grades', $a);
1134
1135                $header = html_writer::link($url, $header, array('title' => $title));
1136            }
1137        }
1138
1139        return $header;
1140    }
1141
1142    private function get_activity_link($element) {
1143        global $CFG;
1144
1145        $itemtype = $element['object']->itemtype;
1146        $itemmodule = $element['object']->itemmodule;
1147        $iteminstance = $element['object']->iteminstance;
1148
1149        // Links only for module items that have valid instance, module and are
1150        // called from grade_tree with valid modinfo
1151        if ($itemtype != 'mod' || !$iteminstance || !$itemmodule || !$this->modinfo) {
1152            return null;
1153        }
1154
1155        // Get $cm efficiently and with visibility information using modinfo
1156        $instances = $this->modinfo->get_instances();
1157        if (empty($instances[$itemmodule][$iteminstance])) {
1158            return null;
1159        }
1160        $cm = $instances[$itemmodule][$iteminstance];
1161
1162        // Do not add link if activity is not visible to the current user
1163        if (!$cm->uservisible) {
1164            return null;
1165        }
1166
1167        // If module has grade.php, link to that, otherwise view.php
1168        $dir = $CFG->dirroot . '/mod/' . $itemmodule;
1169        if (file_exists($dir.'/grade.php')) {
1170            return new moodle_url('/mod/' . $itemmodule . '/grade.php', array('id' => $cm->id));
1171        } else {
1172            return new moodle_url('/mod/' . $itemmodule . '/view.php', array('id' => $cm->id));
1173        }
1174    }
1175
1176    /**
1177     * Returns the grade eid - the grade may not exist yet.
1178     *
1179     * @param grade_grade $grade_grade A grade_grade object
1180     *
1181     * @return string eid
1182     */
1183    public function get_grade_eid($grade_grade) {
1184        if (empty($grade_grade->id)) {
1185            return 'n'.$grade_grade->itemid.'u'.$grade_grade->userid;
1186        } else {
1187            return 'g'.$grade_grade->id;
1188        }
1189    }
1190
1191    /**
1192     * Returns the grade_item eid
1193     * @param grade_item $grade_item A grade_item object
1194     * @return string eid
1195     */
1196    public function get_item_eid($grade_item) {
1197        return 'i'.$grade_item->id;
1198    }
1199
1200    /**
1201     * Given a grade_tree element, returns an array of parameters
1202     * used to build an icon for that element.
1203     *
1204     * @param array $element An array representing an element in the grade_tree
1205     *
1206     * @return array
1207     */
1208    public function get_params_for_iconstr($element) {
1209        $strparams = new stdClass();
1210        $strparams->category = '';
1211        $strparams->itemname = '';
1212        $strparams->itemmodule = '';
1213
1214        if (!method_exists($element['object'], 'get_name')) {
1215            return $strparams;
1216        }
1217
1218        $strparams->itemname = html_to_text($element['object']->get_name());
1219
1220        // If element name is categorytotal, get the name of the parent category
1221        if ($strparams->itemname == get_string('categorytotal', 'grades')) {
1222            $parent = $element['object']->get_parent_category();
1223            $strparams->category = $parent->get_name() . ' ';
1224        } else {
1225            $strparams->category = '';
1226        }
1227
1228        $strparams->itemmodule = null;
1229        if (isset($element['object']->itemmodule)) {
1230            $strparams->itemmodule = $element['object']->itemmodule;
1231        }
1232        return $strparams;
1233    }
1234
1235    /**
1236     * Return edit icon for give element
1237     *
1238     * @param array  $element An array representing an element in the grade_tree
1239     * @param object $gpr A grade_plugin_return object
1240     *
1241     * @return string
1242     */
1243    public function get_edit_icon($element, $gpr) {
1244        global $CFG, $OUTPUT;
1245
1246        if (!has_capability('moodle/grade:manage', $this->context)) {
1247            if ($element['type'] == 'grade' and has_capability('moodle/grade:edit', $this->context)) {
1248                // oki - let them override grade
1249            } else {
1250                return '';
1251            }
1252        }
1253
1254        static $strfeedback   = null;
1255        static $streditgrade = null;
1256        if (is_null($streditgrade)) {
1257            $streditgrade = get_string('editgrade', 'grades');
1258            $strfeedback  = get_string('feedback');
1259        }
1260
1261        $strparams = $this->get_params_for_iconstr($element);
1262
1263        $object = $element['object'];
1264
1265        switch ($element['type']) {
1266            case 'item':
1267            case 'categoryitem':
1268            case 'courseitem':
1269                $stredit = get_string('editverbose', 'grades', $strparams);
1270                if (empty($object->outcomeid) || empty($CFG->enableoutcomes)) {
1271                    $url = new moodle_url('/grade/edit/tree/item.php',
1272                            array('courseid' => $this->courseid, 'id' => $object->id));
1273                } else {
1274                    $url = new moodle_url('/grade/edit/tree/outcomeitem.php',
1275                            array('courseid' => $this->courseid, 'id' => $object->id));
1276                }
1277                break;
1278
1279            case 'category':
1280                $stredit = get_string('editverbose', 'grades', $strparams);
1281                $url = new moodle_url('/grade/edit/tree/category.php',
1282                        array('courseid' => $this->courseid, 'id' => $object->id));
1283                break;
1284
1285            case 'grade':
1286                $stredit = $streditgrade;
1287                if (empty($object->id)) {
1288                    $url = new moodle_url('/grade/edit/tree/grade.php',
1289                            array('courseid' => $this->courseid, 'itemid' => $object->itemid, 'userid' => $object->userid));
1290                } else {
1291                    $url = new moodle_url('/grade/edit/tree/grade.php',
1292                            array('courseid' => $this->courseid, 'id' => $object->id));
1293                }
1294                if (!empty($object->feedback)) {
1295                    $feedback = addslashes_js(trim(format_string($object->feedback, $object->feedbackformat)));
1296                }
1297                break;
1298
1299            default:
1300                $url = null;
1301        }
1302
1303        if ($url) {
1304            return $OUTPUT->action_icon($gpr->add_url_params($url), new pix_icon('t/edit', $stredit));
1305
1306        } else {
1307            return '';
1308        }
1309    }
1310
1311    /**
1312     * Return hiding icon for give element
1313     *
1314     * @param array  $element An array representing an element in the grade_tree
1315     * @param object $gpr A grade_plugin_return object
1316     *
1317     * @return string
1318     */
1319    public function get_hiding_icon($element, $gpr) {
1320        global $CFG, $OUTPUT;
1321
1322        if (!has_capability('moodle/grade:manage', $this->context) and
1323            !has_capability('moodle/grade:hide', $this->context)) {
1324            return '';
1325        }
1326
1327        $strparams = $this->get_params_for_iconstr($element);
1328        $strshow = get_string('showverbose', 'grades', $strparams);
1329        $strhide = get_string('hideverbose', 'grades', $strparams);
1330
1331        $url = new moodle_url('/grade/edit/tree/action.php', array('id' => $this->courseid, 'sesskey' => sesskey(), 'eid' => $element['eid']));
1332        $url = $gpr->add_url_params($url);
1333
1334        if ($element['object']->is_hidden()) {
1335            $type = 'show';
1336            $tooltip = $strshow;
1337
1338            // Change the icon and add a tooltip showing the date
1339            if ($element['type'] != 'category' and $element['object']->get_hidden() > 1) {
1340                $type = 'hiddenuntil';
1341                $tooltip = get_string('hiddenuntildate', 'grades',
1342                        userdate($element['object']->get_hidden()));
1343            }
1344
1345            $url->param('action', 'show');
1346
1347            $hideicon = $OUTPUT->action_icon($url, new pix_icon('t/'.$type, $tooltip, 'moodle', array('alt'=>$strshow, 'class'=>'iconsmall')));
1348
1349        } else {
1350            $url->param('action', 'hide');
1351            $hideicon = $OUTPUT->action_icon($url, new pix_icon('t/hide', $strhide));
1352        }
1353
1354        return $hideicon;
1355    }
1356
1357    /**
1358     * Return locking icon for given element
1359     *
1360     * @param array  $element An array representing an element in the grade_tree
1361     * @param object $gpr A grade_plugin_return object
1362     *
1363     * @return string
1364     */
1365    public function get_locking_icon($element, $gpr) {
1366        global $CFG, $OUTPUT;
1367
1368        $strparams = $this->get_params_for_iconstr($element);
1369        $strunlock = get_string('unlockverbose', 'grades', $strparams);
1370        $strlock = get_string('lockverbose', 'grades', $strparams);
1371
1372        $url = new moodle_url('/grade/edit/tree/action.php', array('id' => $this->courseid, 'sesskey' => sesskey(), 'eid' => $element['eid']));
1373        $url = $gpr->add_url_params($url);
1374
1375        // Don't allow an unlocking action for a grade whose grade item is locked: just print a state icon
1376        if ($element['type'] == 'grade' && $element['object']->grade_item->is_locked()) {
1377            $strparamobj = new stdClass();
1378            $strparamobj->itemname = $element['object']->grade_item->itemname;
1379            $strnonunlockable = get_string('nonunlockableverbose', 'grades', $strparamobj);
1380
1381            $action = $OUTPUT->pix_icon('t/unlock_gray', $strnonunlockable);
1382
1383        } else if ($element['object']->is_locked()) {
1384            $type = 'unlock';
1385            $tooltip = $strunlock;
1386
1387            // Change the icon and add a tooltip showing the date
1388            if ($element['type'] != 'category' and $element['object']->get_locktime() > 1) {
1389                $type = 'locktime';
1390                $tooltip = get_string('locktimedate', 'grades',
1391                        userdate($element['object']->get_locktime()));
1392            }
1393
1394            if (!has_capability('moodle/grade:manage', $this->context) and !has_capability('moodle/grade:unlock', $this->context)) {
1395                $action = '';
1396            } else {
1397                $url->param('action', 'unlock');
1398                $action = $OUTPUT->action_icon($url, new pix_icon('t/'.$type, $tooltip, 'moodle', array('alt'=>$strunlock, 'class'=>'smallicon')));
1399            }
1400
1401        } else {
1402            if (!has_capability('moodle/grade:manage', $this->context) and !has_capability('moodle/grade:lock', $this->context)) {
1403                $action = '';
1404            } else {
1405                $url->param('action', 'lock');
1406                $action = $OUTPUT->action_icon($url, new pix_icon('t/lock', $strlock));
1407            }
1408        }
1409
1410        return $action;
1411    }
1412
1413    /**
1414     * Return calculation icon for given element
1415     *
1416     * @param array  $element An array representing an element in the grade_tree
1417     * @param object $gpr A grade_plugin_return object
1418     *
1419     * @return string
1420     */
1421    public function get_calculation_icon($element, $gpr) {
1422        global $CFG, $OUTPUT;
1423        if (!has_capability('moodle/grade:manage', $this->context)) {
1424            return '';
1425        }
1426
1427        $type   = $element['type'];
1428        $object = $element['object'];
1429
1430        if ($type == 'item' or $type == 'courseitem' or $type == 'categoryitem') {
1431            $strparams = $this->get_params_for_iconstr($element);
1432            $streditcalculation = get_string('editcalculationverbose', 'grades', $strparams);
1433
1434            $is_scale = $object->gradetype == GRADE_TYPE_SCALE;
1435            $is_value = $object->gradetype == GRADE_TYPE_VALUE;
1436
1437            // show calculation icon only when calculation possible
1438            if (!$object->is_external_item() and ($is_scale or $is_value)) {
1439                if ($object->is_calculated()) {
1440                    $icon = 't/calc';
1441                } else {
1442                    $icon = 't/calc_off';

Large files files are truncated, but you can click here to view the full file