backup MDL-22142 This is the user interface for backups, several minor/cosmetic issue...
authorSam Hemelryk <sam@moodle.com>
Sat, 1 May 2010 09:51:39 +0000 (09:51 +0000)
committerSam Hemelryk <sam@moodle.com>
Sat, 1 May 2010 09:51:39 +0000 (09:51 +0000)
20 files changed:
backup/backup.php
backup/moodle2/backup_activity_task.class.php
backup/moodle2/backup_root_task.class.php
backup/moodle2/backup_section_task.class.php
backup/moodle2/backup_settingslib.php
backup/util/factories/backup_factory.class.php
backup/util/includes/backup_includes.php
backup/util/settings/backup_setting.class.php
backup/util/settings/base_setting.class.php
backup/util/settings/setting_dependency.class.php [new file with mode: 0644]
backup/util/ui/backup_moodleform.class.php [new file with mode: 0644]
backup/util/ui/backup_ui.class.php [new file with mode: 0644]
backup/util/ui/backup_ui_setting.class.php [new file with mode: 0644]
backup/util/ui/backup_ui_stage.class.php [new file with mode: 0644]
backup/util/ui/renderer.php [new file with mode: 0644]
files/index.php
lang/en/backup.php [new file with mode: 0644]
lib/moodlelib.php
theme/base/style/core.css
theme/standard/style/core.css

index 8cdba55..a84885b 100644 (file)
 <?php
-    //This script is used to configure and execute the backup proccess.
 
-    //Define some globals for all the script
-
-    require_once ("../config.php");
-    require_once ("lib.php");
-    require_once ("backuplib.php");
-    require_once ("$CFG->libdir/adminlib.php");
-
-    $id = optional_param('id', 0, PARAM_INT);       // course id
-    $to = optional_param('to', 0, PARAM_INT); // id of course to import into afterwards.
-    $cancel = optional_param('cancel', '', PARAM_RAW);
-    $launch = optional_param('launch', '', PARAM_ACTION);
-
-    $url = new moodle_url('/backup/backup.php');
-    if ($id !== 0) {
-        $url->param('id', $id);
-    }
-    if ($to !== 0) {
-        $url->param('to', $to);
-    }
-    if ($launch !== '') {
-        $url->param('launch', $launch);
-    }
-    $PAGE->set_url($url);
-
-    $loginurl = get_login_url();
-
-    if (!empty($id)) {
-        require_login($id);
-        if (!has_capability('moodle/backup:backupcourse', get_context_instance(CONTEXT_COURSE, $id))) {
-            print_error('cannotuseadminadminorteacher', 'error', $loginurl);
-        }
-    } else {
-        require_login();
-        if (!has_capability('moodle/backup:backupcourse', get_context_instance(CONTEXT_SYSTEM))) {
-            print_error('cannotuseadmin', 'error', $loginurl);
-        }
-    }
-
-    if (!empty($to)) {
-        if (!has_capability('moodle/backup:backupcourse', get_context_instance(CONTEXT_COURSE, $to))) {
-            print_error('cannotuseadminadminorteacher', 'error', $loginurl);
-        }
-    }
-
-    //Check site
-    $site = get_site();
-
-    //Check necessary functions exists. Thanks to gregb@crowncollege.edu
-    backup_required_functions();
-
-    //Get strings
-    if (empty($to)) {
-        $strcoursebackup = get_string("coursebackup");
-    }
-    else {
-        $strcoursebackup = get_string('importdata');
-    }
-    $stradministration = get_string("administration");
-
-    //If cancel has been selected, go back to course main page (bug 2817)
-    if ($cancel) {
-        if ($id) {
-            $redirecto = $CFG->wwwroot . '/course/view.php?id=' . $id; //Course page
-        } else {
-            $redirecto = $CFG->wwwroot.'/';
-        }
-        redirect ($redirecto, get_string('backupcancelled')); //Site page
-        exit;
-    }
-
-    //If no course has been selected, show a list of available courses
-    $PAGE->set_title("$site->shortname: $strcoursebackup");
-    $PAGE->set_heading($site->fullname);
-    if (!$id) {
-        $PAGE->navbar->add($stradministration, new moodle_url('/admin/index.php'));
-        $PAGE->navbar->add($strcoursebackup);
-        echo $OUTPUT->header();
-        if ($courses = get_courses('all','c.shortname','c.id,c.shortname,c.fullname')) {
-            echo $OUTPUT->heading(get_string("choosecourse"));
-            echo $OUTPUT->box_start();
-            foreach ($courses as $course) {
-                echo '<a href="backup.php?id='.$course->id.'">'.format_string($course->fullname).' ('.format_string($course->shortname).')</a><br />'."\n";
-            }
-            echo $OUTPUT->box_end();
-        } else {
-            echo $OUTPUT->heading(get_string("nocoursesyet"));
-            echo $OUTPUT->continue_button("$CFG->wwwroot/$CFG->admin/index.php");
-        }
-        echo $OUTPUT->footer();
-        exit;
-    }
-
-    //Get and check course
-    if (! $course = $DB->get_record("course", array("id"=>$id))) {
-        print_error('unknowncourseidnumber','error');
-    }
-
-    //Print header
-    if (has_capability('moodle/backup:backupcourse', get_context_instance(CONTEXT_SYSTEM))) {
-        $PAGE->navbar->add($stradministration, new moodle_url('/admin/index.php'));
-        $PAGE->navbar->add($strcoursebackup, new moodle_url('/backup/backup.php'));
-        $PAGE->navbar->add("$course->fullname ($course->shortname)");
-        echo $OUTPUT->header();
-    } else {
-        $PAGE->navbar->add($course->fullname, new moodle_url('/course/view.php', array('id'=>$course->id)));
-        $PAGE->navbar->add($strcoursebackup);
-        echo $OUTPUT->header();
-    }
-
-    //Print form
-    echo $OUTPUT->heading(format_string("$strcoursebackup: $course->fullname ($course->shortname)"));
-    echo $OUTPUT->box_start();
-
-    //Adjust some php variables to the execution of this script
-    @ini_set("max_execution_time","3000");
-    raise_memory_limit("192M");
-
-    //Call the form, depending the step we are
-    if (!$launch or !data_submitted() or !confirm_sesskey()) {
-        // if we're at the start, clear the cache of prefs
-        if (isset($SESSION->backupprefs[$course->id])) {
-            unset($SESSION->backupprefs[$course->id]);
-        }
-        include_once("backup_form.html");
-    } else if ($launch == "check") {
-        include_once("backup_check.html");
-    } else if ($launch == "execute") {
-        include_once("backup_execute.html");
-    }
-    echo $OUTPUT->box_end();
-
-    //Print footer
-    echo $OUTPUT->footer();
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+require_once('../config.php');
+require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
+require_once($CFG->dirroot . '/backup/moodle2/backup_plan_builder.class.php');
+
+
+$courseid = required_param('id', PARAM_INT);
+$sectionid = optional_param('section', null, PARAM_INT);
+$cmid = optional_param('cm', null, PARAM_INT);
+
+$url = new moodle_url('/backup/backup.php', array('id'=>$courseid));
+if ($sectionid !== null) {
+    $url->param('section', $sectionid);
+}
+if ($cmid !== null) {
+    $url->param('cm', $cmid);
+}
+$PAGE->set_url($url);
+
+$id = $courseid;
+$cm = null;
+$course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
+$type = backup::TYPE_1COURSE;
+if (!is_null($sectionid)) {
+    $section = $DB->get_record('course_sections', array('course'=>$course->id, 'section'=>$sectionid));
+    $type = backup::TYPE_1SECTION;
+    $id = $sectionid;
+}
+if (!is_null($cmid)) {
+    $cm = get_coursemodule_from_id(null, $cmid, $course->id, $sectionid, MUST_EXIST);
+    $type = backup::TYPE_1ACTIVITY;
+    $id = $cmid;
+}
+require_login($course, false, $cm);
+
+if (!has_capability('moodle/backup:backupcourse', get_context_instance(CONTEXT_COURSE, $course->id))) {
+    print_error('cannotuseadminadminorteacher', 'error');
+}
+
+if (!($bc = backup_ui::load_controller())) {
+    $bc = new backup_controller($type, $id, backup::FORMAT_MOODLE,
+                            backup::INTERACTIVE_YES, backup::MODE_GENERAL, $USER->id);
+}
+$backup = new backup_ui($bc);
+$backup->process();
+if ($backup->get_stage() == backup_ui::STAGE_FINAL) {
+    $backup->execute();
+} else {
+    $backup->save_controller();
+}
+
+$PAGE->set_title(get_string('backup'));
+$PAGE->set_heading(get_string('backup'));
+$PAGE->navbar->add($backup->get_stage_name());
+$PAGE->set_pagelayout('admin');
+
+$renderer = $PAGE->get_renderer('core','backup');
+echo $OUTPUT->header();
+if ($backup->enforce_changed_dependencies()) {
+    echo $renderer->dependency_notification(get_string('dependenciesenforced','backup'));
+}
+echo $renderer->progress_bar($backup->get_progress_bar());
+echo $backup->display();
+echo $OUTPUT->footer();
\ No newline at end of file
index d8e1d99..dcc6387 100644 (file)
@@ -234,6 +234,7 @@ abstract class backup_activity_task extends backup_task {
         // Define activity_userinfo (dependent of root users setting)
         $settingname = $settingprefix . 'userinfo';
         $activity_userinfo = new backup_activity_userinfo_setting($settingname, base_setting::IS_BOOLEAN, true);
+        $activity_userinfo->get_ui()->set_label(get_string('includeuserinfo','backup'));
         $this->add_setting($activity_userinfo);
         // Look for "users" root setting
         $users = $this->plan->get_setting('users');
index a733979..41ae043 100644 (file)
@@ -48,56 +48,69 @@ class backup_root_task extends backup_task {
     protected function define_settings() {
 
         // Define filename setting
-        $this->add_setting(new backup_filename_setting('filename', base_setting::IS_FILENAME, 'backup.zip'));
+        $filename = new backup_filename_setting('filename', base_setting::IS_FILENAME, 'backup.zip');
+        $filename->set_ui(get_string('filename', 'backup'), 'backup.zip');
+        $this->add_setting($filename);
 
         // Define users setting (keeping it on hand to define dependencies)
         $users = new backup_users_setting('users', base_setting::IS_BOOLEAN, true);
+        $users->set_ui(new backup_setting_ui_select($users, $users->get_name(), array(1=>get_string('yes'), 0=>get_string('no'))));
         $this->add_setting($users);
 
         // Define anonymize (dependent of users)
         $anonymize = new backup_anonymize_setting('anonymize', base_setting::IS_BOOLEAN, false);
+        $anonymize->set_ui(new backup_setting_ui_select($anonymize, $anonymize->get_name(), array(1=>get_string('yes'), 0=>get_string('no'))));
         $this->add_setting($anonymize);
         $users->add_dependency($anonymize);
 
         // Define role_assignments (dependent of users)
         $roleassignments = new backup_role_assignments_setting('role_assignments', base_setting::IS_BOOLEAN, true);
+        $roleassignments->set_ui(new backup_setting_ui_select($roleassignments, $roleassignments->get_name(), array(1=>get_string('yes'), 0=>get_string('no'))));
         $this->add_setting($roleassignments);
         $users->add_dependency($roleassignments);
 
         // Define user_files (dependent of users)
         $userfiles = new backup_user_files_setting('user_files', base_setting::IS_BOOLEAN, true);
+        $userfiles->set_ui(new backup_setting_ui_select($userfiles, $userfiles->get_name(), array(1=>get_string('yes'), 0=>get_string('no'))));
         $this->add_setting($userfiles);
         $users->add_dependency($userfiles);
 
         // Define activitites
         $activities = new backup_activities_setting('activities', base_setting::IS_BOOLEAN, true);
+        $activities->set_ui(new backup_setting_ui_select($activities, $activities->get_name(), array(1=>get_string('yes'), 0=>get_string('no'))));
         $this->add_setting($activities);
 
         // Define blocks
         $blocks = new backup_generic_setting('blocks', base_setting::IS_BOOLEAN, true);
+        $blocks->set_ui(new backup_setting_ui_select($blocks, $blocks->get_name(), array(1=>get_string('yes'), 0=>get_string('no'))));
         $this->add_setting($blocks);
 
         // Define filters
         $filters = new backup_generic_setting('filters', base_setting::IS_BOOLEAN, true);
+        $filters->set_ui(new backup_setting_ui_select($filters, $filters->get_name(), array(1=>get_string('yes'), 0=>get_string('no'))));
         $this->add_setting($filters);
 
         // Define comments (dependent of users)
         $comments = new backup_comments_setting('comments', base_setting::IS_BOOLEAN, true);
+        $comments->set_ui(new backup_setting_ui_select($comments, $comments->get_name(), array(1=>get_string('yes'), 0=>get_string('no'))));
         $this->add_setting($comments);
         $users->add_dependency($comments);
 
         // Define completion (dependent of users)
         $completion = new backup_userscompletion_setting('userscompletion', base_setting::IS_BOOLEAN, true);
+        $completion->set_ui(new backup_setting_ui_select($completion, $completion->get_name(), array(1=>get_string('yes'), 0=>get_string('no'))));
         $this->add_setting($completion);
         $users->add_dependency($completion);
 
         // Define logs (dependent of users)
         $logs = new backup_logs_setting('logs', base_setting::IS_BOOLEAN, true);
+        $logs->set_ui(new backup_setting_ui_select($logs, $logs->get_name(), array(1=>get_string('yes'), 0=>get_string('no'))));
         $this->add_setting($logs);
         $users->add_dependency($logs);
 
         // Define grade_histories
         $gradehistories = new backup_generic_setting('grade_histories', base_setting::IS_BOOLEAN, true);
+        $gradehistories->set_ui(new backup_setting_ui_select($gradehistories, $gradehistories->get_name(), array(1=>get_string('yes'), 0=>get_string('no'))));
         $this->add_setting($gradehistories);
     }
 }
index 2a9353d..a63ec64 100644 (file)
@@ -109,6 +109,7 @@ class backup_section_task extends backup_task {
         // Define section_userinfo (dependent of root users setting)
         $settingname = $settingprefix . 'userinfo';
         $section_userinfo = new backup_section_userinfo_setting($settingname, base_setting::IS_BOOLEAN, true);
+        $section_userinfo->get_ui()->set_label(get_string('includeuserinfo','backup'));
         $this->add_setting($section_userinfo);
         // Look for "users" root setting
         $users = $this->plan->get_setting('users');
index 8b48c0c..0fba834 100644 (file)
@@ -37,6 +37,15 @@ class backup_generic_setting extends root_backup_setting {
  * root setting to handle backup file names (no dependencies nor anything else)
  */
 class backup_filename_setting extends backup_generic_setting {
+
+    public function  __construct($name, $vtype, $value = null, $visibility = self::VISIBLE, $status = self::NOT_LOCKED) {
+        parent::__construct($name, $vtype, $value, $visibility, $status);
+    }
+
+    public function set_ui($label, $value, array $options = null) {
+        parent::make_ui(self::UI_HTML_TEXTFIELD, $label, null, $options);
+        $this->set_value($value);
+    }
 }
 
 /**
index 7e334b8..480daee 100644 (file)
@@ -136,7 +136,7 @@ abstract class backup_factory {
             throw new backup_task_exception('section_task_section_not_found', $sectionid);
         }
 
-        return new backup_section_task($section->section, $sectionid);
+        return new backup_section_task(empty($section->name) ? $section->section : $section->name, $sectionid);
     }
 
     /**
index 936d7e6..edc7772 100644 (file)
@@ -68,6 +68,7 @@ require_once($CFG->dirroot . '/backup/util/loggers/error_log_logger.class.php');
 require_once($CFG->dirroot . '/backup/util/loggers/file_logger.class.php');
 require_once($CFG->dirroot . '/backup/util/loggers/database_logger.class.php');
 require_once($CFG->dirroot . '/backup/util/loggers/output_indented_logger.class.php');
+require_once($CFG->dirroot . '/backup/util/settings/setting_dependency.class.php');
 require_once($CFG->dirroot . '/backup/util/settings/base_setting.class.php');
 require_once($CFG->dirroot . '/backup/util/settings/backup_setting.class.php');
 require_once($CFG->dirroot . '/backup/util/settings/root/root_backup_setting.class.php');
@@ -83,6 +84,10 @@ require_once($CFG->dirroot . '/backup/util/plan/backup_step.class.php');
 require_once($CFG->dirroot . '/backup/util/plan/backup_structure_step.class.php');
 require_once($CFG->dirroot . '/backup/util/plan/backup_execution_step.class.php');
 require_once($CFG->dirroot . '/backup/controller/backup_controller.class.php');
+require_once($CFG->dirroot . '/backup/util/ui/backup_moodleform.class.php');
+require_once($CFG->dirroot . '/backup/util/ui/backup_ui.class.php');
+require_once($CFG->dirroot . '/backup/util/ui/backup_ui_stage.class.php');
+require_once($CFG->dirroot . '/backup/util/ui/backup_ui_setting.class.php');
 
 // And some moodle stuff too
 require_once($CFG->libdir.'/gradelib.php');
index 3eef5d4..666050e 100644 (file)
@@ -41,15 +41,12 @@ abstract class backup_setting extends base_setting implements checksumable {
         return $this->level;
     }
 
-    public function add_dependency($obj) {
-        if (! $obj instanceof backup_setting) {
-            throw new backup_setting_exception('dependency_is_not_backkup_setting');
-        }
+    public function add_dependency(backup_setting $dependentsetting, $type=setting_dependency::DISABLED_VALUE, $options=array()) {
         // Check the dependency level is >= current level
-        if ($obj->get_level() < $this->level) {
+        if ($dependentsetting->get_level() < $this->level) {
             throw new backup_setting_exception('cannot_add_upper_level_dependency');
         }
-        parent::add_dependency($obj);
+        parent::add_dependency($dependentsetting, $type, $options);
     }
 
 // checksumable interface methods
@@ -64,6 +61,18 @@ abstract class backup_setting extends base_setting implements checksumable {
     public function is_checksum_correct($checksum) {
         return $this->calculate_checksum() === $checksum;
     }
+
+    public function get_dependencies() {
+        return $this->dependencies;
+    }
+
+    public function get_ui_name() {
+        return $this->uisetting->get_name();
+    }
+
+    public function get_ui_type() {
+        return $this->uisetting->get_type();
+    }
 }
 
 /*
index d0bbdff..f8222da 100644 (file)
@@ -71,6 +71,12 @@ abstract class base_setting {
 
     protected $dependencies; // array of dependent (observer) objects (usually setting_base ones)
 
+    /**
+     *
+     * @var backup_setting_ui|backup_setting_ui_checkbox|backup_setting_ui_radio|backup_setting_ui_select|backup_setting_ui_text
+     */
+    protected $uisetting;
+
     // Note: all the UI stuff could go to independent classes in the future...
     protected $ui_type;   // setting_base::UI_HTML_CHECKBOX/setting_base::UI_HTML_RADIOBUTTON...
     protected $ui_label;  // UI label of the setting
@@ -100,11 +106,8 @@ abstract class base_setting {
         $this->status      = $status;
         $this->dependencies= array();
 
-        // Apply these defaults
-        $this->ui_type    = self::UI_HTML_DROPDOWN;
-        $this->ui_label   = $name;
-        $this->ui_values  = array();
-        $this->ui_options = array();
+        // Generate a default ui
+        $this->uisetting = new backup_setting_ui_checkbox($this, $name);
     }
 
     public function get_name() {
@@ -152,7 +155,6 @@ abstract class base_setting {
     }
 
     public function set_status($status) {
-        print_object('setting '. $this->name . ' to status ' . $status);
         $status = $this->validate_status($status);
         $oldstatus = $this->status;
         $this->status = $status;
@@ -161,35 +163,95 @@ abstract class base_setting {
         }
     }
 
-    public function set_ui($type, $label, $values, $options) {
-        $type = $this->validate_ui_type($type);
-        $label =$this->validate_ui_label($label);
-        $this->ui_type    = $type;
-        $this->ui_label   = $label;
-        $this->set_ui_values($values);
-        $this->set_ui_options($options);
+    public function set_ui(backup_setting_ui $ui) {
+        $this->uisetting = $ui;
     }
 
-    public function set_ui_values($values) {
-        $this->ui_values = $values;
+    public function make_ui($type, $label, array $attributes = null, array $options = null) {
+        $type = $this->validate_ui_type($type);
+        $label = $this->validate_ui_label($label);
+        $this->uisetting = backup_setting_ui::make($this, $type, $label, $attributes, $options);
+        if (is_array($options) || is_object($options)) {
+            $options = (array)$options;
+            switch (get_class($this->uisetting)) {
+                case 'backup_setting_ui_radio' :
+                    // text
+                    if (array_key_exists('text', $options)) {
+                        $this->uisetting->set_text($options['text']);
+                    }
+                case 'backup_setting_ui_checkbox' :
+                    // value
+                    if (array_key_exists('value', $options)) {
+                        $this->uisetting->set_value($options['value']);
+                    }
+                    break;
+                case 'backup_setting_ui_select' :
+                    // options
+                    if (array_key_exists('options', $options)) {
+                        $this->uisetting->set_values($options['options']);
+                    }
+                    break;
+            }
+        }
     }
 
-    public function set_ui_options($options) {
-        $this->ui_options = $options;
+    public function get_ui() {
+        return $this->uisetting;
     }
 
-    public function add_dependency($obj) {
-        if ($this->is_circular_reference($obj)) {
+    public function add_dependency(base_setting $dependentsetting, $type=null, $options=array()) {
+        if ($this->is_circular_reference($dependentsetting)) {
             $a = new stdclass();
             $a->alreadydependent = $this->name;
-            $a->main = $obj->get_name();
+            $a->main = $dependentsetting->get_name();
             throw new base_setting_exception('setting_circular_reference', $a);
         }
         // Check the settings hasn't been already added
-        if (array_key_exists($obj->get_name(), $this->dependencies)) {
+        if (array_key_exists($dependentsetting->get_name(), $this->dependencies)) {
             throw new base_setting_exception('setting_already_added');
         }
-        $this->dependencies[$obj->get_name()] = $obj;
+
+        $options = (array)$options;
+
+        if (!array_key_exists('defaultvalue', $options)) {
+            $options['defaultvalue'] = false;
+        }
+
+        if ($type == null) {
+            switch ($this->vtype) {
+                case self::IS_BOOLEAN :
+                    if ($this->value) {
+                        $type = setting_dependency::DISABLED_FALSE;
+                    } else {
+                        $type = setting_dependency::DISABLED_TRUE;
+                    }
+                    break;
+                case self::IS_FILENAME :
+                case self::IS_PATH :
+                case self::IS_INTEGER :
+                default :
+                    $type = setting_dependency::DISABLED_VALUE;
+                    break;
+            }
+        }
+
+        switch ($type) {
+            case setting_dependency::DISABLED_VALUE :
+                if (!array_key_exists('value', $options)) {
+                    throw new base_setting_exception('dependency_needs_value');
+                }
+                $dependency = new setting_dependency_disabledif_equals($this, $dependentsetting, $options['value'], $options['defaultvalue']);
+                break;
+            case setting_dependency::DISABLED_TRUE :
+            case setting_dependency::DISABLED_CHECKED :
+                $dependency = new setting_dependency_disabledif_equals($this, $dependentsetting, true, $options['defaultvalue']);
+                break;
+            case setting_dependency::DISABLED_FALSE :
+            case setting_dependency::DISABLED_NOT_CHECKED :
+                $dependency = new setting_dependency_disabledif_equals($this, $dependentsetting, false, $options['defaultvalue']);
+                break;
+        }
+        $this->dependencies[$dependentsetting->get_name()] = $dependency;
     }
 
 // Protected API starts here
@@ -263,7 +325,7 @@ abstract class base_setting {
 
     protected function inform_dependencies($ctype, $oldv) {
         foreach ($this->dependencies as $dependency) {
-            $dependency->process_change($this, $ctype, $oldv);
+            $dependency->process_change($ctype, $oldv);
         }
     }
 
@@ -279,7 +341,7 @@ abstract class base_setting {
     protected function get_dependencies() {
         $dependencies = array();
         foreach ($this->dependencies as $dependency) {
-            $dependencies[$dependency->get_name()] = $dependency->get_name();
+            $dependencies[$dependency->get_dependant_setting()->get_name()] = $dependency->get_dependant_setting();
             $dependencies = array_merge($dependencies, $dependency->get_dependencies());
         }
         return $dependencies;
diff --git a/backup/util/settings/setting_dependency.class.php b/backup/util/settings/setting_dependency.class.php
new file mode 100644 (file)
index 0000000..a851f00
--- /dev/null
@@ -0,0 +1,252 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * @package   moodlecore
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Generic abstract dependency class
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+abstract class setting_dependency {
+
+    /**
+     * Used to define the type of a dependency.
+     *
+     * Note with these that checked and true, and not checked and false are equal.
+     * This is because the terminology differs but the resulting action is the same.
+     * Reduces code!
+     */
+    const DISABLED_VALUE = 0;
+    const DISABLED_NOT_VALUE = 1;
+    const DISABLED_CHECKED = 2;
+    const DISABLED_TRUE = 2;
+    const DISABLED_NOT_CHECKED = 3;
+    const DISABLED_FALSE = 3;
+
+    /**
+     * The parent setting (primary)
+     * @var base_setting
+     */
+    protected $setting;
+    /**
+     * The dependent setting (secondary)
+     * @var base_setting
+     */
+    protected $dependentsetting;
+    /**
+     * The default setting
+     * @var mixed
+     */
+    protected $defaultvalue;
+    /**
+     * The last value the dependent setting had
+     * @var mixed
+     */
+    protected $lastvalue;
+    /**
+     * Creates the dependency object
+     * @param base_setting $setting The parent setting or the primary setting if you prefer
+     * @param base_setting $dependentsetting The dependent setting
+     * @param mixed $defaultvalue The default value to assign if the dependency is unmet
+     */
+    public function __construct(base_setting $setting, base_setting $dependentsetting, $defaultvalue = false) {
+        $this->setting = $setting;
+        $this->dependentsetting = $dependentsetting;
+        $this->defaultvalue = $defaultvalue;
+        $this->lastvalue = $dependentsetting->get_value();
+    }
+    /**
+     * Processes a change is setting called by the primary setting
+     * @param int $changetype
+     * @param mixed $oldvalue
+     * @return bool
+     */
+    final public function process_change($changetype, $oldvalue) {
+        // Check the type of change requested
+        switch ($changetype) {
+            // Process a status change
+            case base_setting::CHANGED_STATUS: return $this->process_status_change($oldvalue);
+            // Process a visibility change
+            case base_setting::CHANGED_VISIBILITY: return $this->process_visibility_change($oldvalue);
+            // Process a value change
+            case base_setting::CHANGED_VALUE: return $this->process_value_change($oldvalue);
+        }
+        // Throw an exception if we get this far
+        throw new backup_ui_exception('unknownchangetype');
+    }
+    /**
+     * Processes a visibility change
+     * @param bool $oldvisibility
+     * @return bool
+     */
+    protected function process_visibility_change($oldvisibility) {
+        // Store the current dependent settings visibility for comparison
+        $prevalue = $this->dependentsetting->get_visibility();
+        // Set it regardless of whether we need to
+        $this->dependentsetting->set_visibility($this->setting->get_visibility());
+        // Return true if it changed
+        return ($prevalue != $this->dependentsetting->get_visibility());
+    }
+    /**
+     * All dependencies must define how they would like to deal with a status change
+     * @param int $oldstatus
+     */
+    abstract protected function process_status_change($oldstatus);
+    /**
+     * All dependencies must define how they would like to process a value change
+     */
+    abstract protected function process_value_change($oldvalue);
+    /**
+     * Gets the primary setting
+     * @return backup_setting
+     */
+    public function get_setting() {
+        return $this->setting;
+    }
+    /**
+     * Gets the dependent setting
+     * @return backup_setting
+     */
+    public function get_dependant_setting() {
+        return $this->dependentsetting;
+    }
+}
+
+/**
+ * A dependency that disables the secondary setting if the primary setting is
+ * equal to the provided value
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class setting_dependency_disabledif_equals extends setting_dependency {
+    /**
+     * The value to compare to
+     * @var mixed
+     */
+    protected $value;
+    /**
+     * Creates the dependency
+     *
+     * @param base_setting $setting
+     * @param base_setting $dependentsetting
+     * @param mixed $value
+     * @param mixed $defaultvalue
+     */
+    public function __construct(base_setting $setting, base_setting $dependentsetting, $value, $defaultvalue = false) {
+        parent::__construct($setting, $dependentsetting, $defaultvalue);
+        $this->value = $value;
+    }
+    /**
+     * Processes a value change in the primary setting
+     * @param mixed $oldvalue
+     * @return bool
+     */
+    protected function process_value_change($oldvalue) {
+        $prevalue = $this->dependentsetting->get_value();
+        // If the setting is the desired value enact the dependency
+        if ($this->setting->get_value() == $this->value) {
+            // The dependent setting needs to be locked by hierachy and set to the
+            // default value.
+            $this->dependentsetting->set_status(base_setting::LOCKED_BY_HIERARCHY);
+            $this->dependentsetting->set_value($this->defaultvalue);
+        } else if ($this->dependentsetting->get_status() == base_setting::LOCKED_BY_HIERARCHY) {
+            // We can unlock the dependent setting and reset its value to the
+            // last value the user had for it.
+            $this->dependentsetting->set_status(base_setting::NOT_LOCKED);
+            $this->dependentsetting->set_value($this->lastvalue);
+        }
+        // Return true if the value has changed for the dependent setting
+        return ($prevalue != $this->dependentsetting->get_value());
+    }
+    /**
+     * Processes a status change in the primary setting
+     * @param mixed $oldstatus
+     * @return bool
+     */
+    protected function process_status_change($oldstatus) {
+        // Store the dependent status
+        $prevalue = $this->dependentsetting->get_status();
+        // Store the current status
+        $currentstatus = $this->setting->get_status();
+        if ($currentstatus == base_setting::NOT_LOCKED) {
+            if ($prevalue == base_setting::LOCKED_BY_HIERARCHY && $this->setting->get_value() != $this->value) {
+                // Dependency has changes, is not fine, unlock the dependent setting
+                $this->dependentsetting->set_status(base_setting::NOT_LOCKED);
+            }
+        } else {
+            // Make sure the dependent setting is also locked, in this case by hierarchy
+            $this->dependentsetting->set_status(base_setting::LOCKED_BY_HIERARCHY);
+        }
+        // Return true if the dependent setting has changed.
+        return ($prevalue != $this->dependentsetting->get_status());
+    }
+    /**
+     * Enforces the dependency if required.
+     * @return bool True if there were changes
+     */
+    public function enforce() {
+        // This will be set to true if ANYTHING changes
+        $changes = false;
+        // First process any value changes
+        if ($this->process_value_change($this->setting->get_value())) {
+            $changes = true;
+        }
+        // Second process any status changes
+        if ($this->process_status_change($this->setting->get_status())) {
+            $changes = true;
+        }
+        // Finally process visibility changes
+        if ($this->process_visibility_change($this->setting->get_visibility())) {
+            $changes = true;
+        }
+        return $changes;
+    }
+}
+/**
+ * A dependency that disables the secondary element if the primary element is
+ * true or checked
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class setting_dependency_disabledif_checked extends setting_dependency_disabledif_equals {
+    public function __construct(base_setting $setting, base_setting $dependentsetting) {
+        parent::__construct($setting, $dependentsetting, $defaultvalue = false);
+        $this->value = true;
+    }
+}
+
+/**
+ * A dependency that disables the secondary element if the primary element is
+ * false or not checked
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class setting_dependency_disabledif_notchecked extends setting_dependency_disabledif_equals {
+    public function __construct(base_setting $setting, base_setting $dependentsetting, $defaultvalue = false) {
+        parent::__construct($setting, $dependentsetting);
+        $this->value = false;
+    }
+}
\ No newline at end of file
diff --git a/backup/util/ui/backup_moodleform.class.php b/backup/util/ui/backup_moodleform.class.php
new file mode 100644 (file)
index 0000000..92a4a35
--- /dev/null
@@ -0,0 +1,268 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains the generic moodleform bridge for the backup user interface
+ * as well as the individual forms that relate to the different stages the user
+ * interface can exist within.
+ * 
+ * @package   moodlecore
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Backup moodleform bridge
+ *
+ * Ahhh the mighty moodleform bridge! Strong enough to take the weight of 682 full
+ * grown african swallows all of whom have been carring coconuts for several days.
+ * EWWWWW!!!!!!!!!!!!!!!!!!!!!!!!
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+abstract class backup_moodleform extends moodleform {
+    /**
+     * The stage this form belongs to
+     * @var backup_ui_stage
+     */
+    protected $uistage = null;
+    /**
+     * True if we have a course div open, false otherwise
+     * @var bool
+     */
+    protected $coursediv = false;
+    /**
+     * True if we have a section div open, false otherwise
+     * @var bool
+     */
+    protected $sectiondiv = false;
+    /**
+     * True if we have an activity div open, false otherwise
+     * @var bool
+     */
+    protected $activitydiv = false;
+    /**
+     * Creates the form
+     *
+     * @param backup_ui_stage $uistage
+     * @param moodle_url|string $action
+     * @param mixed $customdata
+     * @param string $method get|post
+     * @param string $target
+     * @param array $attributes
+     * @param bool $editable
+     */
+    function __construct(backup_ui_stage $uistage, $action=null, $customdata=null, $method='post', $target='', $attributes=null, $editable=true) {
+        $this->uistage = $uistage;
+        parent::__construct($action, $customdata, $method, $target, $attributes, $editable);
+    }
+    /**
+     * The standard form definition... obviously not much here
+     */
+    function definition() {
+        $mform = $this->_form;
+        $stage = $mform->addElement('hidden', 'stage', $this->uistage->get_next_stage());
+        $stage = $mform->addElement('hidden', 'backup', $this->uistage->get_backupid());
+    }
+    /**
+     * Definition applied after the data is organised.. why's it here? because I want
+     * to add elements on the fly.
+     */
+    function definition_after_data() {
+        $mform = $this->_form;
+        $this->add_action_buttons(get_string('cancel'), get_string('onstage'.$this->uistage->get_stage().'action', 'backup'));
+    }
+    /**
+     * Closes any open divs
+     */
+    function close_task_divs() {
+        if ($this->activitydiv) {
+            $this->_form->addElement('html', html_writer::end_tag('div'));
+            $this->activitydiv = false;
+        }
+        if ($this->sectiondiv) {
+            $this->_form->addElement('html', html_writer::end_tag('div'));
+            $this->sectiondiv = false;
+        }
+        if ($this->coursediv) {
+            $this->_form->addElement('html', html_writer::end_tag('div'));
+            $this->coursediv = false;
+        }
+    }
+    /**
+     * Adds the backup_setting as a element to the form
+     * @param backup_setting $setting
+     * @return bool
+     */
+    function add_setting(backup_setting $setting, backup_task $task=null) {
+        $mform = $this->_form;
+        if ($setting->get_visibility() != backup_setting::VISIBLE) {
+            return false;
+        }
+        if ($setting->get_status() == backup_setting::NOT_LOCKED) {
+            // First add the formatting for this setting
+            $this->add_html_formatting($setting);
+            // The call the add method with the get_element_properties array
+            call_user_method_array('addElement', $mform, $setting->get_ui()->get_element_properties($task));
+            $mform->setDefault($setting->get_ui_name(), $setting->get_value());
+            $this->_form->addElement('html', html_writer::end_tag('div'));
+        } else {
+            // Add as a fixed unchangeable setting
+            $this->add_fixed_setting($setting);
+        }
+        return true;
+    }
+    /**
+     * Adds a heading to the form
+     * @param string $name
+     * @param string $text
+     */
+    function add_heading($name , $text) {
+        $this->_form->addElement('header', $name, $text);
+    }
+    /**
+     * Adds HTML formatting for the given backup setting, needed to group/segment
+     * correctly.
+     * @param backup_setting $setting
+     */
+    protected function add_html_formatting(backup_setting $setting) {
+        $mform = $this->_form;
+        $isincludesetting = (strpos($setting->get_name(), '_include')!==false);
+        if ($isincludesetting && $setting->get_level() != backup_setting::ROOT_LEVEL)  {
+            switch ($setting->get_level()) {
+                case backup_setting::COURSE_LEVEL:
+                    if ($this->activitydiv) {
+                        $this->_form->addElement('html', html_writer::end_tag('div'));
+                        $this->activitydiv = false;
+                    }
+                    if ($this->sectiondiv) {
+                        $this->_form->addElement('html', html_writer::end_tag('div'));
+                        $this->sectiondiv = false;
+                    }
+                    if ($this->coursediv) {
+                        $this->_form->addElement('html', html_writer::end_tag('div'));
+                    }
+                    $mform->addElement('html', html_writer::start_tag('div', array('class'=>'grouped_settings course_level')));
+                    $mform->addElement('html', html_writer::start_tag('div', array('class'=>'include_setting course_level')));
+                    $this->coursediv = true;
+                    break;
+                case backup_setting::SECTION_LEVEL:
+                    if ($this->activitydiv) {
+                        $this->_form->addElement('html', html_writer::end_tag('div'));
+                        $this->activitydiv = false;
+                    }
+                    if ($this->sectiondiv) {
+                        $this->_form->addElement('html', html_writer::end_tag('div'));
+                    }
+                    $mform->addElement('html', html_writer::start_tag('div', array('class'=>'grouped_settings section_level')));
+                    $mform->addElement('html', html_writer::start_tag('div', array('class'=>'include_setting section_level')));
+                    $this->sectiondiv = true;
+                    break;
+                case backup_setting::ACTIVITY_LEVEL:
+                    if ($this->activitydiv) {
+                        $this->_form->addElement('html', html_writer::end_tag('div'));
+                    }
+                    $mform->addElement('html', html_writer::start_tag('div', array('class'=>'grouped_settings activity_level')));
+                    $mform->addElement('html', html_writer::start_tag('div', array('class'=>'include_setting activity_level')));
+                    $this->activitydiv = true;
+                    break;
+                default:
+                    $mform->addElement('html', html_writer::start_tag('div', array('class'=>'normal_setting')));
+                    break;
+            }
+        } else if ($setting->get_level() == backup_setting::ROOT_LEVEL) {
+            $mform->addElement('html', html_writer::start_tag('div', array('class'=>'root_setting')));
+        } else {
+            $mform->addElement('html', html_writer::start_tag('div', array('class'=>'normal_setting')));
+        }
+    }
+    /**
+     * Adds a fixed or static setting to the form
+     * @param backup_setting $setting
+     */
+    function add_fixed_setting(backup_setting $setting) {
+        $this->add_html_formatting($setting);
+
+        $mform = $this->_form;
+        $settingui = $setting->get_ui();
+        if ($setting->get_status() != backup_setting::NOT_LOCKED) {
+            $mform->addElement('static', 'static_'.$settingui->get_name(), $settingui->get_label(), get_string('settingislocked','backup',$settingui->get_static_value()));
+        } else {
+            $mform->addElement('static','static_'. $settingui->get_name(), $settingui->get_label(), $settingui->get_static_value());
+        }
+        $mform->addElement('hidden', $settingui->get_name(), $settingui->get_value());
+
+        $this->_form->addElement('html', html_writer::end_tag('div'));
+    }
+    /**
+     * Adds dependencies to the form recursively
+     * 
+     * @param backup_setting $setting
+     * @param backup_setting $basesetting
+     */
+    function add_dependencies(backup_setting $setting, $basesetting=null) {
+        $mform = $this->_form;
+        if ($basesetting == null) {
+            $basesetting = $setting;
+        }
+        foreach ($setting->get_dependencies() as $dependency) {
+            $dependency = $dependency->get_dependant_setting();
+            switch ($basesetting->get_ui_type()) {
+                case backup_setting::UI_HTML_CHECKBOX :
+                    $mform->disabledIf($dependency->get_ui_name(), $basesetting->get_ui_name(), 'notchecked');
+                    $this->add_dependencies($dependency, $basesetting);
+                    break;
+                case backup_setting::UI_HTML_DROPDOWN :
+                    $mform->disabledIf($dependency->get_ui_name(), $basesetting->get_ui_name(), 'eq', 0);
+                    $this->add_dependencies($dependency, $basesetting);
+                    break;
+                default:
+                    debugging('Unknown backup setting type', DEBUG_DEVELOPER);
+                    break;
+            }
+        }
+    }
+    /**
+     * Returns true if the form was cancelled, false otherwise
+     * @return bool
+     */
+    public function is_cancelled() {
+        return (optional_param('cancel', false, PARAM_BOOL) || parent::is_cancelled());
+    }
+}
+/**
+ * Initial backup user interface stage moodleform.
+ *
+ * Nothing to override we only need it defined so that moodleform doesn't get confused
+ * between stages.
+ */
+class backup_initial_form extends backup_moodleform {}
+/**
+ * Schema backup user interface stage moodleform.
+ *
+ * Nothing to override we only need it defined so that moodleform doesn't get confused
+ * between stages.
+ */
+class backup_schema_form extends backup_moodleform {}
+/**
+ * Confirmation backup user interface stage moodleform.
+ *
+ * Nothing to override we only need it defined so that moodleform doesn't get confused
+ * between stages.
+ */
+class backup_confirmation_form extends backup_moodleform {}
\ No newline at end of file
diff --git a/backup/util/ui/backup_ui.class.php b/backup/util/ui/backup_ui.class.php
new file mode 100644 (file)
index 0000000..8641be6
--- /dev/null
@@ -0,0 +1,346 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains the backup user interface class
+ *
+ * @package   moodlecore
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * This is the backup user interface class
+ *
+ * The backup user interface class manages the user interface and backup for
+ * Moodle.
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class backup_ui {
+    /**
+     * The stages of the backup user interface.
+     */
+    const STAGE_INITIAL = 1;
+    const STAGE_SCHEMA = 2;
+    const STAGE_CONFIRMATION = 4;
+    const STAGE_FINAL = 8;
+    /**
+     * The progress of this instance of the backup ui class
+     */
+    const PROGRESS_INTIAL = 0;
+    const PROGRESS_PROCESSED = 1;
+    const PROGRESS_SAVED = 2;
+    const PROGRESS_EXECUTED = 3;
+    /**
+     * The backup controller
+     * @var backup_controller
+     */
+    protected $controller;
+    /**
+     * The current stage
+     * @var backup_ui_stage
+     */
+    protected $stage;
+    /**
+     * The current progress of the UI
+     * @var int One of self::PROGRESS_*
+     */
+    protected $progress;
+    /**
+     * The number of changes made by dependency enforcement
+     * @var int
+     */
+    protected $dependencychanges = 0;
+
+    /**
+     * Yay for constructors
+     * @param backup_controller $controller
+     */
+    public function __construct(backup_controller $controller) {
+        $this->controller = $controller;
+        $this->progress = self::PROGRESS_INTIAL;
+        $this->stage = $this->initialise_stage();
+    }
+    /**
+     * Intialises what ever stage is requested. If none are requested we check
+     * params for 'stage' and default to initial
+     *
+     * @param int|null $stage The desired stage to intialise or null for the default
+     * @return backup_ui_stage_initial|backup_ui_stage_schema|backup_ui_stage_confirmation|backup_ui_stage_final
+     */
+    protected function initialise_stage($stage = null) {
+        if ($stage == null) {
+            $stage = optional_param('stage', self::STAGE_INITIAL, PARAM_INT);
+        }
+        switch ($stage) {
+            case backup_ui::STAGE_INITIAL:
+                $stage = new backup_ui_stage_initial($this);
+                break;
+            case backup_ui::STAGE_SCHEMA:
+                $stage = new backup_ui_stage_schema($this);
+                break;
+            case backup_ui::STAGE_CONFIRMATION:
+                $stage = new backup_ui_stage_confirmation($this);
+                break;
+            case backup_ui::STAGE_FINAL:
+                $stage = new backup_ui_stage_final($this);
+                break;
+            default:
+                $stage = false;
+                break;
+        }
+        return $stage;
+    }
+    /**
+     * This passes off processing for the current stage to the previous stage.
+     *
+     * This occurs when the current stage hasn't been completed yet
+     *
+     * @param backup_ui_stage $stage
+     * @return bool
+     */
+    public function process_previous_stage(backup_ui_stage $stage) {
+        $prevstage = $stage->get_prev_stage();
+        if ($prevstage) {
+            $prevstage = $this->initialise_stage($prevstage);
+            if ($prevstage) {
+                return $prevstage->process();
+            }
+        }
+        return false;
+    }
+    /**
+     * This magical function processes all previous stages to the provided stage
+     * given its backup_moodleform
+     *
+     * @param backup_ui_stage $stage
+     * @param backup_moodleform $form
+     * @return int The number of changes made by the user
+     */
+    public function process_all_previous_stages(backup_ui_stage $stage, backup_moodleform $form) {
+        $stages = array();
+        // First get an instance of each previous stage
+        while ($stage instanceof backup_ui_stage) {
+            $stage = $stage->get_prev_stage();
+            if ($stage) {
+                $stage = $this->initialise_stage($stage);
+                $stages[] = $stage;
+            }
+        }
+        $stages = array_reverse($stages);
+        $changes = 0;
+        // The process each stage in the correct order.
+        foreach ($stages as $stage) {
+            $outcome = $stage->process($form);
+            // Check it didn't fail
+            if ($outcome === false) {
+                throw new backup_ui_exception('backup_ui_process_all_previous_stages_failed', $stage->get_stage());
+            }
+            $changes += $outcome;
+        }
+        return $changes;
+    }
+    /**
+     * This processes the current stage of the backup
+     * @return bool
+     */
+    public function process() {
+        if ($this->progress >= self::PROGRESS_PROCESSED) {
+            throw new backup_ui_exception('backupuialreadyprocessed');
+        }
+        $this->progress = self::PROGRESS_PROCESSED;
+        return $this->stage->process();
+    }
+    /**
+     * Saves the backup controller.
+     *
+     * Once this has been called nothing else can be changed in the controller.
+     *
+     * @return bool
+     */
+    public function save_controller() {
+        if ($this->progress >= self::PROGRESS_SAVED) {
+            throw new backup_ui_exception('backupuialreadysaved');
+        }
+        $this->progress = self::PROGRESS_SAVED;
+        // First enforce dependencies
+        $this->enforce_dependencies();
+        // Save the controller
+        $this->controller->save_controller();
+        return true;
+    }
+    /**
+     * Displays the UI for the backup!
+     *
+     * Note: The UI makes use of mforms (ewww!) thus it will automatically print
+     * out the result rather than returning a string of HTML like other parts of Moodle
+     *
+     * @return bool
+     */
+    public function display() {
+        if ($this->progress < self::PROGRESS_SAVED) {
+            throw new backup_ui_exception('backupsavebeforedisplay');
+        }
+        $this->stage->display();
+    }
+    /**
+     * Gets all backup tasks from the controller
+     * @return array Array of backup_task
+     */
+    public function get_backup_tasks() {
+        $plan = $this->controller->get_plan();
+        $tasks = $plan->get_tasks();
+        return $tasks;
+    }
+    /**
+     * Gets the stage we are on
+     * @return backup_ui_stage
+     */
+    public function get_stage() {
+        return $this->stage->get_stage();
+    }
+    /**
+     * Gets the name of the stage we are on
+     * @return string
+     */
+    public function get_stage_name() {
+        return $this->stage->get_name();
+    }
+    /**
+     * Gets the backup id from the controller
+     * @return string
+     */
+    public function get_backupid() {
+        return $this->controller->get_backupid();
+    }
+    /**
+     * Executes the backup plan
+     * @return bool
+     */
+    public function execute() {
+        if ($this->progress >= self::PROGRESS_EXECUTED) {
+            throw new backup_ui_exception('backupuialreadyexecuted');
+        }
+        if ($this->stage->get_stage() < self::STAGE_FINAL) {
+            throw new backup_ui_exception('backupuifinalisedbeforeexecute');
+        }
+        $this->progress = self::PROGRESS_EXECUTED;
+        $this->controller->finish_ui();
+        $this->controller->execute_plan();
+        $this->stage = new backup_ui_stage_complete($this, $this->controller->get_results());
+        return true;
+    }
+    /**
+     * Enforces dependencies on all settings. Call before save
+     * @return bool True if dependencies were enforced and changes were made
+     */
+    protected function enforce_dependencies() {
+        // Get the plan
+        $plan = $this->controller->get_plan();
+        // Get the tasks as a var so we can iterate by reference
+        $tasks = $plan->get_tasks();
+        $changes = 0;
+        foreach ($tasks as &$task) {
+            // Store as a var so we can iterate by reference
+            $settings = $task->get_settings();
+            foreach ($settings as &$setting) {
+                // Get all dependencies for iteration by reference
+                $dependencies = $setting->get_dependencies();
+                foreach ($dependencies as &$dependency) {
+                    // Enforce each dependency
+                    if ($dependency->enforce()) {
+                        $changes++;
+                    }
+                }
+            }
+        }
+        // Store the number of settings that changed through enforcement
+        $this->dependencychanges = $changes;
+        return ($changes>0);
+    }
+    /**
+     * Returns true if enforce_dependencies changed any settings
+     * @return bool
+     */
+    public function enforce_changed_dependencies() {
+        return ($this->dependencychanges > 0);
+    }
+    /**
+     * Loads the backup controller if we are tracking one
+     * @return backup_controller|false
+     */
+    final public static function load_controller() {
+        // Get the backup id optional param
+        $backupid = optional_param('backup', false, PARAM_ALPHANUM);
+        if ($backupid) {
+            try {
+                // Try to load the controller with it.
+                // If it fails at this point it is likely because this is the first load
+                $controller = backup_controller::load_controller($backupid);
+                return $controller;
+            } catch (Exception $e) {
+                return false;
+            }
+        }
+        return $backupid;
+    }
+    /**
+     * Cancels the current backup and redirects the user back to the relevant place
+     */
+    public function cancel_backup() {
+        global $PAGE;
+        // Determine the approriate URL to redirect the user to
+        if ($PAGE->context->contextlevel == CONTEXT_MODULE && $PAGE->cm !== null) {
+            $relevanturl = new moodle_url('/mod/'.$PAGE->cm->modname.'/view.php', array('id'=>$PAGE->cm->id));
+        } else {
+            $relevanturl = new moodle_url('/course/view.php', array('id'=>$PAGE->course->id));
+        }
+        redirect($relevanturl);
+    }
+    /**
+     * Gets an array of progress bar items that can be displayed through the backup renderer.
+     * @return array Array of items for the progress bar
+     */
+    public function get_progress_bar() {
+        $stage = self::STAGE_FINAL;
+        $currentstage = $this->stage->get_stage();
+        $items = array();
+        while ($stage > 0) {
+            $classes = array('backup_stage');
+            if (floor($stage/2) == $currentstage) {
+                $classes[] = 'backup_stage_next';
+            } else if ($stage == $currentstage) {
+                $classes[] = 'backup_stage_current';
+            } else if ($stage < $currentstage) {
+                $classes[] = 'backup_stage_complete';
+            }
+            array_unshift($items, array(
+                'text' => get_string('currentstage'.$stage, 'backup'),
+                'class' => join(' ', $classes)
+            ));
+            $stage = floor($stage/2);
+        }
+        return $items;
+    }
+}
+
+/**
+ * Backup user interface exception. Modelled off the backup_exception class
+ */
+class backup_ui_exception extends backup_exception {}
\ No newline at end of file
diff --git a/backup/util/ui/backup_ui_setting.class.php b/backup/util/ui/backup_ui_setting.class.php
new file mode 100644 (file)
index 0000000..b614607
--- /dev/null
@@ -0,0 +1,417 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains the setting user interface classes that all backup/restore
+ * settings use to represent the UI they have.
+ *
+ * @package   moodlecore
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Abstract class used to represent the user interface that a setting has.
+ *
+ * @todo extend as required for restore
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+abstract class base_setting_ui {
+    /**
+     * @var base_setting
+     */
+    protected $setting;
+    /**
+     * Constructors are sooooo cool
+     * @param base_setting $setting
+     */
+    public function __construct(base_setting $setting) {
+        $this->setting = $setting;
+    }
+    /**
+     * Get element properties that can be used to make a quickform element
+     * @return array
+     */
+    abstract public function get_element_properties(backup_task $task=null);
+}
+
+/**
+ * Abstract class to represent the user interface backup settings have
+ * 
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+abstract class backup_setting_ui extends base_setting_ui {
+
+    /**
+     * Prefix applied to all inputs/selects
+     */
+    const NAME_PREFIX = 'setting_';
+    /**
+     * The backup_setting UI type this relates to. One of backup_setting::UI_*;
+     * @var int
+     */
+    protected $type;
+    /**
+     * The name of the setting
+     * @var string
+     */
+    protected $name;
+    /**
+     * The label for the setting
+     * @var string
+     */
+    protected $label;
+    /**
+     * An array of HTML attributes to apply to this setting
+     * @var array
+     */
+    protected $attributes = array();
+    /**
+     * An array of options relating to this setting
+     * @var array
+     */
+    protected $options = array();
+
+    /**
+     * JAC... Just Another Constructor
+     *
+     * @param backup_setting $setting
+     * @param string|null $label The label to display with the setting ui
+     * @param array|null $attributes Array of HTML attributes to apply to the element
+     * @param array|null $options Array of options to apply to the setting ui object
+     */
+    public function __construct(backup_setting $setting, $label = null, array $attributes = null, array $options = null) {
+        parent::__construct($setting);
+        // Improve the inputs name by appending the level to the name
+        switch ($setting->get_level()) {
+            case backup_setting::ROOT_LEVEL :
+                $this->name = 'root_'.$setting->get_name();
+                break;
+            case backup_setting::COURSE_LEVEL :
+                $this->name = 'course_'.$setting->get_name();
+                break;
+            case backup_setting::SECTION_LEVEL :
+                $this->name = 'section_'.$setting->get_name();
+                break;
+            case backup_setting::ACTIVITY_LEVEL :
+                $this->name = 'activity_'.$setting->get_name();
+                break;
+        }
+        $this->label = $label;
+        if (is_array($attributes)) {
+            $this->attributes = $attributes;
+        }
+        if (is_array($options)) {
+            $this->options = $options;
+        }
+    }
+    /**
+     * Creates a new backup setting ui based on the setting it is given
+     *
+     * @param backup_setting $setting
+     * @param int $type The backup_setting UI type. One of backup_setting::UI_*;
+     * @param string $label The label to display with the setting ui
+     * @param array $attributes Array of HTML attributes to apply to the element
+     * @param array $options Array of options to apply to the setting ui object
+     * @return backup_setting_ui_text
+     */
+    final public static function make(backup_setting $setting, $type, $label, array $attributes = null, array $options=null) {
+        // Base the decision we make on the type that was sent
+        switch ($type) {
+            case backup_setting::UI_HTML_CHECKBOX :
+                return new backup_setting_ui_checkbox($setting, $label, null, (array)$attributes, (array)$options);
+            case backup_setting::UI_HTML_DROPDOWN :
+                return new backup_setting_ui_select($setting, $label, null, (array)$attributes, (array)$options);
+            case backup_setting::UI_HTML_RADIOBUTTON :
+                return new backup_setting_ui_radio($setting, $label, null, null, (array)$attributes, (array)$options);
+            case backup_setting::UI_HTML_TEXTFIELD :
+                return new backup_setting_ui_text($setting, $label, $attributes, $options);
+            default:
+                return false;
+        }
+    }
+    /**
+     * Applies config options to a given properties array and then returns it
+     * @param array $properties
+     * @return array
+     */
+    public function apply_options(array $properties) {
+        return $properties;
+    }
+    /**
+     * Gets the name of this item including its prefix
+     * @return string
+     */
+    public function get_name() {
+        return self::NAME_PREFIX.$this->name;
+    }
+    /**
+     * Gets the type of this element
+     * @return int
+     */
+    public function get_type() {
+        return $this->type;
+    }
+    /**
+     * Gets the label for this item
+     * @param backup_task|null $task Optional, if provided and the setting is an include
+     *          $task is used to set the setting label
+     * @return string
+     */
+    public function get_label(backup_task $task=null) {
+        // If a task has been provided and the label is not already set meaniningfully
+        // we will attempt to improve it.
+        if (!is_null($task) && $this->label == $this->setting->get_name() && strpos($this->setting->get_name(), '_include')!==false) {
+            if ($this->setting->get_level() == backup_setting::SECTION_LEVEL) {
+                $this->label = get_string('includesection', 'backup', $task->get_name());
+            } else if ($this->setting->get_level() == backup_setting::ACTIVITY_LEVEL) {
+                $this->label = get_string('includeother', 'backup', $task->get_name());
+            }
+        }
+        return $this->label;
+    }
+    /**
+     * Gets the HTML attributes for this item
+     * @return array
+     */
+    public function get_attributes() {
+        return $this->attributes;
+    }
+    /**
+     * Gets the value of this setting
+     * @return mixed
+     */
+    public function get_value() {
+        return $this->setting->get_value();
+    }
+    /**
+     * Gets the value to display in a static quickforms element
+     * @return mixed
+     */
+    public function get_static_value() {
+        return $this->setting->get_value();
+    }
+    /**
+     * Sets the label
+     * @param string $label
+     */
+    public function set_label($label) {
+        $this->label = $label;
+    }
+}
+
+/**
+ * A text input user interface element for backup settings
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class backup_setting_ui_text extends backup_setting_ui {
+    /**
+     * @var int
+     */
+    protected $type = backup_setting::UI_HTML_TEXTFIELD;
+    /**
+     * Returns an array of properties suitable for generating a quickforms element
+     * @param backup_task|null $task
+     * @return array (element, name, label, attributes)
+     */
+    public function get_element_properties(backup_task $task=null) {
+        // name, label, attributes
+        return $this->apply_options(array('element'=>'text','name'=>self::NAME_PREFIX.$this->name, 'label'=>$this->get_label($task), 'attributes'=>$this->attributes));
+    }
+
+}
+
+/**
+ * A checkbox user interface element for backup settings (default)
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class backup_setting_ui_checkbox extends backup_setting_ui {
+    /**
+     * @var int
+     */
+    protected $type = backup_setting::UI_HTML_CHECKBOX;
+    /**
+     * The text to show next to the checkbox
+     * @var string
+     */
+    protected $text;
+    /**
+     * Overridden constructor so we can take text argument
+     * @param backup_setting $setting
+     * @param string $label
+     * @param string $text
+     * @param array $attributes
+     * @param array $options
+     */
+    public function __construct(backup_setting $setting, $label = null, $text=null, array $attributes = array(), array $options = array()) {
+        parent::__construct($setting, $label, $attributes, $options);
+        $this->text = $text;
+    }
+    /**
+     * Returns an array of properties suitable for generating a quickforms element
+     * @param backup_task|null $task
+     * @return array (element, name, label, text, attributes);
+     */
+    public function get_element_properties(backup_task $task=null) {
+        // name, label, text, attributes
+        return $this->apply_options(array('element'=>'checkbox','name'=>self::NAME_PREFIX.$this->name, 'label'=>$this->get_label($task), 'text'=>$this->text, 'attributes'=>$this->attributes));
+    }
+    /**
+     * Sets the text for the element
+     * @param string $text
+     */
+    public function set_text($text) {
+        $this->text = text;
+    }
+    /**
+     * Gets the static value for the element
+     * @return string
+     */
+    public function get_static_value() {
+        // Checkboxes are always yes or no
+        if ($this->get_value()) {
+            return get_string('yes');
+        } else {
+            return get_string('no');
+        }
+    }
+}
+
+/**
+ * Radio button user interface element for backup settings
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class backup_setting_ui_radio extends backup_setting_ui {
+    /**
+     * @var int
+     */
+    protected $type = backup_setting::UI_HTML_RADIOBUTTON;
+    /**
+     * The string shown next to the input
+     * @var string
+     */
+    protected $text;
+    /**
+     * The value for the radio input
+     * @var string
+     */
+    protected $value;
+    /**
+     *
+     * @param backup_setting $setting
+     * @param string $label
+     * @param string $text
+     * @param string $value
+     * @param array $attributes
+     * @param array $options
+     */
+    public function __construct(backup_setting $setting, $label = null, $text=null, $value=null, array $attributes = array(), array $options = array()) {
+        parent::__construct($setting, $label, $attributes, $options);
+        $this->text = $text;
+        $this->value = (string)$value;
+    }
+    /**
+     * Returns an array of properties suitable for generating a quickforms element
+     * @param backup_task|null $task
+     * @return array (element, name, label, text, value, attributes)
+     */
+    public function get_element_properties(backup_task $task=null) {
+        // name, label, text, value, attributes
+        return $this->apply_options(array('element'=>'radio','name'=>self::NAME_PREFIX.$this->name, 'label'=>$this->get_label($task), 'text'=>$this->text, 'value'=>$this->value, 'attributes'=>$this->attributes));
+    }
+    /**
+     * Sets the text next to this input
+     * @param text $text
+     */
+    public function set_text($text) {
+        $this->text = text;
+    }
+    /**
+     * Sets the value for the input
+     * @param string $value
+     */
+    public function set_value($value) {
+        $this->value = (string)value;
+    }
+    /**
+     * Gets the static value to show for the element
+     */
+    public function get_static_value() {
+        return $this->value;
+    }
+}
+
+/**
+ * A select box, drop down user interface for backup settings
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class backup_setting_ui_select extends backup_setting_ui {
+    /**
+     * @var int
+     */
+    protected $type = backup_setting::UI_HTML_DROPDOWN;
+    /**
+     * An array of options to display in the select
+     * @var array
+     */
+    protected $values;
+    /**
+     *
+     * @param backup_setting $setting
+     * @param string $label
+     * @param array $values
+     * @param array $attributes
+     * @param array $options
+     */
+    public function __construct(backup_setting $setting, $label = null, $values=null, array $attributes = array(), array $options = array()) {
+        parent::__construct($setting, $label, $attributes, $options);
+        $this->values = $values;
+    }
+    /**
+     * Returns an array of properties suitable for generating a quickforms element
+     * @param backup_task|null $task
+     * @return array (element, name, label, options, attributes)
+     */
+    public function get_element_properties(backup_task $task = null) {
+        // name, label, options, attributes
+        return $this->apply_options(array('element'=>'select','name'=>self::NAME_PREFIX.$this->name, 'label'=>$this->get_label($task), 'options'=>$this->values, 'attributes'=>$this->attributes));
+    }
+    /**
+     * Sets the options for the select box
+     * @param array $values Associative array of value=>text options
+     */
+    public function set_values(array $values) {
+        $this->values = $values;
+    }
+    /**
+     * Gets the static value for this select element
+     * @return string
+     */
+    public function get_static_value() {
+        return $this->values[$this->get_value()];
+    }
+}
\ No newline at end of file
diff --git a/backup/util/ui/backup_ui_stage.class.php b/backup/util/ui/backup_ui_stage.class.php
new file mode 100644 (file)
index 0000000..2fae15f
--- /dev/null
@@ -0,0 +1,530 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Backup user interface stages
+ *
+ * This file contains the classes required to manage the stages that make up the
+ * backup user interface.
+ * These will be primarily operated a {@see backup_ui} instance.
+ *
+ * @package   moodlecore
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Abstract stage class
+ *
+ * This class should be extended by all backup stages (a requirement of many backup ui functions).
+ * Each stage must then define two abstract methods
+ *  - process : To process the stage
+ *  - initialise_stage_form : To get a backup_moodleform instance for the stage
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+abstract class backup_ui_stage {
+    /**
+     * The current stage
+     * @var int
+     */
+    protected $stage = backup_ui::STAGE_INITIAL;
+    /**
+     * The backuck UI object
+     * @var backup_ui
+     */
+    protected $ui;
+    /**
+     *
+     * @param backup_ui $ui
+     */
+    public function  __construct(backup_ui $ui) {
+        $this->ui = $ui;
+    }
+    /**
+     * The current stage
+     * @return int
+     */
+    final public function get_stage() {
+        return $this->stage;
+    }
+    /**
+     * The next stage
+     * @return int
+     */
+    final public function get_next_stage() {
+        return floor($this->stage*2);
+    }
+    /**
+     * The previous stage
+     * @return int
+     */
+    final public function get_prev_stage() {
+        return floor($this->stage/2);
+    }
+    /**
+     * The name of this stage
+     * @return string
+     */
+    final public function get_name() {
+        return get_string('currentstage'.$this->stage,'backup');
+    }
+    /**
+     * The backup id from the backup controller
+     * @return string
+     */
+    final public function get_backupid() {
+        return $this->ui->get_backupid();
+    }
+    /**
+     * Displays the stage.
+     *
+     * By default this involves instantiating the form for the stage and the calling
+     * it to display. Remember this is a moodleform instance so it will print
+     * rather than return.
+     */
+    public function display() {
+        $form = $this->initialise_stage_form();
+        $form->display();
+    }
+    /**
+     * Processes the stage.
+     *
+     * This must be overridden by every stage as it will be different for every stage
+     *
+     * @abstract
+     * @param backup_moodleform|null $form
+     */
+    abstract public function process(backup_moodleform $form=null);
+    /**
+     * Creates an instance of the correct moodleform properly populated and all
+     * dependencies instantiated
+     *
+     * @abstract
+     * @return backup_moodleform
+     */
+    abstract protected function initialise_stage_form();
+}
+
+/**
+ * Class representing the initial stage of a backup.
+ * 
+ * In this stage the user is required to set the root level settings.
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class backup_ui_stage_initial extends backup_ui_stage {
+
+    /**
+     * Initial backup stage constructor
+     * @param backup_ui $ui
+     */
+    public function  __construct(backup_ui $ui) {
+        $this->stage = backup_ui::STAGE_INITIAL;
+        parent::__construct($ui);
+    }
+    /**
+     * Processes the initial backup stage
+     * @param backup_moodleform $form
+     * @return int The number of changes
+     */
+    public function process(backup_moodleform $form = null) {
+        // If we wern't given a form create an instance of the form for this stage
+        if (is_null($form)) {
+            $form = $this->initialise_stage_form();
+            // Check it wasn't cancelled
+            if ($form->is_cancelled()) {
+                $this->ui->cancel_backup();
+            }
+        }
+
+        // Check if it was submit
+        $data = $form->get_data();
+        if (!$data || !confirm_sesskey()) {
+            return $this->ui->process_previous_stage($this);
+        }
+
+        // Store the tasks a variable so we can iterate by reference
+        $tasks = $this->ui->get_backup_tasks();
+        $changes = 0;
+
+        foreach ($tasks as &$task) {
+            // We are only interesting in the backup root task for this stage
+            if ($task instanceof backup_root_task) {
+                // Get all settings into a var so we can iterate by reference
+                $settings = $task->get_settings();
+                foreach ($settings as &$setting) {
+                    $name = $setting->get_ui_name();
+                    if (isset($data->$name) &&  $data->$name != $setting->get_value()) {
+                        $setting->set_value($data->$name);
+                        $changes++;
+                    } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
+                        $setting->set_value(0);
+                        $changes++;
+                    }
+                }
+            }
+        }
+        // Return the number of changes the user made
+        return $changes;
+    }
+
+    /**
+     * Initialises the backup_moodleform instance for this stage
+     *
+     * @return backup_initial_form
+     */
+    protected function initialise_stage_form() {
+        global $PAGE;
+        $form = new backup_initial_form($this, $PAGE->url);
+        // Store as a variable so we can iterate by reference
+        $tasks = $this->ui->get_backup_tasks();
+        // Iterate all tasks by reference
+        foreach ($tasks as &$task) {
+            // For the initial stage we are only interested in the root settings
+            if ($task instanceof backup_root_task) {
+                $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
+                $settings = $task->get_settings();
+                // First add all settings except the filename setting
+                foreach ($settings as &$setting) {
+                    if ($setting->get_name() == 'filename') {
+                        continue;
+                    }
+                    $form->add_setting($setting, $task);
+                }
+                // Then add all dependencies
+                foreach ($settings as &$setting) {
+                    if ($setting->get_name() == 'filename') {
+                        continue;
+                    }
+                    $form->add_dependencies($setting);
+                }
+            }
+        }
+        // Return the form
+        return $form;
+    }
+}
+
+/**
+ * Schema stage of backup process
+ *
+ * During the schema stage the user is required to set the settings that relate
+ * to the area that they are backing up as well as its children.
+ * 
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class backup_ui_stage_schema extends backup_ui_stage {
+    /**
+     * Schema stage constructor
+     * @param backup_moodleform $ui
+     */
+    public function  __construct(backup_ui $ui) {
+        $this->stage = backup_ui::STAGE_SCHEMA;
+        parent::__construct($ui);
+    }
+    /**
+     * Processes the schema stage
+     *
+     * @param backup_moodleform|null $form
+     * @return int The number of changes the user made
+     */
+    public function process(backup_moodleform $form = null) {
+        // If we wern't given a form instantiate a new form for this stage
+        if (is_null($form)) {
+            $form = $this->initialise_stage_form();
+            // Check it wasn't cancelled
+            if ($form->is_cancelled()) {
+                $this->ui->cancel_backup();
+            }
+        }
+
+        // Check it has been submit
+        $data = $form->get_data();
+        if (!$data || !confirm_sesskey()) {
+            return $this->ui->process_previous_stage($this);
+        }
+
+        // If this stage is the current stage first process all other stages
+        // to ensure we respect dependencies in the correct order.
+        if ($this->ui->get_stage() == $this->get_next_stage()) {
+            $this->ui->process_all_previous_stages($this, $form);
+        }
+
+        // Get the tasks into a var so we can iterate by reference
+        $tasks = $this->ui->get_backup_tasks();
+        $changes = 0;
+        // Iterate all tasks by reference
+        foreach ($tasks as &$task) {
+            // We are only interested in schema settings
+            if (!($task instanceof backup_root_task)) {
+                // Store as a variable so we can iterate by reference
+                $settings = $task->get_settings();
+                // Iterate by reference
+                foreach ($settings as &$setting) {
+                    $name = $setting->get_ui_name();
+                    if (isset($data->$name) &&  $data->$name != $setting->get_value()) {
+                        $setting->set_value($data->$name);
+                        $changes++;
+                    } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
+                        $setting->set_value(0);
+                        $changes++;
+                    }
+                }
+            }
+        }
+        // Return the number of changes the user made
+        return $changes;
+    }
+    /**
+     * Creates the backup_schema_form instance for this stage
+     *
+     * @return backup_schema_form
+     */
+    protected function initialise_stage_form() {
+        global $PAGE;
+        $form = new backup_schema_form($this, $PAGE->url);
+        $tasks = $this->ui->get_backup_tasks();
+        $content = '';
+        $courseheading = false;
+        foreach ($tasks as $task) {
+            if ($task instanceof backup_root_task) {
+                // Add a root settings heading to group nicely
+                $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
+                // Iterate all settings and add them to the form as a fixed
+                // setting. We only want schema settings to be editable
+                foreach ($task->get_settings() as $setting) {
+                    if ($setting->get_name() != 'filename') {
+                        $form->add_fixed_setting($setting);
+                    }
+                }
+            } else {
+                if (!$courseheading) {
+                    // If we havn't already display a course heading to group nicely
+                    $form->add_heading('coursesettings', get_string('coursesettings', 'backup'));
+                    $courseheading = true;
+                }
+                // First add each setting
+                foreach ($task->get_settings() as $setting) {
+                    $form->add_setting($setting, $task);
+                }
+                // The add all the dependencies
+                foreach ($task->get_settings() as $setting) {
+                    $form->add_dependencies($setting);
+                }
+            }
+        }
+        return $form;
+    }
+}
+
+/**
+ * Confirmation stage
+ *
+ * On this stage the user reviews the setting for the backup and can change the filename
+ * of the file that will be generated.
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class backup_ui_stage_confirmation extends backup_ui_stage {
+    /**
+     * Constructs the stage
+     * @param backup_ui $ui
+     */
+    public function  __construct($ui) {
+        $this->stage = backup_ui::STAGE_CONFIRMATION;
+        parent::__construct($ui);
+    }
+    /**
+     * Processes the confirmation stage
+     *
+     * @param backup_moodleform $form
+     * @return int The number of changes the user made
+     */
+    public function process(backup_moodleform $form = null) {
+        // If we don't have a form passed in then we need to initalise the
+        // form for this stage
+        if (is_null($form)) {
+            $form = $this->initialise_stage_form();
+            // Check it hasn't been cancelled
+            if ($form->is_cancelled()) {
+                $this->ui->cancel_backup();
+            }
+        }
+
+        // Get the data (will be false if not submit yet)
+        $data = $form->get_data();
+        // If not submit or sesskey incorrect process the previous stage
+        if (!$data || !confirm_sesskey()) {
+            return $this->ui->process_previous_stage($this);
+        }
+
+        // If this stage is the current stage first process all other stages
+        // to ensure we respect dependencies in the correct order.
+        if ($this->ui->get_stage() == $this->get_stage()) {
+            $this->ui->process_all_previous_stages($this, $form);
+        }
+
+        // Collect into a variable so we can iterate by reference
+        $tasks = $this->ui->get_backup_tasks();
+        $changes = 0;
+        // Iterate each task by reference
+        foreach ($tasks as &$task) {
+            if ($task instanceof backup_root_task) {
+                // At this stage all we are interested in is the filename setting
+                $setting = $task->get_setting('filename');
+                $name = $setting->get_ui_name();
+                if (isset($data->$name) &&  $data->$name != $setting->get_value()) {
+                    $setting->set_value($data->$name);
+                    $changes++;
+                }
+            }
+        }
+        // Return the number of changes the user made
+        return $changes;
+    }
+    /**
+     * Creates the backup_confirmation_form instance this stage requires
+     *
+     * @return backup_confirmation_form
+     */
+    protected function initialise_stage_form() {
+        global $PAGE;
+        // Get the form
+        $form = new backup_confirmation_form($this, $PAGE->url);
+        $content = '';
+        $courseheading = false;
+        foreach ($this->ui->get_backup_tasks() as $task) {
+            if ($task instanceof backup_root_task) {
+                // If its a backup root add a root settings heading to group nicely
+                $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
+            } else if (!$courseheading) {
+                // we havn't already add a course heading
+                $form->add_heading('coursesettings', get_string('coursesettings', 'backup'));
+                $courseheading = true;
+            }
+            // Iterate all settings, doesnt need to happen by reference
+            foreach ($task->get_settings() as $setting) {
+                // For this stage only the filename setting should be editable
+                if ($setting->get_name() != 'filename') {
+                    $form->add_fixed_setting($setting);
+                } else {
+                    $form->add_setting($setting, $task);
+                }
+            }
+        }
+        return $form;
+    }
+}
+
+/**
+ * Final stage of backup
+ *
+ * This stage is special in that it is does not make use of a form. The reason for
+ * this is the order of procession of backup at this stage.
+ * The processesion is:
+ * 1. The final stage will be intialise.
+ * 2. The confirmation stage will be processed.
+ * 3. The backup will be executed
+ * 4. The complete stage will be loaded by execution
+ * 5. The complete stage will be displayed
+ *
+ * This highlights that we neither need a form nor a display method for this stage
+ * we simply need to process.
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class backup_ui_stage_final extends backup_ui_stage {
+    /**
+     * Constructs the final stage
+     * @param backup_ui $ui
+     */
+    public function  __construct(backup_ui $ui) {
+        $this->stage = backup_ui::STAGE_FINAL;
+        parent::__construct($ui);
+    }
+    /**
+     * Processes the final stage.
+     *
+     * In this case it ALWAYS passes processing to the previous stage (confirmation)
+     */
+    public function process(backup_moodleform $form=null) {
+        return $this->ui->process_previous_stage($this);
+    }
+    /**
+     * should NEVER be called... throws an exception
+     */
+    protected function initialise_stage_form() {
+        throw new backup_ui_exception('backup_ui_must_execute_first');
+    }
+    /**
+     * should NEVER be called... throws an exception
+     */
+    public function display() {
+        throw new backup_ui_exception('backup_ui_must_execute_first');
+    }
+}
+
+/**
+ * The completed backup stage
+ *
+ * At this stage everything is done and the user will be redirected to view the
+ * backup file in the file browser.
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class backup_ui_stage_complete extends backup_ui_stage_final {
+    /**
+     * The results of the backup execution
+     * @var array
+     */
+    protected $results;
+    /**
+     * Constructs the complete backup stage
+     * @param backup_ui $ui
+     * @param array $results
+     */
+    public function __construct(backup_ui $ui, $results) {
+        $this->results = $results;
+        parent::__construct($ui);
+    }
+    /**
+     * Displays the completed backup stage.
+     *
+     * Currently this just envolves redirecting to the file browser with an
+     * appropriate message.
+     */
+    public function display() {
+        // Get the resulting stored_file record
+        $file = $this->results['backup_destination'];
+        // Turn it into a url for the file browser
+        $fileurl = new moodle_url('/files/index.php', array(
+            'contextid' => $file->get_contextid(),
+            'filearea' => $file->get_filearea(),
+            'itemid' => $file->get_itemid(),
+            'filepath' => $file->get_filepath()
+        ));
+        // Redirect the user with a useful message
+        redirect($fileurl, get_string('executionsuccess', 'backup'), 3);
+    }
+}
\ No newline at end of file
diff --git a/backup/util/ui/renderer.php b/backup/util/ui/renderer.php
new file mode 100644 (file)
index 0000000..84b2a9d
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains backup and restore output renderers
+ *
+ * @package   moodlecore
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * The primary renderer for the backup.
+ *
+ * Can be retrieved with the following code:
+ * <?php
+ * $renderer = $PAGE->get_renderer('core','backup');
+ * ?>
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class core_backup_renderer extends plugin_renderer_base {
+    /**
+     * Renderers a progress bar for the backup or restore given the items that
+     * make it up.
+     * @param array $items An array of items
+     * @return string
+     */
+    public function progress_bar(array $items) {
+        foreach ($items as &$item) {
+            $text = $item['text'];
+            unset($item['text']);
+            $item = html_writer::tag('span', $text, $item);
+        }
+        return html_writer::tag('div', join(get_separator(), $items), array('class'=>'backup_progress clearfix'));
+    }
+    /**
+     * Prints a dependency notification
+     * @param string $message
+     * @return string
+     */
+    public function dependency_notification($message) {
+        return html_writer::tag('div', $message, array('class'=>'notification dependencies_enforced'));
+    }
+}
\ No newline at end of file
index 6ae18b5..16e7281 100644 (file)
@@ -40,20 +40,23 @@ $newdirname = optional_param('newdirname', '', PARAM_FILE);
 $delete     = optional_param('delete', 0, PARAM_BOOL);
 
 if ($courseid) {
-    if (!$course = $DB->get_record('course', array('id'=>$courseid))) {
-        print_error('invalidcourseid');
-    }
-    if (!$context = get_context_instance(CONTEXT_COURSE, $course->id)) {
-        print_error('invalidcontext');
-    }
+    $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
+    $context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST);
     redirect(new moodle_url('index.php', array('contextid' => $context->id, 'itemid'=> 0, 'filearea' => 'course_content')));
 }
 
-if (!$context = get_context_instance_by_id($contextid)) {
-    print_error('invalidcontext');
+$context = get_context_instance_by_id($contextid, MUST_EXIST);
+
+$course = null;
+$cm = null;
+if ($context->contextlevel == CONTEXT_MODULE) {
+    $cm = get_coursemodule_from_id(null, $context->instanceid, 0, false, MUST_EXIST);
+    $course = $DB->get_record('course', array('id'=>$cm->course), '*', MUST_EXIST);
+} else if ($context->contextlevel == CONTEXT_COURSE) {
+    $course = $DB->get_record('course', array('id'=>$context->instanceid), '*', MUST_EXIST);
 }
 
-require_login();
+require_login($course, false, $cm);
 require_capability('moodle/course:managefiles', $context);
 
 if ($filearea === '') {
@@ -183,7 +186,14 @@ function html_header($context, $file_info){
     global $CFG, $SITE, $PAGE, $OUTPUT;
 
     $strfiles = get_string("files");
-    build_navbar_for_file($PAGE, $file_info);
+    if ($context->contextlevel == CONTEXT_MODULE) {
+        $PAGE->set_pagelayout('incourse');
+    } else if ($context->contextlevel == CONTEXT_COURSE) {
+        $PAGE->set_pagelayout('course');
+    } else {
+        $PAGE->set_pagelayout('admin');
+    }
+    $PAGE->navbar->add($strfiles);
     $PAGE->set_url("/files/index.php", $file_info->get_params());
     $PAGE->set_title("$SITE->shortname: $strfiles");
     echo $OUTPUT->header();
@@ -325,25 +335,4 @@ function displaydir($file_info) {
     echo "</div>";
     echo "<hr/>";
 
-}
-
-/**
- * Creates a navigation bar that relates to the passed file
- *
- * @param moodle_page $page
- * @param file_info $file_info
- */
-function build_navbar_for_file($page, $file_info) {
-    $page->navbar->ignore_active();
-    $parent_info = $file_info->get_parent();
-    $level = $parent_info;
-    $nodes = array(clone($file_info));
-    while ($level) {
-        $nodes[] = $level;
-        $level = $level->get_parent();
-    }
-    $page->navbar->add(get_string('files'));
-    foreach (array_reverse($nodes) as $level) {
-        $page->navbar->add($level->get_visible_name(), 'index.php?'.implode('&amp;', $level->get_params_rawencoded()));
-    }
-}
+}
\ No newline at end of file
diff --git a/lang/en/backup.php b/lang/en/backup.php
new file mode 100644 (file)
index 0000000..225ffeb
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains the strings used by backup
+ *
+ * @package   moodlecore
+ * @copyright 2010 Eloy
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['coursesettings'] = 'Course settings';
+$string['currentstage1'] = 'Initial settings';
+$string['currentstage2'] = 'Schema settings';
+$string['currentstage4'] = 'Confirmation and review';
+$string['currentstage8'] = 'Preform backup';
+$string['currentstage16'] = 'Complete';
+$string['dependenciesenforced'] = 'Your settings have been altered due to unmet dependencies';
+$string['executionsuccess'] = 'Your backup completed successfully, you will be redirected momentarily to the backup section for this course.';
+$string['filename'] = 'Filename';
+$string['includesection'] = 'Include section {$a}';
+$string['includeother'] = 'Include {$a}';
+$string['includeuserinfo'] = 'Include user information';
+$string['onstage1action'] = 'Save settings and proceed';
+$string['onstage2action'] = 'Save settings and proceed';
+$string['onstage4action'] = 'Preform backup';
+$string['onstage8action'] = 'Continue';
+$string['onstage16action'] = 'Continue';
+$string['rootsettings'] = 'Backup settings';
+$string['settingislocked'] = '{$a} [Locked]';
index 5c57efd..3e0c14b 100644 (file)
@@ -6900,6 +6900,7 @@ function get_core_subsystems() {
             'access'      => NULL,
             'admin'       => $CFG->admin,
             'auth'        => 'auth',
+            'backup'      => 'backup/util/ui',
             'block'       => 'blocks',
             'blog'        => 'blog',
             'bulkusers'   => NULL,
index f5e83d6..20916dd 100644 (file)
@@ -513,11 +513,22 @@ body.tag .managelink {padding: 5px;}
 .fm-file-entry{border: 1px solid red;}
 .fm-operation {font-weight: bold;}
 
-/**
- * Backup and restore
+/*
+ * Backup and Restore CSS
  */
-.backup-form-instances,
-.restore-form-instances {margin:0 20px;}
+.path-backup .mform .grouped_settings.section_level {clear:both;}
+.path-backup .mform .grouped_settings {clear:both;overflow:hidden;}
+.path-backup .mform .grouped_settings .fitem .fitemtitle {width:40%;padding-right:10px;}
+.path-backup .mform .grouped_settings .fitem .felement {width:50%;}
+.path-backup .mform .grouped_settings.section_level .include_setting {width:50%;margin:0;float:left;clear:left;}
+.path-backup .mform .grouped_settings.section_level .normal_setting {width:50%;margin:0;margin-left:50%;}
+.path-backup .notification.dependencies_enforced {text-align:center;color:#A00;font-weight:bold;}
+.path-backup .backup_progress {text-align:center;}
+.path-backup .backup_progress .backup_stage {color:#999;}
+.path-backup .backup_progress .backup_stage.backup_stage_current {font-weight:bold;color:inherit;}
+.path-backup .backup_progress .backup_stage.backup_stage_next {}
+.path-backup .backup_progress .backup_stage.backup_stage_complete {color:inherit;}
+
 
 /**
  * Web Service
index 815474a..d5c8fef 100644 (file)
@@ -352,6 +352,18 @@ table#tag-management-list {margin: 10px auto;width: 80%;}
 .ie6.course-view li.activity {height:0;}
 .ie6 #help_icon_tooltip .yui-tt-shadow-visible {background-color: transparent;}
 
+/*
+ * Backup CSS
+ */
+.path-backup .mform .grouped_settings.section_level {border:1px solid #aaa;margin:10px;clear:both;background-color:#EEE;}
+.path-backup .mform .grouped_settings.section_level .grouped_settings.activity_level  {background-color:#fff;border:1px solid #fff;border-top-color:#DDD;}
+.path-backup .mform .grouped_settings.section_level .include_setting {font-weight:bold;}
+.path-backup .backup_progress {margin:10px;}
+.path-backup .backup_progress .backup_stage {margin:5px 20px;}
+.path-backup .backup_progress .backup_stage.backup_stage_complete {}
+.path-backup .backup_progress .backup_stage.backup_stage_next {}
+.path-backup .backup_progress .backup_stage.backup_stage_current {}
+
 /**
  * Site registration
  */
@@ -376,4 +388,4 @@ table#tag-management-list {margin: 10px auto;width: 80%;}
  #page-blocks-community-communitycourse .trustedtr {background-color: #ffe1c3;}
  #page-blocks-community-communitycourse .prioritisetr {background-color: #ffd4ff;}
  #page-blocks-community-communitycourse .additionaldesc {font-size: 80%; color: purple;}
- #page-blocks-community-communitycourse .additionaladmindesc {font-size: 80%; color: #6666ff;}
\ No newline at end of file
+ #page-blocks-community-communitycourse .additionaladmindesc {font-size: 80%; color: #6666ff;}