Julio Montoya 13 năm trước cách đây
mục cha
commit
0d5680a858

+ 5 - 0
main/css/base_chamilo.css

@@ -1006,6 +1006,11 @@ a.nobold:hover {
     vertical-align: middle;
 }
 
+
+.data_table_no_border td .highlight{
+    font-weight: bold;
+}
+
 .data_table_pagination {
     width:100%;
     margin-top: 8px;    

+ 31 - 5
main/css/chamilo/print.css

@@ -763,26 +763,52 @@ padding-top: 0px;	padding-right: 0px;	padding-bottom: 0px;	padding-left: 0px;}
 	padding: 5px;
 }
 .data_table th {
-	padding-right: 20px;
+	/*padding-right: 20px;*/
 	border: 1px solid gray;
 	background-color: #E5EDF9;
+	text-align: left;
 }
 .data_table tr.row_odd {
-	background-color: #fafafa;
+	background-color: #fafafa;	
 }
 .data_table tr.row_odd:hover, .data_table tr.row_even:hover {
 	background-color: #f0f0f0;
 }
 .data_table tr.row_even {
-	background-color: #fff;
+	background-color: #fff;	
+}
+.data_table td .highlight {
+    font-weight: bold;
 }
 .data_table td {
-	padding: 5px;
-	vertical-align: top;
+	padding: 5px;	
 	border-bottom: 1px solid #b0b0b0;
 	border-right: 1px dotted #e1e1e1;
 	border-left: 1px dotted #e1e1e1;
+	text-align: left;
 }
+
+
+.data_table_no_border {
+    border-collapse: collapse;
+    border-spacing: 0;
+    font-size: 12px;
+    margin-bottom: 15px;
+    margin-top: 8px;
+    text-align: left;
+    width: 100%;    
+}
+
+.data_table_no_border td {
+    line-height: normal;
+    padding: 6px;
+    text-align: left;
+    vertical-align: middle;
+}
+.data_table_no_border .highlight {
+    font-weight: bold;
+}
+
 /* admin page tool list definitions */
 .tool_list dt {
 	font-weight: bold;

+ 20 - 4
main/exercice/admin.php

@@ -42,6 +42,7 @@
 *
 *	@package chamilo.exercise
 * 	@author Olivier Brouckaert
+* Modified by Hubert Borderiou 21-10-2011 Question by category
 */
 /**
  * Code
@@ -234,7 +235,6 @@ if ($cancelQuestion) {
 	} else {
 		// goes back to the question viewing
 		$editQuestion=$modifyQuestion;
-
 		unset($newQuestion,$modifyQuestion);
 	}
 }
@@ -448,6 +448,9 @@ if (isset($exerciseId) && !empty($exerciseId)) {
 	}
 }
 
+// If we are in a test
+$inATest = isset($exerciseId) && $exerciseId > 0;
+if ($inATest) {
 echo '<div class="actions">';
 if (isset($_GET['hotspotadmin']) || isset($_GET['newQuestion']) || isset($_GET['myid']))
     echo '<a href="admin.php?exerciseId='.$exerciseId.'">'.Display::return_icon('back.png', get_lang('GoBackToQuestionList'),'','32').'</a>';
@@ -473,20 +476,33 @@ foreach ($objExercise->questionList as $q) {
 echo '<span style="float:right">'.sprintf(get_lang('XQuestionsWithTotalScoreY'),$objExercise->selectNbrQuestions(),$maxScoreAllQuestions).'</span>';
 
 echo '</div>';
+}
+else if (isset($_GET['newQuestion'])) {
+	// we are in create a new question from question pool not in a test
+	echo '<div class="actions">';
+	echo '<a href="admin.php?'.api_get_cidreq().'">.'.Display::return_icon('back.png', get_lang('GoBackToQuestionList'),'','32').'</a>';
+	echo '</div>';
+}
+else {
+	// If we are in question_poolbut not in an test, go back to question create in pool
+	echo '<div class="actions">';
+	echo '<a href="question_pool.php">'.Display::return_icon('back.png', get_lang('GoBackToQuestionList'),'','32').'</a>';
+	echo '</div>';
+	
+}
 
 if (isset($_GET['message'])) {
 	if (in_array($_GET['message'], array('ExerciseStored', 'ItemUpdated', 'ItemAdded'))) {
 		Display::display_confirmation_message(get_lang($_GET['message']));
 	}
 }
-
 if ($newQuestion || $editQuestion) {
 	// statement management
 	$type = Security::remove_XSS($_REQUEST['answerType']);
 	echo '<input type="hidden" name="Type" value="'.$type.'" />';	
 	require 'question_admin.inc.php';
 }
- 
+
 if (isset($_GET['hotspotadmin'])) {    
     if (!is_object($objQuestion)) {
         $objQuestion = Question :: read($_GET['hotspotadmin']);
@@ -495,6 +511,7 @@ if (isset($_GET['hotspotadmin'])) {
         api_not_allowed();
     }    
 	require 'hotspot_admin.inc.php';}
+
 if (!$newQuestion && !$modifyQuestion && !$editQuestion && !isset($_GET['hotspotadmin'])) {
 	// question list management
 	require 'question_list_admin.inc.php';
@@ -503,5 +520,4 @@ if (!$newQuestion && !$modifyQuestion && !$editQuestion && !isset($_GET['hotspot
 api_session_register('objExercise');
 api_session_register('objQuestion');
 api_session_register('objAnswer');
-
 Display::display_footer();

+ 16 - 3
main/exercice/exercice.php

@@ -7,6 +7,7 @@
 *	@author Denes Nagy, HotPotatoes integration
 *	@author Wolfgang Schneider, code/html cleanup
 *	@author Julio Montoya <gugli100@gmail.com>, lots of cleanup + several improvements
+* Modified by hubert.borderiou (question category)
 */
 /**
  * Code
@@ -118,6 +119,8 @@ $learnpath_id       = intval($_REQUEST['learnpath_id']);
 $learnpath_item_id  = intval($_REQUEST['learnpath_item_id']);
 $page               = intval($_REQUEST['page']);
 
+$course_info        = api_get_course_info();
+
 if ($page < 0) {
     $page = 1;
 }
@@ -197,8 +200,7 @@ if ($show == 'result' && $_REQUEST['comments'] == 'update' && ($is_allowedToEdit
 		Database::query($query);
 		
 		//Saving results in the track recording table
-		$recording_changes = 'INSERT INTO '.$TBL_TRACK_ATTEMPT_RECORDING.' (exe_id, question_id, marks, insert_date, author, teacher_comment) 
-							  VALUES ('."'$id','".$my_questionid."','$my_marks','".api_get_utc_datetime()."','".api_get_user_id()."'".',"'.$my_comments.'")';
+		$recording_changes = 'INSERT INTO '.$TBL_TRACK_ATTEMPT_RECORDING.' (exe_id, question_id, marks, insert_date, author, teacher_comment) VALUES ('."'$id','".$my_questionid."','$my_marks','".api_get_utc_datetime()."','".api_get_user_id()."'".',"'.$my_comments.'")';
 		Database::query($recording_changes);
 	}
 	
@@ -214,7 +216,7 @@ if ($show == 'result' && $_REQUEST['comments'] == 'update' && ($is_allowedToEdit
     
     //@todo move this somewhere else
 	$subject = get_lang('ExamSheetVCC');	
-	$course_info = api_get_course_info();
+	
 	$message  = '<p>'.get_lang('DearStudentEmailIntroduction') . '</p><p>'.get_lang('AttemptVCC');
 	$message .= '<h3>'.get_lang('CourseName'). '</h3><p>'.Security::remove_XSS($course_info['name']).'';
 	$message .= '<h3>'.get_lang('Exercise') . '</h3><p>'.Security::remove_XSS($test);
@@ -383,6 +385,8 @@ if ($is_allowedToEdit) {
 					case 'enable' : // enables an exercise
 						$objExerciseTmp->enable();
 						$objExerciseTmp->save();
+                        
+                        api_item_property_update($course_info, TOOL_QUIZ, $objExerciseTmp->id,'visible', api_get_user_id());
 						// "WHAT'S NEW" notification: update table item_property (previously last_tooledit)
 						Display :: display_confirmation_message(get_lang('VisibilityChanged'));
 
@@ -390,6 +394,7 @@ if ($is_allowedToEdit) {
 					case 'disable' : // disables an exercise
 						$objExerciseTmp->disable();
 						$objExerciseTmp->save();
+                        api_item_property_update($course_info, TOOL_QUIZ, $objExerciseTmp->id,'invisible', api_get_user_id());
 						Display :: display_confirmation_message(get_lang('VisibilityChanged'));
 						break;
 					case 'disable_results' : //disable the results for the learners
@@ -520,6 +525,14 @@ if ($is_allowedToEdit && $origin != 'learnpath') {
 	if ($show != 'result') {
 		echo '<a href="exercise_admin.php?' . api_get_cidreq() . '">' . Display :: return_icon('new_exercice.png', get_lang('NewEx'),'','32').'</a>';
 		echo '<a href="question_create.php?' . api_get_cidreq() . '">' . Display :: return_icon('new_question.png', get_lang('AddQ'),'','32').'</a>';
+		// Question category
+		echo '<a href="tests_category.php">';
+		echo Display::return_icon('question_category.gif', get_lang('QuestionCategory'));
+		echo '</a>';		
+		echo '<a href="question_pool.php">';
+		echo Display::return_icon('database.png', get_lang('langQuestionPool'), array('style'=>'width:32px'));
+		echo '</a>';
+		// end question category
 		echo '<a href="hotpotatoes.php?' . api_get_cidreq() . '">' . Display :: return_icon('import_hotpotatoes.png', get_lang('ImportHotPotatoesQuiz'),'','32').'</a>';
 		// link to import qti2 ...
 		echo '<a href="qti2.php?' . api_get_cidreq() . '">' . Display :: return_icon('import_qti2.png', get_lang('ImportQtiQuiz'),'','32') .'</a>';

+ 128 - 12
main/exercice/exercise.class.php

@@ -5,6 +5,7 @@
  * @package chamilo.exercise
  * @author Olivier Brouckaert
  * @author Julio Montoya Cleaning exercises
+ * Modified by Hubert Borderiou 2011-10-21 (question category)
  */
 /**
  * Code
@@ -48,6 +49,7 @@ class Exercise {
 	public $course;
 	public $propagate_neg;
 	public $review_answers; //
+	public $randomByCat;
 
 	 
 	/**
@@ -72,6 +74,7 @@ class Exercise {
 		$this->expired_time 	= '0000-00-00 00:00:00';
 		$this->propagate_neg    = 0;
 		$this->review_answers	= false;
+		$this->randomByCat = 0;	//
 
 		if (!empty($course_id)) {			
 			$course_info        =  api_get_course_info_by_id($this->course_id);
@@ -114,6 +117,7 @@ class Exercise {
 			$this->attempts 		= $object->max_attempt;
 			$this->feedbacktype 	= $object->feedback_type;
 			$this->propagate_neg    = $object->propagate_neg;
+			$this->randomByCat = $object->random_by_category; //
 		
 			$this->review_answers   = (isset($object->review_answers) && $object->review_answers == 1) ? true : false;  
 			
@@ -234,6 +238,53 @@ class Exercise {
 		return $this->type;
 	}
 
+
+	/**
+	 * return 1 or 2 if randomByCat 
+	 * @author - hubert borderiou
+	 * @return - integer - quiz random by category
+	 */
+	function selectRandomByCat() {
+	 	return $this->randomByCat;
+	}
+
+	/**
+	 * return 0 if no random by cat
+	 * return 1 if rendom by cat, categories shuffled
+	 * return 2 if random by cat, categories sorted by alphabetic order
+	 * @author - hubert borderiou
+	 * @return - integer - quiz random by category
+	 */
+	function isRandomByCat() {
+		$res = 0;
+		if ($this->randomByCat == 1) {
+			$res = 1;
+		}
+		else if ($this->randomByCat == 2) {
+			$res = 2;
+		}
+		return $res;
+	}
+
+	/**
+	 * return nothing
+	 * update randomByCat value for object
+	 * @author - hubert borderiou
+	 */
+	function updateRandomByCat($in_randombycat) {
+	 if ($in_randombycat == 1) {
+	 		$this->randomByCat = 1;
+		}
+		else if ($in_randombycat == 2) {
+	 		$this->randomByCat = 2;
+		}
+		else {
+			$this->randomByCat = 0;
+		}
+	}
+
+
+
 	/**
 	 * tells if questions are selected randomly, and if so returns the draws
 	 *
@@ -554,6 +605,7 @@ class Exercise {
 		$active 		= $this->active;
 		$propagate_neg  = $this->propagate_neg;
 		$review_answers = (isset($this->review_answers) && $this->review_answers) ? 1 : 0;
+		$randomByCat = $this->randomByCat; //
 		
 		$session_id 	= api_get_session_id();
 		 
@@ -584,9 +636,10 @@ class Exercise {
 					start_time     = '$start_time',
 					end_time       = '$end_time',
 					max_attempt    ='".Database::escape_string($attempts)."',
-        			expired_time   ='".Database::escape_string($expired_time)."',
-        			propagate_neg  ='".Database::escape_string($propagate_neg)."',
-        			review_answers  ='".Database::escape_string($review_answers)."',
+     			    expired_time   ='".Database::escape_string($expired_time)."',
+         			propagate_neg  ='".Database::escape_string($propagate_neg)."',
+         			review_answers  ='".Database::escape_string($review_answers)."',
+        	        random_by_category	='".Database::escape_string($randomByCat)."',
 					results_disabled='".Database::escape_string($results_disabled)."'";
 			}
 			
@@ -601,8 +654,7 @@ class Exercise {
 			}
 		} else {
 			// creates a new exercise
-			$sql="INSERT INTO $TBL_EXERCICES (c_id, start_time, end_time, title, description, sound, type, random, random_answers,
-											  active, results_disabled, max_attempt, feedback_type, expired_time, session_id, review_answers)
+			$sql="INSERT INTO $TBL_EXERCICES (c_id, start_time, end_time, title, description, sound, type, random, random_answers, active, results_disabled, max_attempt, feedback_type, expired_time, session_id, review_answers, random_by_category)
 					VALUES(
 						".$this->course_id.",
 						'$start_time','$end_time',
@@ -618,7 +670,8 @@ class Exercise {
 						'".Database::escape_string($feedbacktype)."',
 						'".Database::escape_string($expired_time)."',
 						'".Database::escape_string($session_id)."',
-						'".Database::escape_string($review_answers)."'
+						'".Database::escape_string($review_answers)."',
+						'".Database::escape_string($randomByCat)."'
 						)";
 			Database::query($sql);
 			$this->id = Database::insert_id();
@@ -868,6 +921,15 @@ class Exercise {
 			$radios_random_answers[] = FormValidator :: createElement ('radio', 'randomAnswers', null, get_lang('No'),'0');
 			$form->addGroup($radios_random_answers, null, get_lang('RandomAnswers'));
 
+			//randow by category
+			$form->addElement('html','<div class="clear">&nbsp;</div>');
+			$radiocat = array();
+			$radiocat[] = FormValidator::createElement('radio', 'randomByCat', null, get_lang('yesWithCategoriesShuffled'),'1');
+			$radiocat[] = FormValidator::createElement('radio', 'randomByCat', null, get_lang('yesWithCategoriesSorted'),'2');
+			$radiocat[] = FormValidator::createElement('radio', 'randomByCat', null, get_lang('No'),'0');
+			$form->addGroup($radiocat, null, get_lang('RandomQuestionByCategory'));
+			$form->addElement('html','<div class="clear">&nbsp;</div>');
+			
 			//Attempts
 			$attempt_option=range(0,10);
 			$attempt_option[0]=get_lang('Infinite');
@@ -898,6 +960,7 @@ class Exercise {
 			//$check_option=$this->selectType();
 			$diplay = 'block';							
 			$form->addElement('checkbox', 'propagate_neg', get_lang('PropagateNegativeResults'), null);			
+			$form->addElement('html','<div class="clear">&nbsp;</div>');
 			$form->addElement('checkbox', 'review_answers', get_lang('ReviewAnswers'), null);			
 				
 			$form->addElement('html','<div id="divtimecontrol"  style="display:'.$diplay.';">');
@@ -981,9 +1044,8 @@ class Exercise {
 				$defaults['exerciseFeedbackType'] = $this->selectFeedbackType();
 				$defaults['results_disabled'] = $this->selectResultsDisabled();
 				$defaults['propagate_neg'] = $this->selectPropagateNeg();
-				
 				$defaults['review_answers'] = $this->review_answers;
-				
+				$defaults['randomByCat'] = $this->selectRandomByCat(); //
 
 				if (($this->start_time!='0000-00-00 00:00:00'))
 				$defaults['activate_start_date_check'] = 1;
@@ -1008,7 +1070,7 @@ class Exercise {
 				$defaults['exerciseDescription'] = '';
 				$defaults['exerciseFeedbackType'] = 0;
 				$defaults['results_disabled'] = 0;
-
+				$defaults['randomByCat'] = 0;	// 
 				$defaults['start_time'] = date('Y-m-d 12:00:00');
 				$defaults['end_time']   = date('Y-m-d 12:00:00',time()+84600);
 			}
@@ -1038,7 +1100,7 @@ class Exercise {
 		$this->updateResultsDisabled($form->getSubmitValue('results_disabled'));
 		$this->updateExpiredTime($form->getSubmitValue('enabletimercontroltotalminutes'));
 		$this->updatePropagateNegative($form->getSubmitValue('propagate_neg'));
-		
+		$this->updateRandomByCat($form->getSubmitValue('randomByCat'));			//
 		$this->updateReviewAnswers($form->getSubmitValue('review_answers'));
 
 		if ($form->getSubmitValue('activate_start_date_check') == 1) {
@@ -3223,8 +3285,62 @@ class Exercise {
 	}
 	
 	function get_validated_question_list() {
-		return  ($this->isRandom() ? $this->selectRandomList() : $this->selectQuestionList());
-	}
+		$tabres = array();
+		$isRandomByCategory = $this->isRandomByCat();
+		if (!$isRandomByCategory) {
+			if ($this->isRandom()) {
+				$tabres = $this->selectRandomList();
+			}
+			else {
+				$tabres = $this->selectQuestionList();
+			}
+		}
+		else {
+			if ($this->isRandom()) {
+				if (!class_exists("Testcategory")) {
+					require_once("testcategory.class.php");
+				}
+				// -----------------------------
+				// USE question categories hub 13-10-2011
+				// -----------------------------
+				// get questions by category for this exercice
+				// we have to choice $objExercise->random question in each array values of $tabCategoryQuestions
+				// key of $tabCategoryQuestions are the categopy id (0 for not in a category)
+				// value is the array of question id of this category
+				$questionList = array();
+				$tabCategoryQuestions = array();
+				$tabCategoryQuestions = Testcategory::getQuestionsByCat($this->id);
+				$isRandomByCategory = $this->selectRandomByCat();
+				// on tri les catégories en fonction du terme entre [] en tête de la description de la catégorie
+				/*
+				 * ex de catégories :
+				 * [biologie] Maîtriser les mécanismes de base de la génétique
+				 * [biologie] Relier les moyens de défenses et les agents infectieux
+				 * [biologie] Savoir où est produite l'énergie dans les cellules et sous quelle forme
+				 * [chimie] Classer les molécules suivant leur pouvoir oxydant ou réducteur
+				 * [chimie] Connaître la définition de la théorie acide/base selon Brönsted
+				 * [chimie] Connaître les charges des particules
+				 * On veut dans l'ordre des groupes définis par le terme entre crochet au début du titre de la catégorie
+				*/
+				// If test option is Grouped By Categories
+				if ($isRandomByCategory == 2) {
+					$tabCategoryQuestions = Testcategory::sortTabByBracketLabel($tabCategoryQuestions); // 24-02-2011 hub pour projet Bernard Ycard
+				}
+				while (list($cat_id, $tabquestion) = each($tabCategoryQuestions)) {
+					$questionList = array_merge($questionList, Testcategory::getNElementsFromArray($tabquestion, $this->random));
+				}
+				// shuffle the question list if test is not grouped by categories
+				if ($isRandomByCategory == 1) {
+					shuffle($questionList); // or not
+				}			
+				$tabres = $questionList;
+			}
+			else {
+				// Problem, random by category has been selected and we have no $this->isRandom nnumber of question selected
+				// Should not happened
+			}
+		}
+		return $tabres;	}
 	
 	public function get_stat_track_exercise_info_by_exe_id($exe_id) {
 		$track_exercises = Database :: get_statistic_table(TABLE_STATISTIC_TRACK_E_EXERCICES);

+ 26 - 0
main/exercice/exercise.lib.php

@@ -8,6 +8,7 @@
  * @package chamilo.exercise
  * @author Olivier Brouckaert <oli.brouckaert@skynet.be>
  * @version $Id: exercise.lib.php 22247 2009-07-20 15:57:25Z ivantcholakov $
+ * Modified by Hubert Borderiou 2011-10-21 Question Category
  */
 /**
  * Code
@@ -51,6 +52,7 @@ function showQuestion($questionId, $only_questions = false, $origin = false, $cu
 			$questionDescription = $objQuestionTmp->selectDescription();
 			
 			if ($show_title) {
+				Testcategory::displayCategoryAndTitle($objQuestionTmp->id);	// 				
 				echo Display::div($current_item.'. '.$objQuestionTmp->selectTitle(), array('class'=>'question_title'));
 			}
 			if (!empty($questionDescription)) {
@@ -501,6 +503,7 @@ function showQuestion($questionId, $only_questions = false, $origin = false, $cu
 
 		if (!$only_questions) {
             if ($show_title) {
+								Testcategory::displayCategoryAndTitle($objQuestionTmp->id);	//             	
                 echo '<div class="question_title">'.$current_item.'. '.$questionName.'</div>';
             }
 			//@todo I need to the get the feedback type
@@ -1257,6 +1260,29 @@ function get_all_exercises($course_info = null, $session_id = 0, $check_dates =
     return Database::select('*',$TBL_EXERCICES, $conditions);
 }
 
+
+/**
+ * Getting all active exercises from a course from a session (if a session_id is provided we will show all the exercises in the course + all exercises in the session)
+ * @param   array   course data
+ * @param   int     session id
+ * @param		int			course c_id
+ * @return  array   array with exercise data
+ * modified by Hubert Borderiou 
+ */
+function get_all_exercises_for_course_id($course_info = null, $session_id = 0, $course_id=0) {
+   	$TBL_EXERCICES = Database :: get_course_table(TABLE_QUIZ_TEST);
+    if ($session_id == -1) {
+    	$session_id  = 0;
+    }
+    if ($session_id == 0) {
+    	$conditions = array('where'=>array('active = ? AND session_id = ? AND c_id=?'=>array('1', $session_id, $course_id)), 'order'=>'title');
+    } else {
+        //All exercises
+    	$conditions = array('where'=>array('active = ? AND (session_id = 0 OR session_id = ? ) AND c_id=?' =>array('1', $session_id, $course_id)), 'order'=>'title');
+    }
+    return Database::select('*',$TBL_EXERCICES, $conditions);
+}
+
 /**
  * Gets the position of the score based in a given score (result/weight) and the exe_id based in the user list
  * (NO Exercises in LPs )

+ 5 - 0
main/exercice/exercise_submit.php

@@ -22,6 +22,7 @@
 * 			Cleaning exercises (2010), 
 * 			Adding hotspot delineation support (2011)
 * 			Adding reminder + ajax support (2011)
+*   Modified by hubert.borderiou (2011-10-21 question category)
 */
 /**
  * Code
@@ -585,6 +586,10 @@ if ($question_count != 0) {
 	}
 } else {
 	$error = get_lang('ThereAreNoQuestionsForThisExercise');
+	// if we are in the case where user select random by category, but didn't choose the number of random question
+	if ($objExercise->selectRandomByCat() > 0 && $objExercise->random <= 0) {
+		$error .= "<br/>".get_lang('pleaseSelectSomeRandomQuestion');
+	}
 }
 
 if (!empty ($_GET['gradebook']) && $_GET['gradebook'] == 'view') {

+ 256 - 125
main/exercice/question.class.php

@@ -5,10 +5,12 @@
 *	@package chamilo.exercise
 * 	@author Olivier Brouckaert
 *   @author Julio Montoya <gugli100@gmail.com> lot of bug fixes
+*   Modified by hubert.borderiou@grenet.fr - add question categories
 */
 /**
  * Code
  */
+
 if(!class_exists('Question')):
 
 // answer types
@@ -25,6 +27,7 @@ define('UNIQUE_ANSWER_NO_OPTION',       10);
 define('MULTIPLE_ANSWER_TRUE_FALSE',    11);
 define('MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE',    12);
 
+if (!class_exists('Category')) include_once("testcategory.class.php");	// hub 12-10-2011
 
 /**
 	QUESTION CLASS
@@ -46,8 +49,9 @@ abstract class Question
 	public $level;
 	public $picture;
 	public $exerciseList;  // array with the list of exercises which this question is in
+	public $category;	// hub 12-10-2011
 	private $isContent;
-    public $course;
+  public $course;
     
 	static $typePicture = 'new_question.png';
 	static $explanationLangVar = '';
@@ -79,10 +83,10 @@ abstract class Question
 		$this->position=1;
 		$this->picture='';
 		$this->level = 1;
-        $this->extra='';
+		$this->category=0;	// hub 12-10-2011
+    $this->extra='';
 		$this->exerciseList=array();
 		$this->course = api_get_course_info();
-		$this->course_id = api_get_course_int_id(); 
 	}
 
 	public function getIsContent() {
@@ -105,17 +109,17 @@ abstract class Question
         
         if (!empty($course_id)) {            
             $course_info =  api_get_course_info_by_id($course_id);
-        } else {            
+        } else {
+            global $course;
             $course_info = api_get_course_info();
         }        
         $course_id = $course_info['real_id'];
 
-		$TBL_EXERCICES         = Database::get_course_table(TABLE_QUIZ_TEST);
-		$TBL_QUESTIONS         = Database::get_course_table(TABLE_QUIZ_QUESTION);
-		$TBL_EXERCICE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
+		$TBL_EXERCICES         = Database::get_course_table(TABLE_QUIZ_TEST,          $course_info['db_name']);
+		$TBL_QUESTIONS         = Database::get_course_table(TABLE_QUIZ_QUESTION,      $course_info['db_name']);
+		$TBL_EXERCICE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION, $course_info['db_name']);
         
-		$sql = "SELECT question,description,ponderation,position,type,picture,level,extra 
-				FROM $TBL_QUESTIONS WHERE c_id = $course_id AND id = $id ";
+		$sql = "SELECT question,description,ponderation,position,type,picture,level,extra FROM $TBL_QUESTIONS WHERE c_id = $course_id AND id = $id ";
         
 		$result = Database::query($sql);
 
@@ -132,8 +136,9 @@ abstract class Question
 			$objQuestion->type			= $object->type;
 			$objQuestion->picture		= $object->picture;
 			$objQuestion->level			= (int) $object->level;
-            $objQuestion->extra         = $object->extra;
-            $objQuestion->course        = $course_info;
+      $objQuestion->extra         = $object->extra;
+      $objQuestion->course        = $course_info;
+      $objQuestion->category	=	Testcategory::getCategoryForQuestion($id);	// hub 12-10-2011
             
 			$sql = "SELECT exercice_id FROM $TBL_EXERCICE_QUESTION WHERE c_id = $course_id AND question_id = $id";
 			$result_exercise_list = Database::query($sql);
@@ -299,6 +304,74 @@ abstract class Question
 		$this->weighting=$weighting;
 	}
 
+
+	/**
+	 * @author - Hubert Borderiou 12-10-2011
+	 * @param - array of category $in_category
+	 */
+	function updateCategory($in_category) {
+		$this->category=$in_category;
+	}
+	
+	/**
+	 * @author - Hubert Borderiou 12-10-2011
+	 * @param - interger $in_positive
+	 */
+	function updateScoreAlwaysPositive($in_positive) {
+		$this->scoreAlwaysPositive=$in_positive;
+	}
+	
+	/**
+	 * @author - Hubert Borderiou 12-10-2011
+	 * @param - interger $in_positive
+	 */
+	function updateUncheckedMayScore($in_positive) {
+		$this->uncheckedMayScore=$in_positive;
+	}
+	
+	/**
+	 * @author - Hubert Borderiou 12-10-2011
+	 * @param - interger $in_positive
+	 * in this version, a question can only have 1 category
+	 * if category is 0, then question has no category then delete the category entry
+	 */
+	function saveCategory($in_category) {
+		if ($in_category <= 0) {
+			$this->deleteCategory();
+		}
+		// update or add category for a question
+		else {
+			$TBL_QUESTION_REL_CATEGORY = Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY);
+			$category_id = Database::escape_string($in_category);
+			$question_id = Database::escape_string($this->id);
+			$sql = "SELECT count(*) AS nb FROM $TBL_QUESTION_REL_CATEGORY WHERE question_id=$question_id AND c_id=".api_get_course_int_id();
+			$res = Database::query($sql);
+			$row = Database::fetch_array($res);
+			if ($row['nb'] > 0){
+				$sql = "UPDATE $TBL_QUESTION_REL_CATEGORY SET category_id=$category_id WHERE question_id=$question_id AND c_id=".api_get_course_int_id();
+				$res = Database::query($sql);
+			}
+			else {
+				$sql = "INSERT INTO $TBL_QUESTION_REL_CATEGORY VALUES (".api_get_course_int_id().", $question_id, $category_id)";
+				$res = Database::query($sql);
+			}
+		}
+	}	
+	
+	/**
+	 * @author hubert borderiou 12-10-2011
+	 * delete any category entry for question id
+	 * @param : none
+	 * delte the category for question
+	 */
+	function deleteCategory() {
+		$TBL_QUESTION_REL_CATEGORY = Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY);
+		$question_id = Database::escape_string($this->id);
+	 	$sql = "DELETE FROM $TBL_QUESTION_REL_CATEGORY WHERE question_id=$question_id AND c_id=".api_get_course_int_id();
+	 	$res = Database::query($sql);
+	}
+	
+
 	/**
 	 * changes the question position
 	 *
@@ -329,16 +402,17 @@ abstract class Question
 	 * @param - integer $type - answer type
 	 */
 	function updateType($type) {
-		$TBL_REPONSES = Database::get_course_table(TABLE_QUIZ_ANSWER);
+		$TBL_REPONSES           = Database::get_course_table(TABLE_QUIZ_ANSWER, $this->course['db_name']);
 
 		// if we really change the type
 		if($type != $this->type) {
 			// if we don't change from "unique answer" to "multiple answers" (or conversely)
-			if(!in_array($this->type,array(UNIQUE_ANSWER, MULTIPLE_ANSWER)) || !in_array($type,array(UNIQUE_ANSWER,MULTIPLE_ANSWER))) {
+			if(!in_array($this->type,array(UNIQUE_ANSWER,MULTIPLE_ANSWER)) || !in_array($type,array(UNIQUE_ANSWER,MULTIPLE_ANSWER))) {
 				// removes old answers
-				$sql = "DELETE FROM $TBL_REPONSES WHERE c_id = ".api_get_course_int_id()." AND question_id = ".Database::escape_string($this->id);
+				$sql="DELETE FROM $TBL_REPONSES WHERE question_id='".Database::escape_string($this->id)."'";
 				Database::query($sql);
 			}
+
 			$this->type=$type;
 		}
 	}
@@ -479,12 +553,12 @@ abstract class Question
 	 */
 	function exportPicture($questionId, $course_info) {
 		$course_id = $course_info['real_id'];
-        $TBL_QUESTIONS  	 = Database::get_course_table(TABLE_QUIZ_QUESTION);
+        $TBL_QUESTIONS  = Database::get_course_table(TABLE_QUIZ_QUESTION, $course_info['db_name']);
         $destination_path    = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document/images';
         $source_path         = api_get_path(SYS_COURSE_PATH).$this->course['path'].'/document/images';        		
 
 		// if the question has got an ID and if the picture exists
-		if ($this->id && !empty($this->picture)) {
+		if($this->id && !empty($this->picture)) {
 			$picture=explode('.',$this->picture);
 			$Extension=$picture[sizeof($picture)-1];
 			$picture='quiz-'.$questionId.'.'.$Extension;
@@ -577,8 +651,8 @@ abstract class Question
 	 */
 	function save($exerciseId=0) {
 
-		$TBL_EXERCICE_QUESTION	= Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
-		$TBL_QUESTIONS			= Database::get_course_table(TABLE_QUIZ_QUESTION);
+		$TBL_EXERCICE_QUESTION	= Database::get_course_table(TABLE_QUIZ_TEST_QUESTION, $this->course['db_name']);
+		$TBL_QUESTIONS			= Database::get_course_table(TABLE_QUIZ_QUESTION, $this->course['db_name']);
 
 		$id				= $this->id;
 		$question		= $this->question;
@@ -588,11 +662,13 @@ abstract class Question
 		$type			= $this->type;
 		$picture		= $this->picture;
 		$level			= $this->level;
-        $extra			= $this->extra;
-        $c_id 			= $this->course['real_id'];
-        
+    $extra			= $this->extra;
+    $c_id 			= $this->course['real_id'];
+    $category   = $this->category;	// hub 12-10-2011
+     
+    
 		// question already exists
-		if (!empty($id)) {
+		if(!empty($id)) {
 			$sql="UPDATE $TBL_QUESTIONS SET
 					question 	='".Database::escape_string($question)."',
 					description	='".Database::escape_string($description)."',
@@ -600,23 +676,24 @@ abstract class Question
 					position	='".Database::escape_string($position)."',
 					type		='".Database::escape_string($type)."',
 					picture		='".Database::escape_string($picture)."',
-                    extra       ='".Database::escape_string($extra)."',
+          extra       ='".Database::escape_string($extra)."',
 					level		='".Database::escape_string($level)."'
-				WHERE c_id = ".$c_id." AND id = '".Database::escape_string($id)."'";
+				WHERE id='".Database::escape_string($id)."'";
 			Database::query($sql);
+			$this->saveCategory($category);	// hub 12-10-2011
 			if (!empty($exerciseId)) {
 				api_item_property_update($this->course, TOOL_QUIZ, $id,'QuizQuestionUpdated',api_get_user_id);
 			}
-            if (api_get_setting('search_enabled')=='true') {
-                if ($exerciseId != 0) {
-                    $this -> search_engine_edit($exerciseId);
-                } else {
-                    /**
-                     * actually there is *not* an user interface for
-                     * creating questions without a relation with an exercise
-                     */
-                }
-            }
+      if (api_get_setting('search_enabled')=='true') {
+	      if ($exerciseId != 0) {
+	        $this -> search_engine_edit($exerciseId);
+	      } else {
+	        /**
+	         * actually there is *not* an user interface for
+	         * creating questions without a relation with an exercise
+	         */
+	      }
+      }
 
 		} else {
 			// creates a new question
@@ -624,7 +701,8 @@ abstract class Question
 					   WHERE 	question.id					= test_question.question_id AND 
 								test_question.exercice_id	= '".Database::escape_string($exerciseId)."' AND
 								question.c_id 				= $c_id AND
-								test_question.c_id 			= $c_id								
+								test_question.c_id 			= $c_id
+								
 						";
 			$result	= Database::query($sql);
 			$current_position = Database::result($result,0,0);
@@ -642,8 +720,9 @@ abstract class Question
                     '".Database::escape_string($level)."'
 					)";			
 			Database::query($sql);
+
 			$this->id = Database::insert_id();
-			
+
 			api_item_property_update($this->course, TOOL_QUIZ, $this->id,'QuizQuestionAdded',api_get_user_id());
 
 			// If hotspot, create first answer
@@ -662,16 +741,17 @@ abstract class Question
 			}
 			
 
-            if (api_get_setting('search_enabled')=='true') {
-                if ($exerciseId != 0) {
-                    $this -> search_engine_edit($exerciseId, TRUE);
-                } else {
-                    /**
-                     * actually there is *not* an user interface for
-                     * creating questions without a relation with an exercise
-                     */
-                }
-            }
+      if (api_get_setting('search_enabled')=='true') {
+	      if ($exerciseId != 0) {
+	        $this -> search_engine_edit($exerciseId, TRUE);
+	      } 
+	      else {
+	        /**
+	         * actually there is *not* an user interface for
+	         * creating questions without a relation with an exercise
+	         */
+	      }
+      }
 		}
 
 		// if the question is created in an exercise
@@ -835,28 +915,28 @@ abstract class Question
 		$id=$this->id;
 
 		// searches the position of the exercise ID in the list
-		$pos = array_search($exerciseId,$this->exerciseList);
+		$pos=array_search($exerciseId,$this->exerciseList);
 
 		// exercise not found
-		if ($pos === false) {
+		if($pos === false) {
 			return false;
 		} else {
 			// deletes the position in the array containing the wanted exercise ID
 			unset($this->exerciseList[$pos]);
             //update order of other elements
-            $sql = "SELECT question_order FROM $TBL_EXERCICE_QUESTION WHERE c_id = ".api_get_course_int_id()." AND question_id='".Database::escape_string($id)."' AND exercice_id='".Database::escape_string($exerciseId)."'";
+            $sql = "SELECT question_order FROM $TBL_EXERCICE_QUESTION WHERE question_id='".Database::escape_string($id)."' AND exercice_id='".Database::escape_string($exerciseId)."'";
             $res = Database::query($sql);
             if (Database::num_rows($res)>0) {
                 $row = Database::fetch_array($res);
                 if (!empty($row['question_order'])) {
-                    echo $sql = "UPDATE $TBL_EXERCICE_QUESTION SET question_order = question_order-1 
-                    		WHERE c_id = ".api_get_course_int_id()." AND exercice_id='".Database::escape_string($exerciseId)."' AND question_order > ".$row['question_order'];
+                    $sql = "UPDATE $TBL_EXERCICE_QUESTION SET question_order = question_order-1 WHERE exercice_id='".Database::escape_string($exerciseId)."' AND question_order > ".$row['question_order'];
                     $res = Database::query($sql);
                 }
             }
 
-			$sql = "DELETE FROM $TBL_EXERCICE_QUESTION WHERE c_id = ".api_get_course_int_id()." AND question_id='".Database::escape_string($id)."' AND exercice_id='".Database::escape_string($exerciseId)."'";			
+			$sql="DELETE FROM $TBL_EXERCICE_QUESTION WHERE question_id='".Database::escape_string($id)."' AND exercice_id='".Database::escape_string($exerciseId)."'";
 			Database::query($sql);
+
 			return true;
 		}
 	}
@@ -869,45 +949,52 @@ abstract class Question
 	 * @author - Olivier Brouckaert
 	 * @param - integer $deleteFromEx - exercise ID if the question is only removed from one exercise
 	 */
-	function delete($deleteFromEx = 0) {
+	function delete($deleteFromEx=0) {
 		global $_course,$_user;
 
-		$TBL_EXERCICE_QUESTION	= Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
-		$TBL_QUESTIONS			= Database::get_course_table(TABLE_QUIZ_QUESTION);
-		$TBL_REPONSES           = Database::get_course_table(TABLE_QUIZ_ANSWER);
-
-		$id = $this->id;
+		$TBL_EXERCICE_QUESTION	= Database::get_course_table(TABLE_QUIZ_TEST_QUESTION, $this->course['db_name']);
+		$TBL_QUESTIONS			= Database::get_course_table(TABLE_QUIZ_QUESTION, $this->course['db_name']);
+		$TBL_REPONSES           = Database::get_course_table(TABLE_QUIZ_ANSWER, $this->course['db_name']);
+		$TBL_QUIZ_QUESTION_REL_CATEGORY = Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY, $this->course['db_name']);	// hub 12-10-2011
+		
+		$id=$this->id;
 
 		// if the question must be removed from all exercises
-		if (!$deleteFromEx) {
+		if(!$deleteFromEx)
+		{
             //update the question_order of each question to avoid inconsistencies
-            $sql = "SELECT exercice_id, question_order FROM $TBL_EXERCICE_QUESTION WHERE c_id = ".api_get_course_int_id()." AND question_id='".Database::escape_string($id)."'";
+            $sql = "SELECT exercice_id, question_order FROM $TBL_EXERCICE_QUESTION WHERE question_id='".Database::escape_string($id)."'";
             $res = Database::query($sql);
             if (Database::num_rows($res)>0) {
                 while ($row = Database::fetch_array($res)) {
                     if (!empty($row['question_order'])) {
-                        $sql = "UPDATE $TBL_EXERCICE_QUESTION SET question_order = question_order-1 
-                        		WHERE c_id = ".api_get_course_int_id()." AND exercice_id='".Database::escape_string($row['exercice_id'])."' AND question_order > ".$row['question_order'];
+                        $sql = "UPDATE $TBL_EXERCICE_QUESTION SET question_order = question_order-1 WHERE exercice_id='".Database::escape_string($row['exercice_id'])."' AND question_order > ".$row['question_order'];
                         $res = Database::query($sql);
                     }
                 }
             }
-			$sql="DELETE FROM $TBL_EXERCICE_QUESTION WHERE c_id = ".api_get_course_int_id()." AND question_id='".Database::escape_string($id)."'";
+			$sql="DELETE FROM $TBL_EXERCICE_QUESTION WHERE question_id='".Database::escape_string($id)."'";
 			Database::query($sql);
 
-			$sql="DELETE FROM $TBL_QUESTIONS WHERE c_id = ".api_get_course_int_id()." AND id='".Database::escape_string($id)."'";
+			$sql="DELETE FROM $TBL_QUESTIONS WHERE id='".Database::escape_string($id)."'";
 			Database::query($sql);
 
-			$sql="DELETE FROM $TBL_REPONSES WHERE c_id = ".api_get_course_int_id()." AND question_id='".Database::escape_string($id)."'";
+			$sql="DELETE FROM $TBL_REPONSES WHERE question_id='".Database::escape_string($id)."'";
 			Database::query($sql);
 
+			// hub 12-10-2011 remove the category of this question in the question_rel_category table
+			$sql = "DELETE FROM $TBL_QUIZ_QUESTION_REL_CATEGORY WHERE question_id='".Database::escape_string($id)."' AND c_id=".api_get_course_int_id();
+			Database::query($sql);
+			
 			api_item_property_update($this->course, TOOL_QUIZ, $id,'QuizQuestionDeleted',api_get_user_id());
 			$this->removePicture();
 
 			// resets the object
 			$this->Question();
-		} // just removes the exercise from the list
-		else {
+		}
+		// just removes the exercise from the list
+		else
+		{
 			$this->removeFromList($deleteFromEx);
             if (api_get_setting('search_enabled')=='true' && extension_loaded('xapian')) {
                 // disassociate question with this exercise
@@ -931,8 +1018,8 @@ abstract class Question
         } else {
         	$course_info = $course_info;
         }
-        $TBL_QUESTIONS        = Database::get_course_table(TABLE_QUIZ_QUESTION);
-        $TBL_QUESTION_OPTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION);
+        $TBL_QUESTIONS        = Database::get_course_table(TABLE_QUIZ_QUESTION, $course_info['db_name']);
+        $TBL_QUESTION_OPTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION, $course_info['db_name']);
 
 		$question     = $this->question;
 		$description  = $this->description;
@@ -1007,7 +1094,8 @@ abstract class Question
 		echo '<script>
 			// hack to hide http://cksource.com/forums/viewtopic.php?f=6&t=8700
 
-			function FCKeditor_OnComplete( editorInstance ) {
+			function FCKeditor_OnComplete( editorInstance )
+			{
 			   if (document.getElementById ( \'HiddenFCK\' + editorInstance.Name )) {
 			      HideFCKEditorByInstanceName (editorInstance.Name);
 			   }
@@ -1018,16 +1106,36 @@ abstract class Question
 			      document.getElementById ( \'HiddenFCK\' + editorInstanceName ).className = "media";
 			      }
 			}
-			function show_media() {
+
+			function show_media()
+			{
 				var my_display = document.getElementById(\'HiddenFCKquestionDescription\').style.display;
 				if(my_display== \'none\' || my_display == \'\') {
 				document.getElementById(\'HiddenFCKquestionDescription\').style.display = \'block\';
-				document.getElementById(\'media_icon\').innerHTML=\' <img style="vertical-align: middle;" src="../img/looknfeelna.png" alt="" /> '.addslashes(api_htmlentities(get_lang('EnrichQuestion'))).'\';
+				document.getElementById(\'media_icon\').innerHTML=\'&nbsp;<img style="vertical-align: middle;" src="../img/looknfeelna.png" alt="" />&nbsp;'.get_lang('EnrichQuestion').'\';
 			} else {
 				document.getElementById(\'HiddenFCKquestionDescription\').style.display = \'none\';
-				document.getElementById(\'media_icon\').innerHTML=\' <img style="vertical-align: middle;" src="../img/looknfeel.png" alt="" /> '.addslashes(api_htmlentities(get_lang('EnrichQuestion'))).'\';
+				document.getElementById(\'media_icon\').innerHTML=\'&nbsp;<img style="vertical-align: middle;" src="../img/looknfeel.png" alt="" />&nbsp;'.get_lang('EnrichQuestion').'\';
 			}
 		}
+		
+		// hub 13-12-2010
+		function visiblerDevisibler(in_id) {
+			if (document.getElementById(in_id)) {
+				if (document.getElementById(in_id).style.display == "none") {
+					document.getElementById(in_id).style.display = "block";
+					if (document.getElementById(in_id+"Img")) {
+						document.getElementById(in_id+"Img").src = "../img/div_hide.gif";
+					}
+				}
+				else {
+					document.getElementById(in_id).style.display = "none";
+					if (document.getElementById(in_id+"Img")) {
+						document.getElementById(in_id+"Img").src = "../img/div_show.gif";
+					}
+				}
+			}
+		}		
 		</script>';
 
 
@@ -1041,17 +1149,12 @@ abstract class Question
 		//$test=FormValidator :: createElement ('text', 'questionName');
 
 		//$radios_results_enabled[]=$test;
-		// question level
-		//@todo move levles into a table
-		$select_level = array (1,2,3,4,5);
-		//$radios_results_enabled[] =
-		foreach($select_level as $val) {
-			$radios_results_enabled[] = FormValidator :: createElement ('radio', null, null,$val,$val);
-		}
-		$form->addGroup($radios_results_enabled,'questionLevel',get_lang('Difficulty'));
 
 		$renderer->setElementTemplate('<div class="row"><div class="label">{label}</div><div class="formw" >{element}</div></div>','questionName');
 		$renderer->setElementTemplate('<div class="row"><div class="label">{label}</div><div class="formw">{element}</div></div>','questionLevel');
+		// -------------------------------
+		// Enrich question		
+		// -------------------------------
 		$form->addRule('questionName', get_lang('GiveQuestion'), 'required');
 
 		// default content
@@ -1071,10 +1174,7 @@ abstract class Question
 		$form -> addElement('html','<div class="row">
 		<div class="label"></div>
 		<div class="formw" style="height:50px">
-			<a href="javascript://" onclick=" return show_media()">
-				<span id="media_icon">
-				<img style="vertical-align: middle;" src="../img/looknfeel.png" alt="" /> '.addslashes(api_htmlentities(get_lang('EnrichQuestion'))).'
-				</span></a>
+			<a href="javascript://" onclick=" return show_media()"> <span id="media_icon"> <img style="vertical-align: middle;" src="../img/looknfeel.png" alt="" />&nbsp;'.get_lang('EnrichQuestion').'</span></a>
 		</div>
 		</div>');
 
@@ -1084,31 +1184,52 @@ abstract class Question
 
 		$renderer->setElementTemplate('<div class="row"><div class="label">{label}</div><div class="formw">{element}</div></div>','questionDescription');
 
+		// -------------------------------
+		// Advanced parameters
+		// -------------------------------
+		// question level
+		//@todo move levles into a table
+		$select_level = array (1,2,3,4,5);
+		//$radios_results_enabled[] =
+		foreach($select_level as $val) {
+			$radios_results_enabled[] = FormValidator :: createElement ('radio', null, null,$val,$val);
+		}
+		$form->addGroup($radios_results_enabled,'questionLevel',get_lang('Difficulty'));
+		// HUB 12-10-2011
+		// categories
+		$tabCat = array();
+		$tabCat = Testcategory::getCategoriesIdAndName(); 
+		$form->addElement('select', 'questionCategory', get_lang('Category'), $tabCat);
+		// note always positive for multiple answer questions
+		// Form's style
+		$renderer->setElementTemplate('<div class="row"><div class="label">{label}</div><div class="formw">{element}</div></div>&nbsp;','questionName');
+		$renderer->setElementTemplate('<div style="margin-left:0%;float:right;text-align:left;width:89%" class=""><a href="javascript:void(0)" onclick="visiblerDevisibler(\'id_advancedOption\')"><img id="id_advancedOptionImg" style="vertical-align:middle;" src="../img/div_show.gif" alt="" />&nbsp;'.get_lang("AdvancedParameters").'</a><div id="id_advancedOption" style="background-color:#EFEFEF;display:none;"><div class="row"><div class="label">{label}</div><div class="formw">{element}</div></div>','questionLevel');
+		$renderer->setElementTemplate('<div class="row"><div class="label">{label}</div><div class="formw">{element}</div></div><br/></div></div><div style="clear:both">&nbsp;</div>','questionCategory');
+		// fhub
 		// hidden values
 		$form->addElement('hidden','myid',$_REQUEST['myid']);
-        
-
-        if (!isset($_GET['fromExercise'])) {            
-    		switch($answerType) {
-    			case 1:	$this->question = get_lang('langDefaultUniqueQuestion'); break;
-    			case 2:	$this->question = get_lang('langDefaultMultipleQuestion'); break;
-    			case 3:	$this->question = get_lang('langDefaultFillBlankQuestion'); break;
-    			case 4:	$this->question = get_lang('langDefaultMathingQuestion'); break;
-    			case 5:	$this->question = get_lang('langDefaultOpenQuestion');	break;
-    			case 9:	$this->question = get_lang('langDefaultMultipleQuestion'); break;
-    		}
-        }
+    if (!isset($_GET['fromExercise'])) {            
+  		switch($answerType) {
+  			case 1:	$this->question = get_lang('langDefaultUniqueQuestion'); break;
+  			case 2:	$this->question = get_lang('langDefaultMultipleQuestion'); break;
+  			case 3:	$this->question = get_lang('langDefaultFillBlankQuestion'); break;
+  			case 4:	$this->question = get_lang('langDefaultMathingQuestion'); break;
+  			case 5:	$this->question = get_lang('langDefaultOpenQuestion');	break;
+  			case 9:	$this->question = get_lang('langDefaultMultipleQuestion'); break;
+  		}
+    }
 		$form->addElement('html','</div>');
 		// default values
 		$defaults = array();		
 		$defaults['questionName']          = $this -> question;
 		$defaults['questionDescription']   = $this -> description;
 		$defaults['questionLevel']         = $this -> level;
-        
-        //Came from he question pool        
-        if (isset($_GET['fromExercise'])) {   
-            $form->setDefaults($defaults);   
-        }
+		$defaults['questionCategory'] = $this->category; // hub 12-10-2011
+		
+    //Came from he question pool        
+    if (isset($_GET['fromExercise'])) {   
+        $form->setDefaults($defaults);   
+    }
         
 		if (!empty($_REQUEST['myid'])) {
 			$form->setDefaults($defaults);
@@ -1126,13 +1247,13 @@ abstract class Question
 	 */
 	function processCreation ($form, $objExercise) {
 		$this -> updateTitle($form->getSubmitValue('questionName'));
-	    $this -> updateDescription($form->getSubmitValue('questionDescription'));
-	    $this -> updateLevel($form->getSubmitValue('questionLevel'));
-	    $this -> save($objExercise -> id);
-	    // modify the exercise
-	    $objExercise->addToList($this -> id);
-        $objExercise->update_question_positions();
-
+		$this -> updateDescription($form->getSubmitValue('questionDescription'));
+		$this -> updateLevel($form->getSubmitValue('questionLevel'));
+		$this->updateCategory($form->getSubmitValue('questionCategory'));	// hub 12-10-2011
+		$this -> save($objExercise -> id);
+		// modify the exercise
+		$objExercise->addToList($this -> id);
+		$objExercise->update_question_positions();
 	}
 
 	/**
@@ -1171,7 +1292,7 @@ abstract class Question
 		if (isset($exerciseId) && !empty($exerciseId)) {
 			$TBL_LP_ITEM	= Database::get_course_table(TABLE_LP_ITEM);
 			$sql="SELECT max_score FROM $TBL_LP_ITEM
-				  WHERE c_id = ".api_get_course_int_id()." AND item_type = '".TOOL_QUIZ."' AND path ='".Database::escape_string($exerciseId)."'";
+				  WHERE item_type = '".TOOL_QUIZ."' AND path ='".Database::escape_string($exerciseId)."'";
 			$result = Database::query($sql);
 			if (Database::num_rows($result) > 0) {
 				$show_quiz_edition = false;
@@ -1183,14 +1304,13 @@ abstract class Question
 		foreach ($question_type_custom_list as $i=>$a_type) {
 			// include the class of the type
 			require_once($a_type[0]);
- 		    // get the picture of the type and the langvar which describes it
-            $img = $explanation = '';
+	    // get the picture of the type and the langvar which describes it
+      $img = $explanation = '';
 			eval('$img = '.$a_type[1].'::$typePicture;');
 			eval('$explanation = get_lang('.$a_type[1].'::$explanationLangVar);');
 			echo '<li>';
 			echo '<div class="icon_image_content">';
 			if ($show_quiz_edition) {
-                 
 				echo '<a href="admin.php?'.api_get_cidreq().'&newQuestion=yes&answerType='.$i.'">'.Display::return_icon($img, $explanation).'</a>';
 				//echo '<br>';
 				//echo '<a href="admin.php?'.api_get_cidreq().'&newQuestion=yes&answerType='.$i.'">'.$explanation.'</a>';
@@ -1199,7 +1319,6 @@ abstract class Question
 				$img = $img['filename'];
 				echo ''.Display::return_icon($img.'_na.gif',$explanation).'';
 				//echo '<br>';
-               
 				//echo ''.$explanation.'';
 			}
 			echo '</div>';
@@ -1235,8 +1354,7 @@ abstract class Question
 	}
     
     static function saveQuestionOption($question_id, $name, $position = 0) {
-        $TBL_EXERCICE_QUESTION_OPTION    = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION);        
-        $params['c_id']  		= api_get_course_int_id();
+        $TBL_EXERCICE_QUESTION_OPTION    = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION);   
         $params['question_id']  = intval($question_id);
         $params['name']         = $name;        
         $params['position']     = $position;             
@@ -1247,12 +1365,12 @@ abstract class Question
     
     static function deleteAllQuestionOptions($question_id) {
     	$TBL_EXERCICE_QUESTION_OPTION    = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION);
-        Database::delete($TBL_EXERCICE_QUESTION_OPTION, array('question_id = ? AND c_id = ?' => array($question_id, api_get_course_int_id())));
+        Database::delete($TBL_EXERCICE_QUESTION_OPTION, array('question_id = ?'=> $question_id));
     }
     
     static function updateQuestionOption($id, $params) {
         $TBL_EXERCICE_QUESTION_OPTION    = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION);
-        $result = Database::update($TBL_EXERCICE_QUESTION_OPTION, $params, array('id = ? AND c_id = ? '=>array($id, api_get_course_int_id())));             
+        $result = Database::update($TBL_EXERCICE_QUESTION_OPTION, $params, array('id = ?'=>$id));             
         return $result;        
     }
     
@@ -1263,7 +1381,7 @@ abstract class Question
         } else {
             $TBL_EXERCICE_QUESTION_OPTION    = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION, $db_name);	
         }        
-        $result = Database::select('*', $TBL_EXERCICE_QUESTION_OPTION, array('where'=>array('question_id = ? AND c_id = ? ' =>array($question_id, api_get_course_int_id())), 'order'=>'id ASC'));
+        $result = Database::select('*', $TBL_EXERCICE_QUESTION_OPTION, array('where'=>array('question_id = ?' =>$question_id), 'order'=>'id ASC'));
         return $result;        
     }
     
@@ -1294,15 +1412,15 @@ abstract class Question
         $sql = "SELECT max(position) as max_position"
                ." FROM $tbl_quiz_question q INNER JOIN $tbl_quiz_rel_question r"
                ." ON q.id = r.question_id"
-               ." AND exercice_id = $quiz_id AND q.c_id = ".api_get_course_int_id()." AND r.c_id = ".api_get_course_int_id();
-        $rs_max = Database::query($sql);
+               ." AND exercice_id = $quiz_id";
+        $rs_max = Database::query($sql, __FILE__, __LINE__);
         $row_max = Database::fetch_object($rs_max);
         $max_position = $row_max->max_position +1;
    
         // Insert the new question
         $sql = "INSERT INTO $tbl_quiz_question"
-              ." (c_id, question,ponderation,position,type,level) "
-              ." VALUES(".api_get_course_int_id().", '".Database::escape_string($question_name)."',"
+              ." (question,ponderation,position,type,level) "
+              ." VALUES('".Database::escape_string($question_name)."',"
               ." $max_score , $max_position, $type, $level)";
         $rs = Database::query($sql);
         // Get the question ID
@@ -1315,10 +1433,23 @@ abstract class Question
         $max_order = $row_max_order->max_order + 1;
         // Attach questions to quiz
         $sql = "INSERT INTO $tbl_quiz_rel_question "
-              ."(c_id, question_id,exercice_id,question_order)"
-              ." VALUES(".api_get_course_int_id().", $question_id, $quiz_id, $max_order)";
+              ."(question_id,exercice_id,question_order)"
+              ." VALUES($question_id, $quiz_id, $max_order)";
         $rs = Database::query($sql);
         return $question_id;
     }
+    
+    /**
+     * return the image filename of the question type
+     *
+    */
+    public function get_type_icon_html() {
+    	$type = $this->selectType();
+    	$tabQuestionList = Question::get_types_information(); // [0]=file to include [1]=type name
+    	require_once($tabQuestionList[$type][0]);
+			eval('$img = '.$tabQuestionList[$type][1].'::$typePicture;');
+			eval('$explanation = get_lang('.$tabQuestionList[$type][1].'::$explanationLangVar);');
+			return array($img, $explanation);
+    }
 }
 endif;

+ 116 - 60
main/exercice/question_list_admin.inc.php

@@ -13,6 +13,7 @@
 *	It is included from the script admin.php
 *
 *	@author Olivier Brouckaert
+* Modified by Hubert Borderiou 21-10-2011 (Question by category)
 */
 
 // ALLOWED_TO_INCLUDE is defined in admin.php
@@ -142,65 +143,120 @@ $token = Security::get_token();
 //deletes a session when using don't know question type (ugly fix)
 unset($_SESSION['less_answer']);
  
-echo '<div id="question_list">';
-
-if ($nbrQuestions) {
-    $my_exercise = new Exercise();
-    //forces the query to the database
-    $my_exercise->read($_GET['exerciseId']);
-	$questionList=$my_exercise->selectQuestionList();    
-        
-	if (is_array($questionList)) {		
-		foreach($questionList as $id) {
-			//To avoid warning messages
-			if (!is_numeric($id)) {
-				continue;
-			}	
-			$objQuestionTmp = Question :: read($id);
-            $question_class = get_class($objQuestionTmp);
-            
-            $clone_link = '<a href="'.api_get_self().'?'.api_get_cidreq().'&clone_question='.$id.'">'.Display::return_icon('cd.gif',get_lang('Copy'), array(), 22).'</a>';            
-            $edit_link  = '<a href="'.api_get_self().'?'.api_get_cidreq().'&type='.$objQuestionTmp->selectType().'&myid=1&editQuestion='.$id.'">'.Display::return_icon('edit.png',get_lang('Modify'), array(), 22).'</a>';
-            // this variable  $show_quiz_edition comes from admin.php blocks the exercise/quiz modifications
-            if ($show_quiz_edition) {
-                 $delete_link = '<a id="delete_'.$id.'" class="opener"  href="'.api_get_self().'?'.api_get_cidreq().'&exerciseId='.$exerciseId.'&deleteQuestion='.$id.'" >'.Display::return_icon('delete.png',get_lang('Delete'), array(), 22).'</a>';
-            }
-            $clone_link  = Display::tag('div',$clone_link,  array('style'=>'float:left; padding:0px; margin:0px'));
-            $edit_link   = Display::tag('div',$edit_link,   array('style'=>'float:left; padding:0px; margin:0px'));
-            $delete_link = Display::tag('div',$delete_link, array('style'=>'float:left; padding:0px; margin:0px'));
-            $actions     = Display::tag('div',$edit_link.$clone_link.$delete_link, array('class'=>'edition','style'=>'width:100px; right:10px;     margin-top: 0px;     position: absolute;     top: 10%;'));
-
-            echo '<div id="question_id_list_'.$id.'" >';            
-                echo '<div class="header_operations">';               
-                    $move = Display::return_icon('move.png',get_lang('Move'), array('class'=>'moved', 'style'=>'margin-bottom:-0.5em;'));
-                    $level = '';
-                    if (!empty($objQuestionTmp->level)) {
-                    	$level = '('.get_lang('Difficulty').' '.$objQuestionTmp->level.')';
-                    }            
-                    $title = Security::remove_XSS($objQuestionTmp->selectTitle());
-        		    echo Display::tag('span', '<a href="#" title = "'.$title.'">'.$move.' '.cut($title, 80).' '.Display::tag('span', $level.' ['.get_lang('QualificationNumeric').': '.$objQuestionTmp->selectWeighting().']', array('style'=>"right:110px; position: absolute;padding-top: 0.3em;")).'</a>', array('style'=>''));
-                    echo $actions;
-                echo '</div>';
-            
-                echo '<div class="question-list-description-block">';
-                    echo '<p>';                        
-                        //echo get_lang($question_class.$label);
-                        echo get_lang($question_class);
-                        echo '<br />';
-                        //echo get_lang('Level').': '.$objQuestionTmp->selectLevel();
-                        echo '<br />';
-                        showQuestion($id, false, '', '',false, true);                   
-                    echo '</p>';                        
-                 echo '</div>';                 
-            echo '</div>';            
-                
-            unset($objQuestionTmp);
+// If we are in a test
+$inATest = isset($exerciseId) && $exerciseId > 0;
+if (!$inATest) {
+	echo get_lang("ChoiceQuestionType");
+}
+else {
+	echo '<div id="question_list">';
+	if ($nbrQuestions) {
+	  $my_exercise = new Exercise();
+	  //forces the query to the database
+	  $my_exercise->read($_GET['exerciseId']);
+		$questionList=$my_exercise->selectQuestionList();    
+	  // -----------------------
+	  // Style for columns
+	  // -----------------------
+	  $styleQuestion = "width:50%; float:left;";
+	  $styleType = "width:4%; float:left; padding-top:4px; text-align:center;";
+	  $styleCat = "width:22%; float:left; padding-top:8px; text-align:center;";
+	  $styleLevel = "width:6%; float:left; padding-top:8px; text-align:center;";
+	  $styleScore = "width:4%; float:left; padding-top:8px; text-align:center;";
+	  $styleAction = "width:10%; float:left; padding-top:8px;";
+	  // -------------
+	  // Title line
+	  // -------------
+	  echo "<div>";
+	  echo "<div style='font-weight:bold; width:50%; float:left; padding:10px 0px; text-align:center;'><span style='padding-left:50px;'>&nbsp;</span>".get_lang('Questions')."</div>";
+	  echo "<div style='font-weight:bold; width:4%; float:left; padding:10px 0px; text-align:center;'>".get_lang('Type')."</div>";
+	  echo "<div style='font-weight:bold; width:22%; float:left; padding:10px 0px; text-align:center;'>".get_lang('Category')."</div>";
+	  echo "<div style='font-weight:bold; width:6%; float:left; padding:10px 0px; text-align:center;'>".get_lang('Difficulty')."</div>";  
+	  echo "<div style='font-weight:bold; width:4%; float:left; padding:10px 0px; text-align:center;'>".get_lang('Score')."</div>";
+	  echo "</div>";
+	  echo "<div style='clear:both'>&nbsp;</div>";
+	  // -------------        
+		if (is_array($questionList)) {		
+			foreach($questionList as $id) {
+				//To avoid warning messages
+				if (!is_numeric($id)) {
+					continue;
+				}	
+				$objQuestionTmp = Question :: read($id);
+				$question_class = get_class($objQuestionTmp);
+				
+				$clone_link = '<a href="'.api_get_self().'?'.api_get_cidreq().'&clone_question='.$id.'">'.Display::return_icon('cd.gif',get_lang('Copy'), array(), 22).'</a>';            
+				$edit_link  = '<a href="'.api_get_self().'?'.api_get_cidreq().'&type='.$objQuestionTmp->selectType().'&myid=1&editQuestion='.$id.'">'.Display::return_icon('edit.png',get_lang('Modify'), array(), 22).'</a>';
+				// this variable  $show_quiz_edition comes from admin.php blocks the exercise/quiz modifications
+				if ($show_quiz_edition) {
+				     $delete_link = '<a id="delete_'.$id.'" class="opener"  href="'.api_get_self().'?'.api_get_cidreq().'&exerciseId='.$exerciseId.'&deleteQuestion='.$id.'" >'.Display::return_icon('delete.png',get_lang('RemoveFromTest'), array(), 22).'</a>';
+				}
+				$edit_link   = Display::tag('div',$edit_link,   array('style'=>'float:left; padding:0px; margin:0px'));
+				$clone_link  = Display::tag('div',$clone_link,  array('style'=>'float:left; padding:0px; margin:0px'));
+				$delete_link = Display::tag('div',$delete_link, array('style'=>'float:left; padding:0px; margin:0px'));
+				$actions     = Display::tag('div',$edit_link.$clone_link.$delete_link, array('class'=>'edition','style'=>'width:100px; right:10px;     margin-top: 0px;     position: absolute;     top: 10%;'));
+	
+	      $title = Security::remove_XSS($objQuestionTmp->selectTitle());
+	      $move = Display::return_icon('move.png',get_lang('Move'), array('class'=>'moved', 'style'=>'margin-bottom:-0.5em;'));
+	      // ---------------------
+	      // Question name
+	      // ---------------------
+				$questionName = Display::tag('div', '<a href="#" title = "'.$title.'">'.$move.' '.cut($title, 60).'</a>', array('style'=>$styleQuestion));
+				// ---------------------
+				// Question type
+				// ---------------------
+				$tabQuestionList = Question::get_types_information();
+				list($typeImg, $typeExpl) = $objQuestionTmp->get_type_icon_html();
+				$questionType = Display::tag('div', Display::return_icon($typeImg, $typeExpl, array(), 32), array('style'=>$styleType));
+				// ---------------------
+				// Question category 
+				// ---------------------
+				$txtQuestionCat = Security::remove_XSS(Testcategory::getCategoryNameForQuestion($objQuestionTmp->id));
+				if (empty($txtQuestionCat)) {
+					$txtQuestionCat = "-";
+				}
+				$questionCategory = Display::tag('div', '<a href="#" style="padding:0px; margin:0px;" title="'.$txtQuestionCat.'">'.cut($txtQuestionCat, 55).'</a>', array('style'=>$styleCat));
+				// ---------------------
+				// Question level
+				// ---------------------
+				$txtQuestionLevel = $objQuestionTmp->level;
+	      if (empty($objQuestionTmp->level)) {
+	      	$txtQuestionLevel = '-';
+	      }
+	      $questionLevel = Display::tag('div', $txtQuestionLevel, array('style'=>$styleLevel));
+	      // ---------------------
+	      // Question score
+	      // ---------------------
+	      $questionScore = Display::tag('div', $objQuestionTmp->selectWeighting(), array('style'=>$styleScore));
+	      // ---------------------
+	      echo '<div id="question_id_list_'.$id.'" >';            
+		      echo '<div class="header_operations">';               
+		        echo $questionName;
+		        echo $questionType;
+		        echo $questionCategory;
+		        echo $questionLevel;
+		        echo $questionScore;
+			      echo $actions;
+		      echo '</div>';
+		      echo '<div class="question-list-description-block">';
+			      echo '<p>';                        
+			      //echo get_lang($question_class.$label);
+			      echo get_lang($question_class);
+			      echo '<br />';
+			      //echo get_lang('Level').': '.$objQuestionTmp->selectLevel();
+			      echo '<br />';
+			      showQuestion($id, false, '', '',false, true);                   
+			      echo '</p>';                        
+		      echo '</div>';                 
+	      echo '</div>';            
+	      unset($objQuestionTmp);
+			}
+	        echo '</div>';
 		}
-        echo '</div>';
 	}
-}
-if(!$nbrQuestions) {	
-  	echo Display::display_warning_message(get_lang('NoQuestion'));
-}
-
-echo '</div>';
+	if(!$nbrQuestions) {	
+	  	echo Display::display_warning_message(get_lang('NoQuestion'));
+	}
+	
+	echo '</div>';
+}

+ 422 - 305
main/exercice/question_pool.php

@@ -8,6 +8,7 @@
 *	@package chamilo.exercise
 * 	@author Olivier Brouckaert
 *   @author Julio Montoya adding support to query all questions from all session, courses, exercises  
+*   Modify by hubert borderiou 2011-10-21 Question's category
 */
 /**
  * Code
@@ -23,7 +24,7 @@ require_once '../inc/global.inc.php';
 
 $this_section = SECTION_COURSES;
 
-$is_allowedToEdit = api_is_allowed_to_edit(null,true);
+$is_allowedToEdit=api_is_allowed_to_edit(null,true);
 
 if (empty($delete)) {
     $delete = intval($_GET['delete']);
@@ -34,12 +35,14 @@ if ( empty ( $recup ) ) {
 if ( empty ( $fromExercise ) ) {
     $fromExercise = intval($_REQUEST['fromExercise']);
 }
-
-$exerciseId = null;
 if(isset($_GET['exerciseId'])){
 	$exerciseId = intval($_GET['exerciseId']);
 }
 
+if (isset($_GET['courseCategoryId'])) {
+	$courseCategoryId = intval($_GET['courseCategoryId']);
+}
+
 $exerciseLevel = -1;
 if(isset($_REQUEST['exerciseLevel'])){
 	$exerciseLevel = intval($_REQUEST['exerciseLevel']);
@@ -56,17 +59,15 @@ if(!empty($_GET['copy_question'])){
 	$copy_question = intval($_GET['copy_question']);
 }
 
-//only that type of question
-if(!empty($_GET['type'])){
-	$type = intval($_GET['type']);
-}
+$session_id      			= intval($_GET['session_id']);
+$selected_course 			= intval($_GET['selected_course']);
+$course_id_changed		= intval($_GET['course_id_changed']);	// save the id of the previous course selected by user to reset menu if we detect that user change course hub 13-10-2011
+$exercice_id_changed 	= intval($_GET['exercice_id_changed']); // save the id of the previous exercice selected by user to reset menu if we detect that user change course hub 13-10-2011
 
-$session_id      = intval($_GET['session_id']);
-$selected_course = intval($_GET['selected_course']);
-
-
-// maximum number of questions on a same page
-$limitQuestPage = 20;
+// by default when we go to the page for the first time, we select the current course
+if (!isset($_GET['selected_course']) && !isset($_GET['exerciseId'])) {
+	$selected_course = api_get_course_int_id();
+}
 
 // document path
 $documentPath = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document';
@@ -82,65 +83,56 @@ $nameTools = get_lang('QuestionPool');
 $interbreadcrumb[] = array("url" => "exercice.php","name" => get_lang('Exercices'));
 $interbreadcrumb[] = array("url" => "admin.php?exerciseId=".$objExercise->id, "name" => $objExercise->name);
     
+$displayMessage = "";	// messag to be displayed if actions succesfull
 if ($is_allowedToEdit) {
-	
 	//Duplicating a Question
-    
 	if (!isset($_POST['recup']) && $copy_question != 0 && isset($fromExercise)) {
-        $origin_course_id   = intval($_GET['course_id']);
-        $origin_course_info = api_get_course_info_by_id($origin_course_id);
-        $current_course     = api_get_course_info();     
-        $old_question_id    = $copy_question;       
-        
-        //Reading the source question
+    $origin_course_id   = intval($_GET['course_id']);
+    $origin_course_info = api_get_course_info_by_id($origin_course_id);
+    $current_course     = api_get_course_info();
+    $old_question_id    = $copy_question;       
+    //Reading the source question
 		$old_question_obj = Question::read($old_question_id, $origin_course_id);
 		if ($old_question_obj) {
 			$old_question_obj->updateTitle($old_question_obj->selectTitle().' - '.get_lang('Copy'));     
-	        
-	        //Duplicating the source question, in the current course
+      //Duplicating the source question, in the current course
 			$new_id = $old_question_obj->duplicate($current_course);
-			
-	        //Reading new question
+      //Reading new question
 			$new_question_obj = Question::read($new_id);
-						
 			$new_question_obj->addToList($fromExercise);
-	        			
-	        //Reading Answers obj of the current course 
+      //Reading Answers obj of the current course 
 			$new_answer_obj = new Answer($old_question_id, $origin_course_id);
 			$new_answer_obj->read();
-	        
-	        //Duplicating the Answers in the current course
+      //Duplicating the Answers in the current course
 			$new_answer_obj->duplicate($new_id, $current_course);		
-			
 			// destruction of the Question object
 			unset($new_question_obj);
 			unset($old_question_obj);
-	
-	        if (!$objExcercise instanceOf Exercise) {
-	        	$objExercise = new Exercise();
-	            $objExercise->read($fromExercise);
-	        }
+      if (!$objExcercise instanceOf Exercise) {
+      	$objExercise = new Exercise();
+          $objExercise->read($fromExercise);
+      }
 			api_session_register('objExercise');
 		}
-		header("Location: admin.php?".api_get_cidreq()."&exerciseId=$fromExercise");
-		exit();	
+		$displayMessage = get_lang('ItemAdded');
+//		header("Location: admin.php?".api_get_cidreq()."&exerciseId=$fromExercise");
+//		exit();	
 	}
-	
-	// deletes a question from the data base and all exercises
+	// deletes a question from the database and all exercises
 	if ($delete) {
 		// construction of the Question object
 		// if the question exists
-		if($objQuestionTmp = Question::read($delete)) {
+		if($objQuestionTmp = Question::read($delete))
+		{
 			// deletes the question from all exercises
 			$objQuestionTmp->delete();
 		}
 		// destruction of the Question object
 		unset($objQuestionTmp);
-	} elseif($recup && $fromExercise) {
-		/*
+	} 
+	elseif($recup && $fromExercise) {
 		// gets an existing question and copies it into a new exercise
 		$objQuestionTmp = Question :: read($recup);
-		
 		// if the question exists
 		if($objQuestionTmp = Question :: read($recup)) {
 			// adds the exercise ID represented by $fromExercise into the list of exercises for the current question
@@ -156,9 +148,11 @@ if ($is_allowedToEdit) {
 		// adds the question ID represented by $recup into the list of questions for the current exercise
 		$objExercise->addToList($recup);
 		api_session_register('objExercise');
-		header("Location: admin.php?".api_get_cidreq()."&exerciseId=$fromExercise");
-		exit();*/
-	} else if( isset($_POST['recup']) && is_array($_POST['recup']) && $fromExercise) {
+
+//		header("Location: admin.php?".api_get_cidreq()."&exerciseId=$fromExercise");
+//		exit();
+	} 
+	else if( isset($_POST['recup']) && is_array($_POST['recup']) && $fromExercise) {
 		$list_recup 		= $_POST['recup'];
 		
 		foreach ($list_recup as $course_id => $question_data) {
@@ -216,8 +210,8 @@ if ($is_allowedToEdit) {
 			}
 		}
 		api_session_register('objExercise');
-		header("Location: admin.php?".api_get_cidreq()."&exerciseId=$fromExercise");
-		exit();
+//		header("Location: admin.php?".api_get_cidreq()."&exerciseId=$fromExercise");
+//		exit();
 	}
 }
 
@@ -234,25 +228,55 @@ if (!$is_allowedToEdit) {
     api_not_allowed(true);
 }
 
-$htmlHeadXtra[] = ' <script type="text/javascript">                 
+$confirmYourChoice = addslashes(api_htmlentities(get_lang('ConfirmYourChoice'),ENT_QUOTES,$charset));
+
+$htmlHeadXtra[] = " 
+<script type='text/javascript'>          
 	function submit_form(obj) {            
 		document.question_pool.submit();
 	}		
-	</script>';
+	
+	function mark_course_id_changed() { 
+		$('#course_id_changed').val('1');
+	}
+	
+	function mark_exercice_id_changed() { 
+		$('#exercice_id_changed').val('1');
+	}
+	
+	function confirm_your_choice() {
+		return confirm('$confirmYourChoice');
+	}
+</script>
+";
+
 Display::display_header($nameTools,'Exercise');
 
 // Menu 
 echo '<div class="actions">';
-if (isset($type)) {
-	$url = api_get_self().'?type=1';
-} else {
-	$url = api_get_self();
-}
-echo '<a href="admin.php?'.api_get_cidreq().'&exerciseId='.$fromExercise.'">'.Display::return_icon('back.png', get_lang('GoBackToQuestionList'),'','32').'</a>';
+	if (isset($type)) {
+		$url = api_get_self().'?type=1';
+	} else {
+		$url = api_get_self();
+	}
+	if (isset($fromExercise) && $fromExercise > 0) {
+		echo '<a href="admin.php?'.api_get_cidreq().'&exerciseId='.$fromExercise.'">'.Display::return_icon('back.png', get_lang('GoBackToQuestionList'),'','32').'</a>';
+		$titleAdd = get_lang('addQuestionToTest');
+	}
+	else {
+		echo '<a href="exercice.php?'.api_get_cidReq().'">'.Display::return_icon('back.png', get_lang('BackToExercisesList'),'','32').'</a>';
+		echo "<a href='admin.php?exerciceId=0'>".Display::return_icon('add_question.gif', get_lang('NewQu'), '', 32)."</a>";
+		$titleAdd = get_lang('manageAllQuestions');
+	}
 echo '</div>';
 
+if ($displayMessage != "") {
+	Display::display_confirmation_message($displayMessage);
+	$displayMessage = "";
+}
+
 //Title
-echo '<h2>'.$nameTools.'</h2>';
+echo '<h2>'.$nameTools.' - '.$titleAdd.'</h2>';
 
 //Form
 echo '<form name="question_pool" method="GET" action="'.$url.'">';	 
@@ -261,70 +285,107 @@ if (isset($type)) {
 }    
 echo '<input type="hidden" name="fromExercise" value="'.$fromExercise.'">';
 
-//Session list  
+// ----------------------------------------------------
+// Session list, if sessions are used.
+// ----------------------------------------------------
 $session_list = SessionManager::get_sessions_by_coach(api_get_user_id());
-
+// hub 13-10-2011
+$tabAttrParam = array('class'=>'chzn-select', 'onchange'=>'submit_form(this)');	// when sessions are used
+$labelFormRow = get_lang('Session');
+if (api_get_setting('use_session_mode') == 'false') {
+	$tabAttrParam = array('style'=>'visibility:hidden', 'onchange'=>'submit_form(this)');
+	$labelFormRow = "";
+}
 $session_select_list = array();
 foreach($session_list as $item) {
-    $session_select_list[$item['id']] = $item['name'];
+	$session_select_list[$item['id']] = $item['name'];
 }
-$select_session_html =  Display::select('session_id', $session_select_list, $session_id, array('class'=>'chzn-select','onchange'=>'submit_form(this);'));
-echo Display::form_row(get_lang('Session'), $select_session_html);
-
-//Course list
-
-if (!empty($session_id) && $session_id != '-1') {	
-    $course_list = SessionManager::get_course_list_by_session_id($session_id);
-} else {
-    $course_list = CourseManager::get_course_list_of_user_as_course_admin(api_get_user_id());        
+$select_session_html =  Display::select('session_id', $session_select_list, $session_id, $tabAttrParam);	// hub 13-10-2011
+echo Display::form_row($labelFormRow, $select_session_html);	// hub 13-10-2011
+
+// -----------------------------------------------------------------------------
+// Course list, get course list of session, or for course where user is admin
+// -----------------------------------------------------------------------------
+if (!empty($session_id) && $session_id != '-1') {
+	$course_list = SessionManager::get_course_list_by_session_id($session_id);
+} else {        
+	$course_list = CourseManager::get_course_list_of_user_as_course_admin(api_get_user_id());        
 }    
-
 $course_select_list = array();
 foreach ($course_list as $item) {
-	$course_select_list[$item['id']] = $item['title'];
-}    
+	$course_select_list[$item['id']] = "";
+	if ($item['id'] == api_get_course_int_id()) {
+		$course_select_list[$item['id']] = ">&nbsp;&nbsp;&nbsp;&nbsp;";
+	}
+	$course_select_list[$item['id']] .= $item['title'];
+}
 
-$select_course_html =  Display::select('selected_course', $course_select_list, $selected_course, array('class'=>'chzn-select','onchange'=>'submit_form(this);'));
+$select_course_html =  Display::select('selected_course', $course_select_list, $selected_course, array('class'=>'chzn-select','onchange'=>'mark_course_id_changed(); submit_form(this);'));
 echo Display::form_row(get_lang('Course'), $select_course_html);    
-
+$db_name = "";
 if (empty($selected_course) || $selected_course == '-1') {
-    $course_info = api_get_course_info();    
-} else {        
-	$course_info = CourseManager::get_course_information_by_id($selected_course);
+    $course_info = api_get_course_info();
+    reset_menu_exo_lvl_type();    // no course selected, reset menu test / difficulté / type de reponse // hub 13-10-2011
+} 
+else {   
+	$course_info = CourseManager::get_course_information_by_id($selected_course);                
+}
+// If course has changed, reset the menu default
+if ($course_id_changed) {
+	reset_menu_exo_lvl_type();
 }
 $course_id = $course_info['real_id'];
-
 //Redefining table calls
 $TBL_EXERCICE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
 $TBL_EXERCICES         = Database::get_course_table(TABLE_QUIZ_TEST);
 $TBL_QUESTIONS         = Database::get_course_table(TABLE_QUIZ_QUESTION);
 $TBL_REPONSES          = Database::get_course_table(TABLE_QUIZ_ANSWER);
+$TBL_CATEGORY							= Database::get_course_table(TABLE_QUIZ_QUESTION_CATEGORY);		// hub 13-10-2011
+$TBL_COURSE_REL_CATEGORY	= Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY);  // hub 13-10-2011
+
 
-$exercise_list         = get_all_exercises($course_info, $session_id);
+// ---------------------------------------------
+// Get course categories for the selected course
+// ---------------------------------------------
 
+// get category list for the course $selected_course
+$tabCatList = Testcategory::getCategoriesIdAndName($selected_course);
+$selectCourseCateogry = Display::select('courseCategoryId', $tabCatList, $courseCategoryId, array('class'=>'chzn-select','onchange'=>'submit_form(this);'), false);
+echo Display::form_row(get_lang("QuestionCategory"), $selectCourseCateogry);
 
+// ---------------------------------------------
+// Get exercice list for this course
+// ---------------------------------------------
+$exercise_list         = get_all_exercises_for_course_id($course_info, $session_id, $selected_course);
 //Exercise List
 $my_exercise_list = array();
 $my_exercise_list['0']  = get_lang('AllExercises');
 $my_exercise_list['-1'] = get_lang('OrphanQuestions'); 
-    
 if (is_array($exercise_list)) {
-    foreach($exercise_list as $row) {        
-        if ($row['id'] !=  $fromExercise) {       
-            $my_exercise_list[$row['id']] = $row['title'];
-        }
-    }
+  foreach($exercise_list as $row) {       
+		$my_exercise_list[$row['id']] = "";
+    if ($row['id'] ==  $fromExercise && $selected_course == api_get_course_int_id()) {       
+    	$my_exercise_list[$row['id']] = ">&nbsp;&nbsp;&nbsp;&nbsp;";	// hub 13-10-2011
+    }    
+    $my_exercise_list[$row['id']] .= $row['title'];
+  }
 }    
 
-$select_exercise_html =  Display::select('exerciseId', $my_exercise_list, $exerciseId, array('class'=>'chzn-select','onchange'=>'submit_form(this);'), false);
+if ($exercice_id_changed == 1) {
+	reset_menu_lvl_type();
+}
+$select_exercise_html =  Display::select('exerciseId', $my_exercise_list, $exerciseId, array('class'=>'chzn-select','onchange'=>'mark_exercice_id_changed(); submit_form(this);'), false);
 echo Display::form_row(get_lang('Exercise'), $select_exercise_html);
 
-//Difficulty list (only from 0 to 5)                
+// ---------------------------------------------
+// Difficulty list (only from 0 to 5)                
+// ---------------------------------------------
 $select_difficulty_html = Display::select('exerciseLevel', array(-1 => get_lang('All'), 0=>0, 1=>1, 2=>2, 3=>3, 4=>4, 5=>5), $exerciseLevel, array('class'=>'chzn-select', 'onchange'=>'submit_form(this);'), false);
 echo Display::form_row(get_lang('Difficulty'), $select_difficulty_html);
 
-//Answer type
-
+// ---------------------------------------------
+// Answer type
+// ---------------------------------------------
 $question_list = Question::get_types_information();
 $new_question_list = array();
 $new_question_list['-1']  = get_lang('All');
@@ -348,267 +409,323 @@ $select_answer_html = Display::select('answerType', $new_question_list, $answerT
 echo Display::form_row(get_lang('AnswerType'), $select_answer_html);
 $button = '<button class="save" type="submit" name="name" value="'.get_lang('Filter').'">'.get_lang('Filter').'</button>'; 
 echo Display::form_row('', $button);
+echo "<input type='hidden' id='course_id_changed' name='course_id_changed' value='0' />"; // hub 13-10-2011
+echo "<input type='hidden' id='exercice_id_changed' name='exercice_id_changed' value='0' />"; // hub 13-10-2011
 ?>
 </form>
 <div class="clear"></div>
 <form method="post" action="<?php echo $url.'?'.api_get_cidreq().'&fromExercise='.$fromExercise; ?>" >
 <?php
 echo '<input type="hidden" name="course_id" value="'.$selected_course.'">';
-echo '<table class="data_table">';
-$from = $page * $limitQuestPage;
-
-$show_pagination = true;
 
+// --------------------------------------------------------
 // if we have selected an exercise in the list-box 'Filter'
+// --------------------------------------------------------
 if ($exerciseId > 0) {
-	//Specific exercise
 	$where = '';
-	if (isset($type) && $type==1) {
-		$where = ' type = 1 AND ';
+	$from = '';
+	if (isset($courseCategoryId) && $courseCategoryId > 0) {
+		$from = ", $TBL_COURSE_REL_CATEGORY crc ";
+		$where .= " AND crc.c_id=$selected_course AND crc.question_id=qu.id AND crc.category_id=$courseCategoryId";
 	}
 	if (isset($exerciseLevel) && $exerciseLevel != -1) {
-		$where .= ' level='.$exerciseLevel.' AND ';
+		$where .= ' AND level='.$exerciseLevel;
 	}
 	if (isset($answerType) && $answerType != -1) {
-		$where .= ' type='.$answerType.' AND ';
-	}
-	$sql = "SELECT id, question, type, level
-			FROM $TBL_EXERCICE_QUESTION eq, $TBL_QUESTIONS q
-		  	WHERE $where question_id=id AND exercice_id='".$exerciseId."' AND eq.c_id = $course_id AND q.c_id = $course_id
-			ORDER BY question_order";            
-    $result=Database::query($sql);
-    while($row = Database::fetch_array($result, 'ASSOC')) {
-    	$main_question_list[] = $row;
-    }    
-} elseif($exerciseId == -1) {
-	//Orphan	
-	$type_where= '';
-	if (isset($type) && $type==1) {
-		$type_where = ' AND questions.type = 1 ';
+		$where .= ' AND type='.$answerType;
 	}
+	$sql = "SELECT DISTINCT id,question,type,level FROM $TBL_EXERCICE_QUESTION qt,$TBL_QUESTIONS qu $from WHERE qt.question_id=qu.id AND qt.exercice_id=$exerciseId AND qt.c_id=$selected_course AND qu.c_id=$selected_course $where ORDER BY question_order";
+  $result=Database::query($sql);
+  while($row = Database::fetch_array($result, 'ASSOC')) {
+  	$main_question_list[] = $row;
+  }    
+} 
+elseif ($exerciseId == -1) {
+	// ---------------------------------------------------------------------------
+	// if we have selected the option 'Orphan questions' in the list-box 'Filter'
+	// ---------------------------------------------------------------------------
 	$level_where = '';
+	$from = '';
+	if (isset($courseCategoryId) && $courseCategoryId > 0) {
+		$from = ", $TBL_COURSE_REL_CATEGORY crc ";
+		$level_where .= " AND crc.c_id=$selected_course AND crc.question_id=qu.id AND crc.category_id=$courseCategoryId";
+	}	
 	if (isset($exerciseLevel) && $exerciseLevel!= -1 ) {
-		$level_where = ' level='.$exerciseLevel.' AND ';
+		$level_where = ' AND level='.$exerciseLevel;
 	}
 	$answer_where = '';
 	if (isset($answerType) && $answerType != -1 ) {
-		$answer_where = ' questions.type='.$answerType.' AND ';
+		$answer_where = ' AND type='.$answerType;
 	}
-	$sql = 'SELECT questions.id, questions.question, questions.type, quizz_questions.exercice_id , level, session_id
-			FROM '.$TBL_QUESTIONS.' as questions LEFT JOIN '.$TBL_EXERCICE_QUESTION.' as quizz_questions
-			ON questions.id=quizz_questions.question_id LEFT JOIN '.$TBL_EXERCICES.' as exercices
-			ON exercice_id=exercices.id
-			WHERE '.$answer_where.' '.$level_where.' (quizz_questions.exercice_id IS NULL OR exercices.active = -1 )  '.$type_where.' AND 
-					questions.c_id = '.$course_id.'
-							
-			LIMIT '.$from.', '.($limitQuestPage + 1);
-    $result = Database::query($sql);
-    
-    while($row = Database::fetch_array($result, 'ASSOC')) {
-        $main_question_list[] = $row;
-    }
-} else {
-	//All tests
-	$show_pagination = false;
-	
+	$sql = "SELECT DISTINCT * FROM `chamilo19_main`.`c_quiz_question` AS qu $from WHERE qu.c_id=$selected_course AND qu.id NOT IN (SELECT question_id FROM `chamilo19_main`.`c_quiz_rel_question` WHERE c_id=$selected_course ) $level_where $answer_where";
+  $result = Database::query($sql);
+  while($row = Database::fetch_array($result, 'ASSOC')) {
+      $main_question_list[] = $row;
+  }
+} 
+else {
+	// ---------------------------------
+	// All tests for selected course 
+	// ---------------------------------
 	// if we have not selected any option in the list-box 'Filter'
 	$filter = '';
-	if (isset($type) && $type==1){
-		$filter  .= ' AND qu.type = 1 ';
-	}
+	$from = '';
+	if (isset($courseCategoryId) && $courseCategoryId > 0) {
+		$from = ", $TBL_COURSE_REL_CATEGORY crc ";
+		$filter .= " AND crc.c_id=$selected_course AND crc.question_id=qu.id AND crc.category_id=$courseCategoryId";
+	}		
 	if (isset($exerciseLevel) && $exerciseLevel != -1) {
 		$filter .= ' AND level='.$exerciseLevel.' ';
 	}
 	if (isset($answerType) && $answerType != -1) {
 		$filter .= ' AND qu.type='.$answerType.' ';
-	}	
-    if ($objExercise->feedbacktype != EXERCISE_FEEDBACK_TYPE_DIRECT) {
-        $filter .= ' AND qu.type <> '.HOT_SPOT_DELINEATION.' ';
-    }
-    $new_limit_page = $limitQuestPage + 1;	
-	
-    if (!empty($session_id) && $session_id != '-1') {
-        $main_question_list = array();
-        if (!empty($course_list))
-        foreach ($course_list as $course_item) {    
-            if (!empty($selected_course) && $selected_course != '-1') {
-                if ($selected_course != $course_item['id']) {                
+	}
+//	// why these lines ?
+//  if ($objExercise->feedbacktype != EXERCISE_FEEDBACK_TYPE_DIRECT) {
+//      $filter .= ' AND qu.type <> '.HOT_SPOT_DELINEATION.' ';
+//  }
+//  // fwhy
+  // --------------------
+  // if in session
+  // --------------------
+  if (!empty($session_id) && $session_id != '-1') {
+    $main_question_list = array();
+    if (!empty($course_list))
+    foreach ($course_list as $course_item) {    
+      if (!empty($selected_course) && $selected_course != '-1') {
+          if ($selected_course != $course_item['id']) {                
+          	continue;
+          }
+      }        
+      $exercise_list = get_all_exercises($course_item, $session_id);
+      if (!empty($exercise_list)) {        
+        foreach ($exercise_list as $exercise) {                    
+          $my_exercise = new Exercise($course_item['id']);
+          $my_exercise->read($exercise['id']);
+          if (!empty($my_exercise)) {
+            if (!empty($my_exercise->questionList)) {                            
+              foreach ($my_exercise->questionList as $question_id) {  
+              	$question_obj = Question::read($question_id, $course_item['id']);
+                if ($exerciseLevel != '-1')
+                if ($exerciseLevel != $question_obj->level) {
                 	continue;
                 }
-            }        
-            $exercise_list = get_all_exercises($course_item, $session_id);           
-
-            if (!empty($exercise_list)) {        
-                foreach ($exercise_list as $exercise) {                    
-                    $my_exercise = new Exercise($course_item['id']);
-                    $my_exercise->read($exercise['id']);
-                    
-            
-                    if (!empty($my_exercise)) {
-                    	
-                        if (!empty($my_exercise->questionList)) {                            
-                            foreach ($my_exercise->questionList as $question_id) {  
-                                                              
-                            	$question_obj = Question::read($question_id, $course_item['id']);
-                                if ($exerciseLevel != '-1')
-                                if ($exerciseLevel != $question_obj->level) {
-                                	continue;
-                                }
-                                
-                                if ($answerType != '-1')
-                                if ($answerType != $question_obj->type) {
-                                	continue;
-                                }
-                                if ($objExercise->feedbacktype != EXERCISE_FEEDBACK_TYPE_DIRECT) {
-                                     if ($question_obj->type == HOT_SPOT_DELINEATION)  {
-                                         continue;
-                                     }
-                                }                    
-                                $question_row = array(	'id'			=> $question_obj->id, 
-                                						'question'		=> $question_obj->question, 
-                                						'type'			=> $question_obj->type, 
-                                						'level'			=> $question_obj->level, 
-                                						'exercise_id'	=> $exercise['id'],
-                                						'course_id'		=> $course_item['id'],
-                                );
-                                                            
-                                $main_question_list[]    = $question_row;                        
-                            }
-                        }
-                    }                    
+                if ($answerType != '-1')
+                if ($answerType != $question_obj->type) {
+                	continue;
                 }
-            }           	
-        }      
-    } else {
-        //By default
-    	$sql = "SELECT qu.id, question, qu.type, level, q.session_id 
-    			FROM $TBL_QUESTIONS as qu, $TBL_EXERCICE_QUESTION as qt, $TBL_EXERCICES as q
-              	WHERE 	qu.c_id = $course_id AND 
-              			qu.c_id = $course_id AND
-              			q.id=qt.exercice_id AND 
-    					qu.id=qt.question_id AND 
-    					qt.exercice_id <> ".$fromExercise." $filter 
-    			ORDER BY session_id ASC 
-    			LIMIT $from, $new_limit_page";
-    	$result = Database::query($sql);
-    	
-    	while($row = Database::fetch_array($result, 'ASSOC')) {
-    		$main_question_list[] = $row;
-    	}
-    }
+                // hub 23-10-2011
+                if ($courseCategoryId > 0 && Testcategory::getCategoryForQuestion($question_obj->id, $selected_course)) {
+                	continue;
+                }
+                if ($objExercise->feedbacktype != EXERCISE_FEEDBACK_TYPE_DIRECT) {
+                   if ($question_obj->type == HOT_SPOT_DELINEATION)  {
+                     continue;
+                   }
+                }                    
+                $question_row = array(	'id'			=> $question_obj->id, 
+                						'question'		=> $question_obj->question, 
+                						'type'			=> $question_obj->type, 
+                						'level'			=> $question_obj->level, 
+                						'exercise_id'	=> $exercise['id'],
+                						'course_id'		=> $course_item['id'],
+                );
+                $main_question_list[]    = $question_row;                        
+              }
+            }
+          }                    
+        }
+      }           	
+    }      
+  } 
+  else {
+  	// ------------------------------------------------------------
+    // All tests for the course selected, not in session
+    // ------------------------------------------------------------
+  	$sql = "SELECT DISTINCT qu.id, question, qu.type, level, q.session_id FROM $TBL_QUESTIONS as qu, $TBL_EXERCICE_QUESTION as qt, $TBL_EXERCICES as q $from WHERE qu.c_id=$selected_course AND qt.c_id=$selected_course AND q.c_id=$selected_course AND qu.id = qt.question_id AND q.id = qt.exercice_id $filter ORDER BY session_id ASC";
+  	$result = Database::query($sql);
+  	while($row = Database::fetch_array($result, 'ASSOC')) {
+  		$main_question_list[] = $row;
+  	}
+  }
 	// forces the value to 0
 	$exerciseId=0;
 }
+
 $nbrQuestions = count($main_question_list);
-if ($show_pagination) {
-	echo '<tr>',
-	  '<td colspan="',($fromExercise?4:4),'">',
-		'<table border="0" cellpadding="0" cellspacing="0" width="100%">',
-		'<tr><td align="right">';
-	
-	if(!empty($page)) {	
-		echo '<a href="',api_get_self(),'?',api_get_cidreq(),'&exerciseId=',$exerciseId,'&fromExercise=',$fromExercise,'&page=',($page-1),'&session_id='.$session_id.'&selected_course='.$selected_course.'&answerType=',$answerType,'&exerciseLevel='.$exerciseLevel.'">';
-		echo Display::return_icon('action_prev.png');
-		echo '&nbsp;';
-		
-	} elseif($nbrQuestions > $limitQuestPage) {
-		echo Display::return_icon('action_prev_na.png');
-		echo '&nbsp;';
+// ------------------------------------------------
+// build the line of the array to display questions
+// Actions are different if you launch the question_pool page
+// They are different too if you have displayed questions from your course
+// Or from another course you are the admin(or session admin)
+// from a test or not
+/*
++--------------------------------------------+--------------------------------------------+
+|   NOT IN A TEST                            |         IN A TEST                          |
++----------------------+---------------------+---------------------+----------------------+
+|IN THE COURSE (*)  "x | NOT IN THE COURSE o | IN THE COURSE    +  | NOT IN THE COURSE  o |
++----------------------+---------------------+---------------------+----------------------+
+|Edit the question     | Do nothing          | Add question to test|Clone question in test|
+|Delete the question   |                     |                     |                      |
+|(true delete)         |                     |                     |                      |
++----------------------+---------------------+---------------------+----------------------+
+(*) this is the only way to delete or modify orphan questions
+*/
+// ----------------------------------------------------------------------------------------
+if ($fromExercise <= 0) { // NOT IN A TEST - IN THE COURSE
+	if ($selected_course == api_get_course_int_id()) {
+		$actionLabel = get_lang('Action');
+		$actionIcon1 = "edit";
+		$actionIcon2 = "delete";
+		$questionTagA = 1;	// we are in the course, question title can be a link to the question edit page
 	}
-	
-	if($nbrQuestions > $limitQuestPage) {
-		echo '<a href="',api_get_self(),'?',api_get_cidreq(),'&exerciseId=',$exerciseId,'&fromExercise=',$fromExercise,'&page=',($page+1),'&session_id='.$session_id.'&selected_course='.$selected_course.'&answerType=',$answerType,'&exerciseLevel='.$exerciseLevel.'">';
-		echo Display::return_icon('action_next.png');
-		echo '</a>';
-		
-	} elseif($page) {
-	   	echo Display::return_icon('action_next_na.png');
-	   echo '&nbsp;';
+	else { // NOT IN A TEST - NOT IN THE COURSE
+		$actionLabel = get_lang('Reuse');
+		$actionIcon1 = get_lang('mustBeInATest');
+		$actionIcon2 = "";
+		$questionTagA = 0;	// we are not in  this course, to messy if we link to the question in another course
 	}
-	echo '</td>
-		</tr>
-		</table>
-	  </td>
-	</tr>';
 }
-echo '<tr>';
-
-if (!empty($fromExercise)) {
-	if (api_get_session_id() == 0 ){
-    	echo '<th width="4%"> </th>';
+else { // IN A TEST - IN THE COURSE
+	if ($selected_course == api_get_course_int_id()) {
+		$actionLabel = get_lang('Reuse');
+		$actionIcon1 = "add";
+		$actionIcon2 = "";
+		$questionTagA = 1;
 	}
-    echo '<th>',get_lang('Question'),'</th>',
-        '<th>',get_lang('Difficulty'),'</th>',
-        '<th>',get_lang('Reuse'),'</th>';
-} else {
-    echo '<td width="60%" align="center">',get_lang('Question'),'</td>',
-        '<td width="20%" align="center">',get_lang('Modify'),'</td>',
-        '<td width="16%" align="center">',get_lang('Delete'),'</td>';
-}
-echo '</tr>';
-$i=1;
-
-$session_id  = api_get_session_id();
-if (!empty($main_question_list))
-foreach ($main_question_list as $row) {
-	$my_course_id = 0;
-	if (isset($row['course_id'])) {
-		$my_course_id = $row['course_id'];
+	else { // IN A TEST - NOT IN THE COURSE
+		$actionLabel = get_lang('Reuse');
+		$actionIcon1 = "clone";
+		$actionIcon2 = "";
+		$questionTagA = 0;
 	}
-	
+}
+// -------------------
+// display table
+// -------------------
+$header = array();
+$header[] = array(get_lang('Question'), false, array("style"=>"text-align:center"));
+$header[] = array(get_lang('Type'), false, array("style"=>"text-align:center"), array("style"=>"text-align:center"));
+$header[] = array(get_lang('QuestionCategory'), false, array("style"=>"text-align:center"), array("style"=>"text-align:center"));
+$header[] = array(get_lang('Difficulty'), false, array("style"=>"text-align:center"), array("style"=>"text-align:center"));
+$header[] = array($actionLabel, false, array("style"=>"text-align:center"), array("style"=>"text-align:center"));
+$data = array();
+foreach ($main_question_list as $tabQuestion) {
+	$row = array();
+	$row[] = get_a_tag_for_question($questionTagA, $fromExercise, $tabQuestion['id'], $tabQuestion['type'], $tabQuestion['question']);
+	$row[] = get_question_type_for_question($selected_course, $tabQuestion['id']);
+	$row[] = get_question_categorie_for_question($selected_course, $tabQuestion['id']);
+	$row[] = $tabQuestion['level'];
+	$row[] = get_action_icon_for_question($actionIcon1, $fromExercise, $tabQuestion['id'], $tabQuestion['type'], $tabQuestion['question'], $selected_course, $courseCategoryId, $exerciseId, $exerciseLevel, $answerType, $session_id)."&nbsp;".get_action_icon_for_question($actionIcon2, $fromExercise, $tabQuestion['id'], $tabQuestion['type'], $tabQuestion['question'], $selected_course, $courseCategoryId, $exercice_id, $exerciseLevel, $answerType, $session_id);
+	$data[] = $row;
+}
+Display :: display_sortable_table($header, $data, array(), array('per_page_default'=>999,'per_page'=>999,'page_nr'=>1));
 
-	// if we come from the exercise administration to get a question,
-    // don't show the questions already used by that exercise
+if (!$nbrQuestions) {
+	echo get_lang('NoQuestion');
+}
 
-    // original recipe -
-    //if (!$fromExercise || !isset($objExercise) || !($objExercise instanceOf Exercise) || (!$objExercise->isInList($row['id'])))
-	if (!$fromExercise || !isset($objExercise) || !($objExercise instanceOf Exercise) || (is_array($objExercise->questionList)) ) {
-        echo '<tr ',($i%2==0?'class="row_odd"':'class="row_even"'),'>';
-        if (api_get_session_id() == 0 ){
-        	echo '<td align="center"> <input type="checkbox" value="'.$row['id'].'" name="recup['.$my_course_id.'][]"/></td>';
-        }
-        echo '  <td><a href="admin.php?',api_get_cidreq(),'&editQuestion=',$row['id'],'&fromExercise='.$fromExercise.'&answerType='.$row['type'].'">',$row['question'],'</a></td>';
-        echo '  <td align="center" >';
-		if (empty($fromExercise)) {
-            echo '<a href="admin.php?'.api_get_cidreq().'&amp;editQuestion=',$row['id'],'"><img src="../img/edit.gif" border="0" alt="',get_lang('Modify'),'"></a>',
-                '</td>',
-                '<td align="center">',
-                '<a href="',api_get_self(),'?',api_get_cidreq(),'&exerciseId=',$exerciseId,'&delete=',$row['id'],'" onclick="javascript:if(!confirm(\'',addslashes(api_htmlentities(get_lang('ConfirmYourChoice'),ENT_QUOTES,$charset)),'\')) return false;"><img src="../img/delete.gif" border="0" alt="',get_lang('Delete'),'"></a>';
-                //'<a href="',api_get_self(),'?',api_get_cidreq(),'&exerciseId=',$exerciseId,'&delete=',$row['id'],'" onclick="javascript:if(!confirm(\'',addslashes(api_htmlentities(get_lang('ConfirmYourChoice'),ENT_QUOTES,$charset)),'\')) return false;"><img src="../img/delete.gif" border="0" alt="',get_lang('Delete'),'"></a>';
-		} else {
-			echo $row['level'],'</td>',
-				 '<td align="center">';
-			
-			echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&amp;copy_question='.$row['id'].'&course_id='.$my_course_id.'&fromExercise=',$fromExercise,'">';                
-            echo ' '.Display::return_icon('cd.gif', get_lang('ReUseACopyInCurrentTest'));
-            echo '</a> ';
-			if ($row['session_id'] == $session_id) {
-			    if ($selected_course == api_get_course_int_id()) {
-				    //echo '<a href="',api_get_self(),'?',api_get_cidreq(),'&recup=',$row['id'],'&fromExercise=',$fromExercise,'"><img src="../img/view_more_stats.gif" border="0" title="'.get_lang('InsertALinkToThisQuestionInTheExercise').'" alt="'.get_lang('InsertALinkToThisQuestionInTheExercise').'"></a>';
-			    }
-			}
-		}
-        echo '</td>';
-        echo '</tr>';
+if (api_get_session_id() == 0 ){
+	echo '<div style="width:100%; border-top:1px dotted #4171B5;"><button class="save" type="submit">'.get_lang('Reuse').'</button></div></form>';
+}
+Display::display_footer();
 
-		// skips the last question, that is only used to know if we have or not to create a link "Next page"
-		if($i == $limitQuestPage) {
-			break;
-		}
-		$i++;
+
+
+// =========================================================================
+// Some functions here, just for question_pool to ease the code
+// =========================================================================
+
+/*
+	Put the menu entry for level and type to default "Choice"
+	It is usefull if you change the exercice, you need to reset the other menus
+	hubert.borderiou 13-10-2011
+*/
+function reset_menu_lvl_type() {
+	global $exerciseLevel, $answerType;
+	$answerType = -1;
+	$exerciseLevel = -1;
+}
+/*
+	Put the menu entry for exercice and level and type to default "Choice"
+	It is usefull if you change the course, you need to reset the other menus
+	hubert.borderiou 13-10-2011
+*/
+
+function reset_menu_exo_lvl_type() {
+	global $exerciseId, $courseCategoryId;
+	reset_menu_lvl_type();
+	$exerciseId = 0;
+	$courseCategoryId = 0;
+}
+
+// 
+// return the <a> link to admin question, if needed
+// hubert.borderiou 13-10-2011
+function get_a_tag_for_question($in_addA, $in_fromex, $in_questionid, $in_questiontype, $in_questionname) {
+	$res = $in_questionname;
+	if ($in_addA) {
+		$res = "<a href='admin.php?".api_get_cidreq()."&editQuestion=$in_questionid&type=$in_questiontype&fromExercise=$in_fromex'>".$res."</a>";
 	}
+	return $res;
 }
 
-if (!$nbrQuestions) {
-    echo '<tr>',
-        '<td colspan="',($fromExercise?4:4),'">',get_lang('NoQuestion'),'</td>',
-        '</tr>';
+// 
+// return the <a> html code for delete, add, clone, edit a question
+// hubert.borderiou 13-10-2011
+function get_action_icon_for_question($in_action, $from_exercice, $in_questionid, $in_questiontype, $in_questionname, $in_selected_course, $in_courseCategoryId, $in_exercise_id, $in_exerciseLevel, $in_answerType, $in_session_id) {
+	$res = "";
+	$getParams = "&selected_course=$in_selected_course&courseCategoryId=$in_courseCategoryId&exerciseId=$in_exercise_id&exerciseLevel=$in_exerciseLevel&answerType=$in_answerType&session_id=$in_session_id";
+	switch ($in_action) {
+		case "delete" :	
+			$res = "<a href='".api_get_self()."?".api_get_cidreq()."&exerciseId=$from_exercice&delete=$in_questionid$getParams' onclick='return confirm_your_choice()'>";
+			$res .= Display::return_icon("delete.gif", get_lang('Delete'));
+			$res .= "</a>";
+			break;
+		case "edit" :
+			$res = get_a_tag_for_question(1, $from_exercice, $in_questionid, $in_questiontype, Display::return_icon("edit.gif", get_lang('Modify')));
+			break;
+		case "add":
+			// add if question is not already in test
+			$myObjEx = new Exercise();
+			$myObjEx->read($from_exercice);
+			if (!$myObjEx->isInList($in_questionid)) {
+				$res = "<a href='".api_get_self()."?".api_get_cidreq()."&recup=$in_questionid&fromExercise=$from_exercice$getParams'>";
+				$res .= Display::return_icon("view_more_stats.gif", get_lang('InsertALinkToThisQuestionInTheExercise'));
+				$res .= "</a>";
+			}
+			else {
+				$res = "-";
+			}
+			unset($myObjEx);
+			break;
+		case "clone":
+			$res = "<a href='".api_get_self()."?".api_get_cidreq()."&amp;copy_question=$in_questionid&course_id=$in_selected_course&fromExercise=$from_exercice$getParams'>";
+			$res .= Display::return_icon('cd.gif', get_lang('ReUseACopyInCurrentTest'));
+			$res .= "</a>";
+			break;
+		default : 
+			$res = $in_action;
+			break;
+	}
+	return $res;
 }
-echo '</table>';
 
-if (api_get_session_id() == 0 ){
-	echo '<div style="width:100%; border-top:1px dotted #4171B5;">
-		  <button class="save" type="submit">'.get_lang('Reuse').'</button>
-	  	</div></form>';
+//
+// return the icon for the question type
+// hubert.borderiou 13-10-2011
+function get_question_type_for_question($in_selectedcourse, $in_questionid) {
+	$myObjQuestion = Question::read($in_questionid, $in_selectedcourse);
+	list($typeImg, $typeExpl) = $myObjQuestion->get_type_icon_html();
+	$questionType = Display::tag('div', Display::return_icon($typeImg, $typeExpl, array(), 32), array());
+	unset($myObjQuestion);
+	return $questionType;
 }
-Display::display_footer();
+
+//
+// return the name of the category for the question in a course
+// hubert.borderiou 13-10-2011
+function get_question_categorie_for_question($in_courseid, $in_questionid) {
+	$cat = Testcategory::getCategoryNameForQuestion($in_questionid, $in_courseid);
+	return $cat;
+}

+ 421 - 0
main/exercice/testcategory.class.php

@@ -0,0 +1,421 @@
+<?php
+// $Id: testcategory.class.php 2010-12-06 hubert.borderiou 
+
+if(!class_exists('Testcategory')):
+
+class Testcategory {
+	public $id;
+	public $name;
+	public $description;
+	
+	/**
+	 * Constructor of the class Category
+	 * @author - Hubert Borderiou
+	 If you give an in_id and no in_name, you get info concerning the category of id=in_id
+	 otherwise, you've got an category objet avec your in_id, in_name, in_descr
+	 */
+	function Testcategory($in_id=0, $in_name, $in_description="") {
+		if ($in_id != 0 && $in_name == "") {
+			$tmpobj = new Testcategory();
+			$tmpobj->getCategory($in_id);
+			$this->id = $tmpobj->id;
+			$this->name = $tmpobj->name;
+			$this->description = $tmpobj->description;
+		}
+		else {
+			$this->id = $in_id;
+			$this->name = $in_name;
+			$this->description = $in_description;
+		}
+	}
+	
+	/** return the Testcategory object with id=in_id
+	 */
+	function getCategory($in_id) {
+		$t_cattable = Database::get_course_table(TABLE_QUIZ_QUESTION_CATEGORY);
+		$in_id = Database::escape_string($in_id);
+		$sql = "SELECT * FROM $t_cattable WHERE id=$in_id AND c_id=".api_get_course_int_id();
+		$res = Database::query($sql);
+		$numrows = Database::num_rows($res);
+		if ($numrows > 0) {
+			$row = Database::fetch_array($res);
+			$this->id = $row['id'];
+			$this->name = $row['name'];
+			$this->description  = $row['description'];
+		}
+	}
+	
+	/** add Testcategory in the database if name doesn't already exists
+		*/
+	function addCategoryInBDD() {
+		$t_cattable = Database :: get_course_table(TABLE_QUIZ_QUESTION_CATEGORY);
+		$v_name = $this->name;
+		$v_name = Database::escape_string($v_name);
+		$v_description = $this->description;
+		$v_description = Database::escape_string($v_description);
+		// check if name already exists
+		$sql_verif = "SELECT count(*) AS nb FROM $t_cattable WHERE name = '$v_name' AND c_id=".api_get_course_int_id();
+		$result_verif = Database::query($sql_verif, __FILE__, __LINE__);
+		$data_verif = Database::fetch_array($result_verif);
+		// lets add in BDD if not the same name
+		if ($data_verif['nb'] <= 0) {
+			$c_id = api_get_course_int_id();
+			$sql = "INSERT INTO $t_cattable VALUES ('$c_id', '', '$v_name', '$v_description')";
+			$res = Database::query($sql, __FILE__, __LINE__);
+			return true;
+		}
+		else {
+			return false;
+		}		
+	}
+	
+	/** remove catagory with id=in_id from the database if no question use this category
+	 */
+	function removeCategory($in_id) {
+		$t_cattable = Database :: get_course_table(TABLE_QUIZ_QUESTION_CATEGORY);
+		$v_id = Database::escape_string($this->id);
+		$sql = "DELETE FROM $t_cattable WHERE id=$v_id AND c_id=".api_get_course_int_id();
+		$res = Database::query($sql);
+		if (Database::affected_rows() <= 0) {
+			return false;
+		}
+		else {
+			return true;
+		}		
+	}
+	
+
+	/** modify category name or description of category with id=in_id 
+	 */
+	function modifyCategory($in_id, $in_name, $in_description) {
+		$t_cattable = Database :: get_course_table(TABLE_QUIZ_QUESTION_CATEGORY);
+		$v_id = Database::escape_string($this->id);
+		$v_name = Database::escape_string($this->name);
+		$v_description = Database::escape_string($this->description);
+		$sql = "UPDATE $t_cattable SET name='$v_name', description='$v_description' WHERE id='$v_id' AND c_id=".api_get_course_int_id();
+		$res = Database::query($sql);
+		if (Database::affected_rows() <= 0) {
+			return false;
+		}
+		else {
+			return true;
+		}
+	}
+	
+	/** get number of question of category id=in_id
+	 */
+	function getCategoryQuestionsNumber($in_id) {
+		$t_reltable = Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY);
+		$in_id = Database::escape_string($this->id);
+		$sql = "SELECT count(*) AS nb FROM $t_reltable WHERE category_id=$in_id AND c_id=".api_get_course_int_id();
+		$res = Database::query($sql, __FILE__, __LINE__);
+		$row = Database::fetch_array($res);
+		return $row['nb'];
+	}
+	
+	
+	function display($in_color="#E0EBF5") {
+		echo "<textarea style='background-color:$in_color; width:60%; height:100px;'>";
+		print_r($this);
+		echo "</textarea>";
+	}
+	
+	
+	
+	/** return an array of all Category objects in the database
+	If in_field=="" Return an array of all category objects in the database
+	Otherwise, return an array of all in_field value in the database (in_field = id or name or description)
+	 */
+	public function getCategoryListInfo($in_field="", $in_courseid="") {
+		if (empty($in_courseid) || $in_courseid=="") {
+			$in_courseid = api_get_course_int_id();
+		}		
+		$t_cattable = Database :: get_course_table(TABLE_QUIZ_QUESTION_CATEGORY);		
+		$in_field = Database::escape_string($in_field);
+		$tabres = array();
+		if ($in_field=="") {
+			$sql = "SELECT * FROM $t_cattable WHERE c_id=$in_courseid ORDER BY name ASC";
+			$res = Database::query($sql);
+			while ($row = Database::fetch_array($res)) {
+				$tmpcat = new Testcategory($row['id'], $row['name'], $row['description']);
+				$tabres[] = $tmpcat;
+			}
+		}
+		else {
+			$sql = "SELECT $in_field FROM $t_cattable WHERE c_id=$in_courseid ORDER BY $in_field ASC";
+			$res = Database::query($sql);
+			while ($row = Database::fetch_array($res)) {
+				$tabres[] = $row[$in_field];
+			}
+		}
+		return $tabres;
+	}
+		
+
+	/**
+	 Return the testcategory id for question with question_id = $in_questionid
+	 In this version, a question has only 1 testcategory.
+	 Return the testcategory id, 0 if none
+	 */
+	public static function getCategoryForQuestion($in_questionid, $in_courseid="") {
+		$result = 0;	// result
+		if (empty($in_courseid) || $in_courseid=="") {
+			$in_courseid = api_get_course_int_id();
+		}
+		$t_cattable = Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY);		
+		$question_id = Database::escape_string($in_questionid);
+		$sql = "SELECT category_id FROM $t_cattable WHERE question_id='$question_id' AND c_id=$in_courseid";
+		$res = Database::query($sql);
+		$data = Database::fetch_array($res);
+		if (Database::num_rows($res) > 0) {
+			$result = $data['category_id'];
+		}
+		return $result;
+	}		
+	
+	
+	/**
+	 * true if question id has a category
+	 */
+	public static function isQuestionHasCategory($in_questionid) {
+		if (Testcategory::getCategoryForQuestion($in_questionid) > 0) {
+			return true;
+		}
+		return false;
+	}
+	
+	
+	/**
+	 Return the category name for question with question_id = $in_questionid
+	 In this version, a question has only 1 category.
+	 Return the category id, "" if none
+	 */
+	function getCategoryNameForQuestion($in_questionid, $in_courseid="") {
+		if (empty($in_courseid) || $in_courseid=="") {
+			$in_courseid = api_get_course_int_id();
+		}		
+		$catid = Testcategory::getCategoryForQuestion($in_questionid, $in_courseid);
+		$result = "";	// result
+		$t_cattable = Database::get_course_table(TABLE_QUIZ_QUESTION_CATEGORY);		
+		$catid = Database::escape_string($catid);
+		$sql = "SELECT name FROM $t_cattable WHERE id='$catid' AND c_id=$in_courseid";
+		$res = Database::query($sql);
+		$data = Database::fetch_array($res);
+		if (Database::num_rows($res) > 0) {
+			$result = $data['name'];
+		}
+		return $result;
+	}
+	
+
+	
+	/**
+	 * return the list of differents categories ID for a test
+	 * input : test_id
+	 * return : array of category id (integer)
+	 * hubert.borderiou 07-04-2011
+	 */
+	public static function getListOfCategoriesIDForTest($in_testid) {
+		// parcourir les questions d'un test, recup les categories uniques dans un tableau
+		$tabcat = array();
+		$quiz = new Exercise();
+		$quiz->read($in_testid);
+		$tabQuestionList = $quiz->selectQuestionList();
+		for ($i=0; $i < count($tabQuestionList); $i++) {
+			if (!in_array(Testcategory::getCategoryForQuestion($tabQuestionList[$i]), $tabcat)) {
+				$tabcat[] = Testcategory::getCategoryForQuestion($tabQuestionList[$i]);
+			}
+		}
+		return $tabcat;
+	}
+	
+	
+	/**
+	 * return the list of differents categories NAME for a test
+	 * input : test_id
+	 * return : array of string
+	 * hubert.borderiou 07-04-2011
+	 */
+	public static function getListOfCategoriesNameForTest($in_testid) {
+		$tabcatName = array();
+		$tabcatID = getListOfCategoriesNameForTest($in_testid);
+		for ($i=0; $i < count($tabcatID); $i++) {
+			$cat = new Testcategory($tabcatID[$i]);
+			$tabcatName[] = $cat->name;
+		}
+		return $tabcatName;
+	}
+	
+	/**
+	 * return the number of differents categories for a test
+	 * input : test_id
+	 * return : integer
+	 * hubert.borderiou 07-04-2011
+	 */
+	public static function getNumberOfCategoriesForTest($in_testid) {
+		return count(Testcategory::getListOfCategoriesIDForTest($in_testid));
+	}
+	
+	
+	/**
+	 * return the number of question of a category id in a test
+	 * input : test_id, category_id
+	 * return : integer
+	 * hubert.borderiou 07-04-2011
+	 */
+	public static function getNumberOfQuestionsInCategoryForTest($in_testid, $in_categoryid) {
+		$nbCatResult = 0;
+		$quiz = new Exercise();
+		$quiz->read($in_testid);
+		$tabQuestionList = $quiz->selectQuestionList();
+		for ($i=0; $i < count($tabQuestionList); $i++) {
+			if (Testcategory::getCategoryForQuestion($tabQuestionList[$i]) == $in_categoryid) {
+				$nbCatResult++;
+			}
+		}		
+		return $nbCatResult;
+	}
+	
+	/**
+	 * return the number of question for a test using random by category
+	 * input  : test_id, number of random question (min 1)
+	 * hubert.borderiou 07-04-2011
+	 * question witout categories are not counted
+	 */
+	public static function getNumberOfQuestionRandomByCategory($in_testid, $in_nbrandom) {
+		$nbquestionresult = 0;
+		$tabcatid = Testcategory::getListOfCategoriesIDForTest($in_testid);
+		for ($i=0; $i < count($tabcatid); $i++) {
+			if ($tabcatid[$i] > 0) {	// 0 = no category for this questio
+				$nbQuestionInThisCat = Testcategory::getNumberOfQuestionsInCategoryForTest($in_testid, $tabcatid[$i]);
+				if ($nbQuestionInThisCat > $in_nbrandom) {
+					$nbquestionresult += $in_nbrandom;
+				}
+				else {
+					$nbquestionresult += $nbQuestionInThisCat;
+				}
+			}
+		}
+		return $nbquestionresult;
+	}
+	
+	
+	/**
+	 * Return an array (id=>name)
+	 * tabresult[0] = get_lang('NoCategory');
+	 *
+	 */
+	function getCategoriesIdAndName($in_courseid="") {
+		if (empty($in_courseid) || $in_courseid=="") {
+			$in_courseid = api_get_course_int_id();
+		}		
+	 	$tabcatobject = Testcategory::getCategoryListInfo("", $in_courseid);
+	 	$tabresult = array("0"=>get_lang('NoCategory'));
+	 	for ($i=0; $i < count($tabcatobject); $i++) {
+	 		$tabresult[$tabcatobject[$i]->id] = $tabcatobject[$i]->name;
+	 	}
+	 	return $tabresult;
+	}
+	
+	/**
+		* return an array of question_id for each category
+		* tabres[0] = array of question id with category id = 0 (i.e. no category)
+		* tabres[24] = array of question id with category id = 24
+		* In this version, a question has 0 or 1 category
+	 */
+	function getQuestionsByCat($in_exerciceId) {
+		$tabres = array();
+		$TBL_EXERCICE = Database::get_course_table(TABLE_QUIZ_TEST);
+		$TBL_EXERCICE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
+		$TBL_QUESTION_REL_CATEGORY = Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY);
+		$sql = "SELECT qrc.question_id, qrc.category_id FROM $TBL_QUESTION_REL_CATEGORY qrc, $TBL_EXERCICE_QUESTION eq WHERE exercice_id=$in_exerciceId AND eq.question_id=qrc.question_id AND eq.c_id=".api_get_course_int_id()." AND eq.c_id=qrc.c_id ORDER BY category_id, question_id";
+		$res = Database::query($sql);
+		while ($data = Database::fetch_array($res)) {
+			if (!is_array($tabres[$data['category_id']])) {
+				$tabres[$data['category_id']] = array();
+			}
+			$tabres[$data['category_id']][] = $data['question_id'];
+		}
+		return $tabres;
+	}
+	
+	
+	/**
+	 * return a tab of $in_number random elements of $in_tab
+	 */
+	function getNElementsFromArray($in_tab, $in_number) {
+		$tabres = $in_tab;
+		shuffle($tabres);
+		if ($in_number < count($tabres)) {
+			$tabres = array_slice($tabres, 0, $in_number);
+		}
+		return $tabres;
+	}
+	
+	/**
+	 * display the category
+	 */
+	function displayCategoryAndTitle($in_questionID) {
+		if (Testcategory::getCategoryNameForQuestion($in_questionID) != "") {
+			echo "<div id=\"question_title\" class=\"sectiontitle\" style='font-size:110%; margin-top:20px; padding-top:10px'>";
+			echo "<div style='font-size:110%;font-weight:normal; margin-bottom:5px; padding:0px 10px 5px 10px;'>";
+			echo get_lang('Category').": ".Testcategory::getCategoryNameForQuestion($in_questionID);
+			echo "</div>";			
+			echo "</div>";
+		}
+	}
+	
+	/**
+		* Display signs [+] and/or (>0) after question title if question has options
+		* scoreAlwaysPositive and/or uncheckedMayScore
+		*/
+	function displayQuestionOption($in_objQuestion) {
+		if ($in_objQuestion->type == MULTIPLE_ANSWER && $in_objQuestion->scoreAlwaysPositive) {
+			echo "<span style='font-size:75%'> (>0)</span>";
+		}
+		if ($in_objQuestion->type == MULTIPLE_ANSWER && $in_objQuestion->uncheckedMayScore) {
+			echo "<span style='font-size:75%'> [+]</span>";
+		}
+	}
+	
+	/**
+	 * sortTabByBracketLabel ($tabCategoryQuestions)
+	 * key of $tabCategoryQuestions are the categopy id (0 for not in a category)
+	 * value is the array of question id of this category
+	 * Sort question by Category
+	*/
+	function sortTabByBracketLabel($in_tab) {
+		$tabResult = array();
+		$tabCatName = array();	// tab of category name
+		while (list($cat_id, $tabquestion) = each($in_tab)) {
+			$catTitle = new Testcategory($cat_id);
+			$tabCatName[$cat_id] = $catTitle->name;
+		}
+		reset($in_tab);
+		// sort table by value, keeping keys as they are
+		asort($tabCatName);
+		// keys of $tabCatName are keys order for $in_tab
+		while (list($key, $val) = each($tabCatName)) {
+			$tabResult[$key] = $in_tab[$key];
+		}
+		return $tabResult;
+	}
+	
+	/**
+		* return total score for test exe_id for all question in the category $in_cat_id for user
+		* If no question for this category, return ""
+	*/
+	public static function getCatScoreForExeidForUserid($in_cat_id, $in_exe_id, $in_user_id) {
+		$tbl_track_attempt		= Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
+		$tbl_question_rel_category = Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY);
+		$query = "SELECT DISTINCT marks, exe_id, user_id, ta.question_id, category_id FROM $tbl_track_attempt ta , $tbl_question_rel_category qrc WHERE ta.question_id=qrc.question_id AND qrc.category_id=$in_cat_id AND exe_id=$in_exe_id AND user_id=$in_user_id";
+		$res = Database::query($query);
+		$totalcatscore = "";
+		while ($data = Database::fetch_array($res)) {
+			$totalcatscore += $data['marks'];
+		}
+		return $totalcatscore;
+	}
+}
+endif;
+?>

+ 274 - 0
main/exercice/tests_category.php

@@ -0,0 +1,274 @@
+<?php
+/**
+	hubert.borderiou 
+	Manage tests category page
+*/
+
+$htmlHeadXtra[] = '
+<script type="text/javascript">
+	function confirmDelete(in_txt, in_id) {
+		var oldbgcolor = document.getElementById(in_id).style.backgroundColor;
+		document.getElementById(in_id).style.backgroundColor="#AAFFB0";
+		if (confirm(in_txt)) {
+			return true;
+		}
+		else {
+			document.getElementById(in_id).style.backgroundColor = oldbgcolor;
+			return false;
+		}
+	}
+</script>
+';
+
+// name of the language file that needs to be included
+$language_file='exercice';
+$nameTools= "";
+
+include('question.class.php');
+include('testcategory.class.php');
+include('../inc/global.inc.php');
+include('exercise.lib.php');
+require_once (api_get_path(LIBRARY_PATH).'formvalidator/FormValidator.class.php');
+
+$this_section=SECTION_COURSES;
+
+if(!api_is_allowed_to_edit()) {
+	api_not_allowed(true);
+}
+
+// breadcrumbs
+$interbreadcrumb[]=array("url" => "exercice.php","name" => get_lang('Exercices'));
+Display::display_header(get_lang('Category'));
+
+// Action handling: add, edit and remove
+if (isset($_GET['action']) && $_GET['action'] == 'addcategory') 
+{			
+	add_category_form(Security::remove_XSS($_GET['action']));
+}
+else if (isset($_GET['action']) && $_GET['action'] == 'editcategory') {
+	edit_category_form(Security::remove_XSS($_GET['action']));
+}
+else if (isset($_GET['action']) && $_GET['action'] == 'deletecategory') {
+	delete_category_form(Security::remove_XSS($_GET['action']));
+}
+else {
+	display_add_category();
+	display_categories();
+}
+
+Display::display_footer();
+
+// **********************************************************************************
+// ******                       FUNCTIONS                        ********************
+// **********************************************************************************
+
+// ------------------------------------------------------------------------
+// form to edit a category
+// ------------------------------------------------------------------------
+function edit_category_form($in_action) {
+	
+	if (isset($_GET['category_id']) && is_numeric($_GET['category_id'])) {
+		$category_id = Security::remove_XSS($_GET['category_id']);
+		$objcat = new Testcategory($category_id);
+		// --------------------
+		// initiate the object
+		// --------------------
+		$form = new FormValidator('note','post', api_get_self().'?action='.$in_action.'&category_id='.$category_id);
+		// --------------------
+		// settting the form elements	
+		// --------------------
+		$form->addElement('header', '', get_lang('EditCategory'));
+		$form->addElement('hidden', 'category_id');
+		$form->addElement('text', 'category_name', get_lang('CategoryName'),array('size'=>'95'));
+		$form->addElement('html_editor', 'category_description', get_lang('CategoryDescription'), null, array('ToolbarSet' => 'test_category', 'Width' => '90%', 'Height' => '200'));
+		$form->addElement('style_submit_button', 'SubmitNote', get_lang('ModifyCategory'), 'class="add"');	
+		// --------------------
+		// setting the defaults
+		// --------------------
+		$defaults = array();
+		$defaults["category_id"] = $objcat->id;
+		$defaults["category_name"] = $objcat->name;
+		$defaults["category_description"] =  $objcat->description;
+		$form->setDefaults($defaults);
+		// --------------------
+		// setting the rules
+		// --------------------
+		$form->addRule('category_name', '<div class="required">'.get_lang('ThisFieldIsRequired'), 'required');	
+		// --------------------
+		// The validation or display
+		// --------------------
+		if ($form->validate()) 
+		{
+			$check = Security::check_token('post');	
+			if ($check) {
+	   		$values = $form->exportValues();
+	   		$v_id = Security::remove_XSS($values['category_id']);
+				$v_name = Security::remove_XSS($values['category_name'], COURSEMANAGER);
+				$v_description = Security::remove_XSS($values['category_description'], COURSEMANAGER);
+	   		$objcat = new Testcategory($v_id, $v_name, $v_description);
+	   		if ($objcat->modifyCategory()) {
+	   			Display::display_confirmation_message(get_lang('MofidfyCategoryDone'));
+	   		}
+	   		else {
+	   			Display::display_confirmation_message(get_lang('ModifyCategoryError'));
+	   		}
+			}
+			Security::clear_token();		
+			display_add_category();
+			display_categories();
+		} 
+		else 
+		{
+			display_goback();
+			$token = Security::get_token();
+			$form->addElement('hidden','sec_token');
+			$form->setConstants(array('sec_token' => $token));		
+			$form->display();
+			display_categories();
+		}		
+	}
+	else {
+		Display::display_error_message(get_lang('CannotEditCategory'));
+	}
+}
+
+// ------------------------------------------------------------------------
+// process to delete a category
+// ------------------------------------------------------------------------
+function delete_category_form($in_action) {
+	if (isset($_GET['category_id']) && is_numeric($_GET['category_id'])) {
+		$category_id = Security::remove_XSS($_GET['category_id']);
+		$catobject = new Testcategory($category_id);
+		if ($catobject->getCategoryQuestionsNumber() == 0) {
+			if ($catobject->removeCategory()) {
+				Display::display_confirmation_message(get_lang('DeleteCategoryDone'));
+			}
+			else {
+				Display::display_error_message(get_lang('CannotDeleteCategoryError'));
+			}
+		}
+		else {
+			Display::display_error_message(get_lang('CannotDeleteCategory'));
+		}
+	}
+	else {
+		Display::display_error_message(get_lang('CannotDeleteCategoryError'));
+	}
+	display_add_category();
+	display_categories();
+}
+
+// ------------------------------------------------------------------------
+// form to add a category
+// ------------------------------------------------------------------------
+function add_category_form($in_action) {
+	// initiate the object
+	$form = new FormValidator('note','post', api_get_self().'?action='.$in_action);
+	// settting the form elements	
+	$form->addElement('header', '', get_lang('AddACategory'));
+	$form->addElement('text', 'category_name', get_lang('CategoryName'),array('size'=>'95'));
+	$form->addElement('html_editor', 'category_description', get_lang('CategoryDescription'), null, array('ToolbarSet' => 'test_category', 'Width' => '90%', 'Height' => '200'));
+	$form->addElement('style_submit_button', 'SubmitNote', get_lang('AddTestCategory'), 'class="add"');	
+	// setting the rules
+	$form->addRule('category_name', '<div class="required">'.get_lang('ThisFieldIsRequired'), 'required');	
+	// The validation or display
+	if ($form->validate()) 
+	{
+		$check = Security::check_token('post');	
+		if ($check) {
+	   		$values = $form->exportValues();
+				$v_name = Security::remove_XSS($values['category_name'], COURSEMANAGER);
+				$v_description = Security::remove_XSS($values['category_description'], COURSEMANAGER);
+	   		$objcat = new Testcategory(0, $v_name, $v_description);
+	   		if ($objcat->addCategoryInBDD()) {
+	   			Display::display_confirmation_message(get_lang('AddCategoryDone'));
+	   		}
+	   		else {
+	   			Display::display_confirmation_message(get_lang('AddCategoryNameAlreadyExists'));
+	   		}
+		}
+		Security::clear_token();		
+		display_add_category();
+		display_categories();
+	} 
+	else 
+	{
+		display_goback();
+		$token = Security::get_token();
+		$form->addElement('hidden','sec_token');
+		$form->setConstants(array('sec_token' => $token));		
+		$form->display();
+		display_categories();
+	}	
+}
+
+
+// ------------------------------------------------------------------------
+// Display add category button
+// ------------------------------------------------------------------------
+function display_add_category() {
+	echo '<div class="actions">';
+	echo '<a href="exercice.php?'.api_get_cidreq().'">'.Display::return_icon('back.png', get_lang('GoBackToQuestionList'),'',32).'</a>';			
+	echo '<a href="'.api_get_self().'?action=addcategory">'.Display::return_icon('question_category.gif').'</a>';
+	echo '</div>';
+	echo "<br/>";
+}
+
+
+// ------------------------------------------------------------------------
+// Display category list
+// ------------------------------------------------------------------------
+function display_categories() {
+	$t_cattable = Database::get_course_table(TABLE_QUIZ_QUESTION_CATEGORY);
+	$sql = "SELECT * FROM $t_cattable ORDER BY name";
+	$res = Database::query($sql, __FILE__, __LINE__);
+	while ($row = Database::fetch_array($res)) {
+		// le titre avec le nombre de questions qui sont dans cette catégorie
+		$tmpobj = new Testcategory($row['id']);
+		$nb_question = $tmpobj->getCategoryQuestionsNumber();
+		echo '<div class="sectiontitle" id="id_cat'.$row['id'].'">';
+		echo "<span style='float:right'>".$nb_question.get_lang('NbCategory')."</span>";
+		echo $row['name'];
+		echo '</div>';
+		echo '<div class="sectioncomment">';
+		echo $row['description'];
+		echo '</div>';
+		echo '<div>';
+		echo '<a href="'.api_get_self().'?action=editcategory&amp;category_id='.$row['id'].'">'.Display::return_icon('edit.gif', get_lang('Edit')).'</a>';
+		if ($nb_question > 0) {
+			echo '<a href="javascript:void(0)" onclick="alert(\''.protectJSDialogQuote(get_lang('CannotDeleteCategory')).'\')">';
+			echo Display::return_icon('delete_na.gif', get_lang('CannotDeleteCategory'));
+			echo '</a>';
+		}
+		else {
+			$rowname = protectJSDialogQuote($row['name']);
+			echo '<a href="'.api_get_self().'?action=deletecategory&amp;category_id='.$row['id'].'" ';
+			echo 'onclick="return confirmDelete(\''.protectJSDialogQuote(get_lang('DeleteCategoryAreYouSure').'['.$rowname).'] ?\', \'id_cat'.$row['id'].'\');">';
+			echo Display::return_icon('delete.gif', get_lang('Delete')).'</a>';
+		}
+		echo '</div>';
+	}
+}
+
+
+// ------------------------------------------------------------------------
+// display goback to category list page link
+// ------------------------------------------------------------------------
+function display_goback() {
+	echo '<div class="actions">';
+	echo '<a href="'.api_get_self().'">'.Display::return_icon('back.png', '', 32).' '.get_lang('BackToCategoryList').'</a>';
+	echo '</div>';
+}
+
+// ------------------------------------------------------------------------
+// To allowed " in javascript dialog box without bad surprises
+// replace " with two '
+// ------------------------------------------------------------------------
+function protectJSDialogQuote($in_txt) {
+	$res = $in_txt;
+	$res = str_replace("'", "\'", $res);
+	$res = str_replace('"', "\'\'", $res);	// super astuce pour afficher les " dans les boite de dialogue
+	return $res;
+}
+
+?>

+ 7 - 1
main/forum/editpost.php

@@ -153,25 +153,31 @@ if (!api_is_allowed_to_edit(null, true) AND (($current_forum_category['visibilit
         exit;
     }
 }
+ 
 if (!api_is_allowed_to_edit(null, true) AND ($current_forum_category['locked'] <> 0 OR $current_forum['locked'] <> 0 OR $current_thread['locked'] <> 0)) {
     $forum_allow = forum_not_allowed_here();
     if ($forum_allow === false) {
         exit;
     }
 }
+
 if (!$_user['user_id'] AND $current_forum['allow_anonymous'] == 0) {
     $forum_allow = forum_not_allowed_here();
     if ($forum_allow === false) {
         exit;
     }
 }
-if (!api_is_allowed_to_edit(null, true) AND $current_forum['allow_edit'] == 0) {
+$group_id = api_get_group_id();
+
+if (!api_is_allowed_to_edit(null, true) AND $current_forum['allow_edit'] == 0 && !GroupManager::is_tutor_of_group(api_get_user_id(), $group_id)) {
     $forum_allow = forum_not_allowed_here();
     if ($forum_allow === false) {
         exit;
     }
 }
 
+
+
 // Action links
 if ($origin != 'learnpath') {
     echo '<div class="actions">';

+ 38 - 25
main/forum/forumfunction.inc.php

@@ -519,14 +519,14 @@ function store_forum($values) {
         $new_max = null;
     } else {
         $sql = "SELECT MAX(forum_order) as sort_max FROM ".$table_forums." 
-        		WHERE c_id = $course_id AND forum_category='".Database::escape_string(stripslashes($values['forum_category']))."'";
+        		WHERE c_id = $course_id AND forum_category='".Database::escape_string($values['forum_category'])."'";
         $result = Database::query($sql);
         $row = Database::fetch_array($result);
         $new_max = $row['sort_max'] + 1;
     }
 
     $session_id = api_get_session_id();
-    $clean_title = Database::escape_string(stripslashes($values['forum_title']));
+    $clean_title = Database::escape_string($values['forum_title']);
 
     // Forum images
     $image_moved = false;
@@ -597,6 +597,7 @@ function store_forum($values) {
                 forum_of_group='".	Database::escape_string($values['group_forum'])."'
             WHERE forum_id='".Database::escape_string($values['forum_id'])."'";
             Database::query($sql);
+         
             api_item_property_update($_course, TOOL_FORUM, Database::escape_string($values['forum_id']), 'ForumUpdated', api_get_user_id());
             $return_message = get_lang('ForumEdited');
     } else {
@@ -623,7 +624,7 @@ function store_forum($values) {
                 '".Database::escape_string(isset($values['group_forum'])?$values['group_forum']:null)."',
                 '".Database::escape_string(isset($values['public_private_group_forum_group']['public_private_group_forum'])?$values['public_private_group_forum_group']['public_private_group_forum']:null)."',
                 '".Database::escape_string(isset($new_max)?$new_max:null)."',
-                ".intval($session_id).")";
+                ".intval($session_id).")";                   
         Database::query($sql);
         $last_id = Database::insert_id();
         if ($last_id > 0) {
@@ -1824,7 +1825,7 @@ function store_thread($values) {
     }
     if ($upload_ok) {
 
-        $post_date = date('Y-m-d H:i:s');
+        $post_date = api_get_utc_datetime();
 
         if ($current_forum['approval_direct_post'] == '1' && !api_is_allowed_to_edit(null, true)) {
             $visible = 0; // The post has not been approved yet.
@@ -3611,25 +3612,33 @@ function get_forums_of_group($group_id) {
     $table_posts 			= Database :: get_course_table(TABLE_FORUM_POST);
     $table_item_property 	= Database :: get_course_table(TABLE_ITEM_PROPERTY);
     $table_users 			= Database :: get_main_table(TABLE_MAIN_USER);
-
+    $course_id              = api_get_course_int_id();
+    
     //-------------- Student -----------------//
     // Select all the forum information of all forums (that are visible to students).
     $sql = "SELECT * FROM ".$table_forums." forum , ".$table_item_property." item_properties
-                WHERE forum.forum_of_group = '".Database::escape_string($group_id)."'
-                AND forum.forum_id=item_properties.ref
-                AND item_properties.visibility=1
-                AND item_properties.tool='".TOOL_FORUM."'
+                WHERE forum.forum_of_group = '".Database::escape_string($group_id)."' AND
+                forum.c_id = $course_id AND
+                item_properties.c_id = $course_id AND                 
+                forum.forum_id=item_properties.ref AND 
+                item_properties.visibility=1 AND
+                item_properties.tool='".TOOL_FORUM."'
                 ORDER BY forum.forum_order ASC";
     // Select the number of threads of the forums (only the threads that are visible).
     $sql2 = "SELECT count(thread_id) AS number_of_threads, threads.forum_id FROM $table_threads threads, ".$table_item_property." item_properties
-                    WHERE threads.thread_id=item_properties.ref
-                    AND item_properties.visibility=1
-                    AND item_properties.tool='".TOOL_FORUM_THREAD."'
+                    WHERE threads.thread_id=item_properties.ref AND
+                    forum.c_id = $course_id AND
+                    item_properties.c_id = $course_id AND 
+                    item_properties.visibility=1 AND
+                    item_properties.tool='".TOOL_FORUM_THREAD."'
                     GROUP BY threads.forum_id";
     // Select the number of posts of the forum (post that are visible and that are in a thread that is visible).
     $sql3 = "SELECT count(post_id) AS number_of_posts, posts.forum_id FROM $table_posts posts, $table_threads threads, ".$table_item_property." item_properties
-            WHERE posts.visible=1
-            AND posts.thread_id=threads.thread_id
+            WHERE posts.visible=1 AND
+            posts.c_id = $course_id AND
+            item_properties.c_id = $course_id AND
+            threads.c_id = $course_id
+            AND posts.thread_id=threads.thread_id            
             AND threads.thread_id=item_properties.ref
             AND item_properties.visibility=1
             AND item_properties.tool='".TOOL_FORUM_THREAD."'
@@ -3639,25 +3648,29 @@ function get_forums_of_group($group_id) {
     if (is_allowed_to_edit()) {
         // Select all the forum information of all forums (that are not deleted).
         $sql = "SELECT * FROM ".$table_forums." forum , ".$table_item_property." item_properties
-                    WHERE forum.forum_of_group = '".Database::escape_string($group_id)."'
-                    AND forum.forum_id=item_properties.ref
-                    AND item_properties.visibility<>2
-                    AND item_properties.tool='".TOOL_FORUM."'
+                    WHERE forum.forum_of_group = '".Database::escape_string($group_id)."' AND
+                    forum.c_id = $course_id AND
+                    item_properties.c_id = $course_id AND         
+                    forum.forum_id=item_properties.ref AND
+                    item_properties.visibility<>2 AND 
+                    item_properties.tool='".TOOL_FORUM."' 
                     ORDER BY forum_order ASC";
-        //echo $sql.'<hr />';
+
         // Select the number of threads of the forums (only the threads that are not deleted).
         $sql2 = "SELECT count(thread_id) AS number_of_threads, threads.forum_id FROM $table_threads threads, ".$table_item_property." item_properties
-                        WHERE threads.thread_id=item_properties.ref
-                        AND item_properties.visibility<>2
-                        AND item_properties.tool='".TOOL_FORUM_THREAD."'
+                        WHERE threads.thread_id=item_properties.ref AND
+                        threads.c_id = $course_id AND
+                        item_properties.c_id = $course_id AND 
+                        item_properties.visibility<>2 AND
+                        item_properties.tool='".TOOL_FORUM_THREAD."'
                         GROUP BY threads.forum_id";
-        //echo $sql2.'<hr />';
         // Select the number of posts of the forum.
-        $sql3 = "SELECT count(post_id) AS number_of_posts, forum_id FROM $table_posts GROUP BY forum_id";
-        //echo $sql3.'<hr />';
+        $sql3 = "SELECT count(post_id) AS number_of_posts, forum_id FROM $table_posts WHERE c_id = $course_id GROUP BY forum_id";
+
     }
 
     // Handling all the forum information.
+    
     $result = Database::query($sql);
     while ($row = Database::fetch_array($result, 'ASSOC')) {
         $forum_list[$row['forum_id']] = $row;

+ 5 - 2
main/forum/viewthread.php

@@ -101,11 +101,14 @@ if (!api_is_allowed_to_edit(false, true) AND ($current_forum['visibility'] == 0
 
 /* Actions */
 
+$group_id = api_get_group_id();
+
+
 $my_action = isset($_GET['action']) ? $_GET['action'] : '';
-if ($my_action == 'delete' AND isset($_GET['content']) AND isset($_GET['id']) AND api_is_allowed_to_edit(false, true)) {
+if ($my_action == 'delete' AND isset($_GET['content']) AND isset($_GET['id']) AND (api_is_allowed_to_edit(false, true) OR GroupManager::is_tutor_of_group(api_get_user_id(), $group_id))) {
     $message = delete_post($_GET['id']); // Note: This has to be cleaned first.
 }
-if (($my_action == 'invisible' OR $my_action == 'visible') AND isset($_GET['id']) AND api_is_allowed_to_edit(false, true)) {
+if (($my_action == 'invisible' OR $my_action == 'visible') AND isset($_GET['id']) AND api_is_allowed_to_edit(false, true) OR GroupManager::is_tutor_of_group(api_get_user_id(), $group_id)) {
     $message = approve_post($_GET['id'], $_GET['action']); // Note: This has to be cleaned first.
 }
 if ($my_action == 'move' AND isset($_GET['post'])) {

+ 6 - 2
main/forum/viewthread_flat.inc.php

@@ -46,6 +46,8 @@ if (isset($current_thread['thread_id'])){
         } else {
             echo $name. '<br />';
         }
+
+        $group_id = api_get_group_id();
         
         echo api_convert_and_format_date($row['post_date']).'<br /><br />';
         // get attach id
@@ -53,15 +55,17 @@ if (isset($current_thread['thread_id'])){
         $id_attach = !empty($attachment_list)?$attachment_list['id']:'';
         // The user who posted it can edit his thread only if the course admin allowed this in the properties of the forum
         // The course admin him/herself can do this off course always
-        if (($current_forum['allow_edit']==1 AND $row['user_id']==$_user['user_id']) or (api_is_allowed_to_edit(false,true)  && !(api_is_course_coach() && $current_forum['session_id']!=$_SESSION['id_session']))) {
+        if ( GroupManager::is_tutor_of_group(api_get_user_id(), $group_id) OR  ($current_forum['allow_edit']==1 AND $row['user_id']==$_user['user_id']) or (api_is_allowed_to_edit(false,true)  && !(api_is_course_coach() && $current_forum['session_id']!=$_SESSION['id_session']))) {
             if (api_is_allowed_to_session_edit(false,true)) {
                 echo "<a href=\"editpost.php?".api_get_cidreq()."&amp;gidReq=".Security::remove_XSS($_GET['gidReq'])."&amp;forum=".$clean_forum_id."&amp;thread=".$clean_thread_id."&amp;post=".$row['post_id']."&amp;origin=".$origin."&amp;edit=edition&amp;id_attach=".$id_attach."\">".Display::return_icon('edit.png',get_lang('Edit'), array(), 22)."</a>";
             }
         }
 
         if ($origin != 'learnpath') {
-            if (api_is_allowed_to_edit(false,true)  && !(api_is_course_coach() && $current_forum['session_id']!=$_SESSION['id_session'])) {
+            if (GroupManager::is_tutor_of_group(api_get_user_id(), $group_id) OR api_is_allowed_to_edit(false,true)  && !(api_is_course_coach() && $current_forum['session_id']!=$_SESSION['id_session'])) {
                 echo "<a href=\"".api_get_self()."?".api_get_cidreq()."&amp;gidReq=".Security::remove_XSS($_GET['gidReq'])."&amp;forum=".$clean_forum_id."&amp;thread=".$clean_thread_id."&amp;action=delete&amp;content=post&amp;id=".$row['post_id']."&amp;origin=".$origin."\" onclick=\"javascript:if(!confirm('".addslashes(api_htmlentities(get_lang('DeletePost'), ENT_QUOTES))."')) return false;\">".Display::return_icon('delete.png', get_lang('Delete'),array(),  22)."</a>";
+            }
+            if (api_is_allowed_to_edit(false,true)  && !(api_is_course_coach() && $current_forum['session_id']!=$_SESSION['id_session'])) {
                 display_visible_invisible_icon('post', $row['post_id'], $row['visible'],array('forum'=>$clean_forum_id,'thread'=>$clean_thread_id, 'origin'=>$origin ));
                 echo "";
                 if ($increment>0) {

+ 51 - 39
main/group/group.php

@@ -268,42 +268,51 @@ foreach ($group_cats as $index => $category) {
 			} else {
 				$row[] = $this_group['name'].'<br />'.stripslashes(trim($this_group['description']));
 			}
-			// Self-registration / unregistration
-			if (!api_is_allowed_to_edit(false, true)) {
-				if (GroupManager :: is_self_registration_allowed($_user['user_id'], $this_group['id'])) {
-					$row[] = '<a href="group.php?'.api_get_cidreq().'&category='.$category['id'].'&amp;action=self_reg&amp;group_id='.$this_group['id'].'" onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES, $charset))."'".')) return false;">'.get_lang('GroupSelfRegInf').'</a>';
-				} elseif (GroupManager :: is_self_unregistration_allowed($_user['user_id'], $this_group['id'])) {
-					$row[] = '<a href="group.php?'.api_get_cidreq().'&category='.$category['id'].'&amp;action=self_unreg&amp;group_id='.$this_group['id'].'" onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES, $charset))."'".')) return false;">'.get_lang('GroupSelfUnRegInf').'</a>';
-				} else {
-					$row[] = '-';
-				}
-			}
+            
+            
+            
+            // Tutor name
+            $tutor_info = '';
+
+            if (count($tutorsids_of_group) > 0) {
+                foreach ($tutorsids_of_group as $tutor_id) {
+                    $tutor = api_get_user_info($tutor_id);
+                    if (api_get_setting('show_email_addresses') == 'true') {
+                        $tutor_info .= Display::encrypted_mailto_link($tutor['mail'], api_get_person_name($tutor['firstName'], $tutor['lastName'])).', ';
+                    } else {
+                        if (api_is_allowed_to_edit()) {
+                            $tutor_info .= Display::encrypted_mailto_link($tutor['mail'], api_get_person_name($tutor['firstName'], $tutor['lastName'])).', ';
+                        } else {
+                            $tutor_info .= api_get_person_name($tutor['firstName'], $tutor['lastName']).', ';
+                        }
+                    }
+                }
+            }
+            $tutor_info = api_substr($tutor_info, 0, api_strlen($tutor_info) - 2);
+            $row[] = $tutor_info;
+            
+		
+            // Max number of members in group
+            $max_members = ($this_group['maximum_number_of_members'] == MEMBER_PER_GROUP_NO_LIMIT ? '-' : $this_group['maximum_number_of_members']);
+            
+            
 			// Number of members in group
-			$row[] = $this_group['number_of_members'];
-			// Max number of members in group
-			$row[] = ($this_group['maximum_number_of_members'] == MEMBER_PER_GROUP_NO_LIMIT ? '-' : $this_group['maximum_number_of_members']);
-			// Tutor name
-			$tutor_info = '';
-
-			if (count($tutorsids_of_group) > 0) {
-				foreach ($tutorsids_of_group as $tutor_id) {
-					$tutor = api_get_user_info($tutor_id);
-					if (api_get_setting('show_email_addresses') == 'true') {
-						$tutor_info .= Display::encrypted_mailto_link($tutor['mail'], api_get_person_name($tutor['firstName'], $tutor['lastName'])).', ';
-					} else {
-						if (api_is_allowed_to_edit()) {
-							$tutor_info .= Display::encrypted_mailto_link($tutor['mail'], api_get_person_name($tutor['firstName'], $tutor['lastName'])).', ';
-						} else {
-							$tutor_info .= api_get_person_name($tutor['firstName'], $tutor['lastName']).', ';
-						}
-					}
-				}
-			}
-			$tutor_info = api_substr($tutor_info, 0, api_strlen($tutor_info) - 2);
-			$row[] = $tutor_info;
+			$row[] = $this_group['number_of_members'].'/'.$max_members;
+			
+                // Self-registration / unregistration
+            if (!api_is_allowed_to_edit(false, true)) {
+                if (GroupManager :: is_self_registration_allowed($_user['user_id'], $this_group['id'])) {
+                    $row[] = '<a class = "a_button gray small" href="group.php?'.api_get_cidreq().'&category='.$category['id'].'&amp;action=self_reg&amp;group_id='.$this_group['id'].'" onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES, $charset))."'".')) return false;">'.get_lang('GroupSelfRegInf').'</a>';
+                } elseif (GroupManager :: is_self_unregistration_allowed($_user['user_id'], $this_group['id'])) {
+                    $row[] = '<a class = "a_button gray small" href="group.php?'.api_get_cidreq().'&category='.$category['id'].'&amp;action=self_unreg&amp;group_id='.$this_group['id'].'" onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES, $charset))."'".')) return false;">'.get_lang('GroupSelfUnRegInf').'</a>';
+                } else {
+                    $row[] = '-';
+                }
+            }
+
 			// Edit-links
 			if (api_is_allowed_to_edit(false, true)  && !(api_is_course_coach() && intval($this_group['session_id']) != intval($_SESSION['id_session']))) {
-				$edit_actions = '<a href="group_edit.php?'.api_get_cidreq().'&gidReq='.$this_group['id'].'"  title="'.get_lang('Edit').'">'.Display::return_icon('settings.png', get_lang('EditGroup'),'','22').'</a>&nbsp;';								
+				$edit_actions = '<a href="group_edit.php?'.api_get_cidreq().'&gidReq='.$this_group['id'].'"  title="'.get_lang('Edit').'">'.Display::return_icon('edit.png', get_lang('EditGroup'),'','22').'</a>&nbsp;';								
 				$edit_actions .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&category='.$category['id'].'&amp;action=empty_one&amp;id='.$this_group['id'].'" onclick="javascript: if(!confirm('."'".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES))."'".')) return false;" title="'.get_lang('EmptyGroup').'">'.Display::return_icon('clean.png',get_lang('EmptyGroup'),'','22').'</a>&nbsp;';				
 				$edit_actions .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&category='.$category['id'].'&amp;action=fill_one&amp;id='.$this_group['id'].'" onclick="javascript: if(!confirm('."'".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES))."'".')) return false;" title="'.get_lang('FillGroup').'">'.Display::return_icon('fill.png',get_lang('FillGroup'),'','22').'</a>&nbsp;';
 				$edit_actions .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&category='.$category['id'].'&amp;action=delete_one&amp;id='.$this_group['id'].'" onclick="javascript: if(!confirm('."'".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES))."'".')) return false;" title="'.get_lang('Delete').'">'.Display::return_icon('delete.png', get_lang('Delete'),'','22').'</a>&nbsp;';
@@ -327,13 +336,16 @@ foreach ($group_cats as $index => $category) {
 		if (api_is_allowed_to_edit(false, true) and count($group_list) > 1) {
 			$table->set_header($column++, '', false);
 		}
-		$table->set_header($column++, get_lang('ExistingGroups'));
+		$table->set_header($column++, get_lang('Groups'));
+        $table->set_header($column++, get_lang('GroupTutor'));
+        		
+		$table->set_header($column++, get_lang('Registered'), false);
+		
 		if (!api_is_allowed_to_edit(false, true)) { // If self-registration allowed
-			$table->set_header($column++, get_lang('GroupSelfRegistration'));
-		}
-		$table->set_header($column++, get_lang('Registered'));
-		$table->set_header($column++, get_lang('MaximumOfParticipants'));
-		$table->set_header($column++, get_lang('GroupTutor'));
+            $table->set_header($column++, get_lang('GroupSelfRegistration'), false);
+        }
+		//$table->set_header($column++, get_lang('MaximumOfParticipants'));
+		
 		if (api_is_allowed_to_edit(false, true)) { // Only for course administrator
 			$table->set_header($column++, get_lang('Modify'), false);
 			$form_actions = array();

+ 2 - 1
main/group/group_creation.php

@@ -161,7 +161,7 @@ elseif (isset($_POST['number_of_groups'])) {
 
 EOT;
 		$renderer->setElementTemplate($element_template);
-		$form->addElement('header', '', $nameTools);
+		//$form->addElement('header', '', $nameTools);
 
 		$form->addElement('hidden', 'action');
 		$form->addElement('hidden', 'number_of_groups');
@@ -216,6 +216,7 @@ EOT;
 		$defaults['number_of_groups'] = intval($_POST['number_of_groups']);
 		$form->setDefaults($defaults);
 		$form->addElement('style_submit_button', 'submit', get_lang('CreateGroup'), 'class="save"');
+        echo Display::tag('h2',$nameTools);
 		$form->display();
 	}
 } else {

+ 40 - 23
main/group/group_edit.php

@@ -143,43 +143,60 @@ $form->addGroup($group, 'max_member_group', null, '', false);
 $form->addRule('max_member_group', get_lang('InvalidMaxNumberOfMembers'), 'callback', 'check_max_number_of_members');
 
 // Self registration
-$form->addElement('checkbox', 'self_registration_allowed', get_lang('GroupSelfRegistration'), get_lang('GroupAllowStudentRegistration'), 1);
-$form->addElement('checkbox', 'self_unregistration_allowed', null, get_lang('GroupAllowStudentUnregistration'), 1);
+$group = array();
+$group[] = $form->createElement('checkbox', 'self_registration_allowed', get_lang('GroupSelfRegistration'), get_lang('GroupAllowStudentRegistration'), 1);
+$group[] = $form->createElement('checkbox', 'self_unregistration_allowed', null, get_lang('GroupAllowStudentUnregistration'), 1);
+$form->addGroup($group, '', get_lang('GroupSelfRegistration'), '<div></div>', false);
 
 // Documents settings
-$form->addElement('radio', 'doc_state', get_lang('GroupDocument'), get_lang('NotAvailable'), TOOL_NOT_AVAILABLE);
-$form->addElement('radio', 'doc_state', null, get_lang('Public'), TOOL_PUBLIC);
-$form->addElement('radio', 'doc_state', null, get_lang('Private'), TOOL_PRIVATE);
+$group = array();
+$group[] = $form->createElement('radio', 'doc_state', get_lang('GroupDocument'), get_lang('NotAvailable'), TOOL_NOT_AVAILABLE);
+$group[] = $form->createElement('radio', 'doc_state', null, get_lang('Public'), TOOL_PUBLIC);
+$group[] = $form->createElement('radio', 'doc_state', null, get_lang('Private'), TOOL_PRIVATE);
+$form->addGroup($group, '', get_lang('GroupDocument'), '<div></div>', false);
 
 // Work settings
-$form->addElement('radio', 'work_state', get_lang('GroupWork'), get_lang('NotAvailable'), TOOL_NOT_AVAILABLE);
-$form->addElement('radio', 'work_state', null, get_lang('Public'), TOOL_PUBLIC);
-$form->addElement('radio', 'work_state', null, get_lang('Private'), TOOL_PRIVATE);
+$group = array();
+$group[] = $form->createElement('radio', 'work_state', get_lang('GroupWork'), get_lang('NotAvailable'), TOOL_NOT_AVAILABLE);
+$group[] = $form->createElement('radio', 'work_state', null, get_lang('Public'), TOOL_PUBLIC);
+$group[] = $form->createElement('radio', 'work_state', null, get_lang('Private'), TOOL_PRIVATE);
+$form->addGroup($group, '', get_lang('GroupWork'), '<div></div>', false);
+
 
 // Calendar settings
-$form->addElement('radio', 'calendar_state', get_lang('GroupCalendar'), get_lang('NotAvailable'), TOOL_NOT_AVAILABLE);
-$form->addElement('radio', 'calendar_state', null, get_lang('Public'), TOOL_PUBLIC);
-$form->addElement('radio', 'calendar_state', null, get_lang('Private'), TOOL_PRIVATE);
+$group = array();
+$group[] = $form->createElement('radio', 'calendar_state', get_lang('GroupCalendar'), get_lang('NotAvailable'), TOOL_NOT_AVAILABLE);
+$group[] = $form->createElement('radio', 'calendar_state', null, get_lang('Public'), TOOL_PUBLIC);
+$group[] = $form->createElement('radio', 'calendar_state', null, get_lang('Private'), TOOL_PRIVATE);
+$form->addGroup($group, '', get_lang('GroupCalendar'), '<div></div>', false);
 
 // Announcements settings
-$form->addElement('radio', 'announcements_state', get_lang('GroupAnnouncements'), get_lang('NotAvailable'), TOOL_NOT_AVAILABLE);
-$form->addElement('radio', 'announcements_state', null, get_lang('Public'), TOOL_PUBLIC);
-$form->addElement('radio', 'announcements_state', null, get_lang('Private'), TOOL_PRIVATE);
+$group = array();
+$group[] = $form->createElement('radio', 'announcements_state', get_lang('GroupAnnouncements'), get_lang('NotAvailable'), TOOL_NOT_AVAILABLE);
+$group[] = $form->createElement('radio', 'announcements_state', null, get_lang('Public'), TOOL_PUBLIC);
+$group[] = $form->createElement('radio', 'announcements_state', null, get_lang('Private'), TOOL_PRIVATE);
+$form->addGroup($group, '', get_lang('GroupAnnouncements'), '<div></div>', false);
 
 //Forum settings
-$form->addElement('radio', 'forum_state', get_lang('GroupForum'), get_lang('NotAvailable'), TOOL_NOT_AVAILABLE);
-$form->addElement('radio', 'forum_state', null, get_lang('Public'), TOOL_PUBLIC);
-$form->addElement('radio', 'forum_state', null, get_lang('Private'), TOOL_PRIVATE);
+$group = array();
+$group[] = $form->createElement('radio', 'forum_state', get_lang('GroupForum'), get_lang('NotAvailable'), TOOL_NOT_AVAILABLE);
+$group[] = $form->createElement('radio', 'forum_state', null, get_lang('Public'), TOOL_PUBLIC);
+$group[] = $form->createElement('radio', 'forum_state', null, get_lang('Private'), TOOL_PRIVATE);
+$form->addGroup($group, '', get_lang('GroupForum'), '<div></div>', false);
 
 // Wiki settings
-$form->addElement('radio', 'wiki_state', get_lang('GroupWiki'), get_lang('NotAvailable'), TOOL_NOT_AVAILABLE);
-$form->addElement('radio', 'wiki_state', null, get_lang('Public'), TOOL_PUBLIC);
-$form->addElement('radio', 'wiki_state', null, get_lang('Private'), TOOL_PRIVATE);
+$group = array();
+$group[] = $form->createElement('radio', 'wiki_state', get_lang('GroupWiki'), get_lang('NotAvailable'), TOOL_NOT_AVAILABLE);
+$group[] = $form->createElement('radio', 'wiki_state', null, get_lang('Public'), TOOL_PUBLIC);
+$group[] = $form->createElement('radio', 'wiki_state', null, get_lang('Private'), TOOL_PRIVATE);
+$form->addGroup($group, '', get_lang('GroupWiki'), '<div></div>', false);
 
 // Chat settings
-$form->addElement('radio', 'chat_state', get_lang('Chat'), get_lang('NotAvailable'), TOOL_NOT_AVAILABLE);
-$form->addElement('radio', 'chat_state', null, get_lang('Public'), TOOL_PUBLIC);
-$form->addElement('radio', 'chat_state', null, get_lang('Private'), TOOL_PRIVATE);
+$group = array();
+$group[] = $form->createElement('radio', 'chat_state', get_lang('Chat'), get_lang('NotAvailable'), TOOL_NOT_AVAILABLE);
+$group[] = $form->createElement('radio', 'chat_state', null, get_lang('Public'), TOOL_PUBLIC);
+$group[] = $form->createElement('radio', 'chat_state', null, get_lang('Private'), TOOL_PRIVATE);
+$form->addGroup($group, '', get_lang('Chat'), '<div></div>', false);
 
 // Search Members of group
 //$form = new FormValidator('search_member', 'get', 'group_edit', '', null, false);

+ 34 - 25
main/group/group_overview.php

@@ -78,38 +78,47 @@ if (!isset ($_GET['origin']) || $_GET['origin'] != 'learnpath') {
 
 // Action links
 echo '<div class="actions">';
-echo '<a href="group_creation.php?'.api_get_cidreq().'">'.Display::return_icon('new_group.png', get_lang('NewGroupCreate'),'','32').'</a>';
-echo '<a href="group.php?'.api_get_cidreq().'">'.Display::return_icon('group.png', get_lang('Groups'),'','32').'</a>';
-if (api_get_setting('allow_group_categories') == 'true') {
-	echo '<a href="group_category.php?'.api_get_cidreq().'&action=add_category">'.Display::return_icon('new_folder.png', get_lang('AddCategory'),'','32').'</a>';
-} else {
-	//echo '<a href="group_category.php?'.api_get_cidreq().'&id=2">'.Display::return_icon('edit_group.gif').'&nbsp;'.get_lang('PropModify').'</a>&nbsp;';
-	echo '<a href="group_category.php?'.api_get_cidreq().'&id=2">'.Display::return_icon('settings.png', get_lang('PropModify'),'','32').'</a>';
-}
-//echo Display::return_icon('csv.gif', get_lang('ExportAsCSV')).'<a href="group_overview.php?'.api_get_cidreq().'&action=export&type=csv">'.get_lang('ExportAsCSV').'</a> ';
-echo '<a href="group_overview.php?'.api_get_cidreq().'&action=export&type=xls">'.Display::return_icon('export_excel.png', get_lang('ExportAsXLS'),'','32').'</a>';
+    echo '<a href="group_creation.php?'.api_get_cidreq().'">'.Display::return_icon('new_group.png', get_lang('NewGroupCreate'),'','32').'</a>';
+    echo '<a href="group.php?'.api_get_cidreq().'">'.Display::return_icon('group.png', get_lang('Groups'),'','32').'</a>';
+    if (api_get_setting('allow_group_categories') == 'true') {
+    	echo '<a href="group_category.php?'.api_get_cidreq().'&action=add_category">'.Display::return_icon('new_folder.png', get_lang('AddCategory'),'','32').'</a>';
+    } else {
+    	//echo '<a href="group_category.php?'.api_get_cidreq().'&id=2">'.Display::return_icon('edit_group.gif').'&nbsp;'.get_lang('PropModify').'</a>&nbsp;';
+    	echo '<a href="group_category.php?'.api_get_cidreq().'&id=2">'.Display::return_icon('settings.png', get_lang('PropModify'),'','32').'</a>';
+    }
+    //echo Display::return_icon('csv.gif', get_lang('ExportAsCSV')).'<a href="group_overview.php?'.api_get_cidreq().'&action=export&type=csv">'.get_lang('ExportAsCSV').'</a> ';
+    echo '<a href="group_overview.php?'.api_get_cidreq().'&action=export&type=xls">'.Display::return_icon('export_excel.png', get_lang('ExportAsXLS'),'','32').'</a>';
 echo '</div>';
 
 $categories = GroupManager::get_categories();
+
 foreach ($categories as $index => $category) {
 	if (api_get_setting('allow_group_categories') == 'true') {
-		echo '<h3>'.$category['title'].'</h3>';
+		echo '<h2>'.$category['title'].'</h2>';
 	}
 	$groups = GroupManager::get_group_list($category['id']);
-	echo '<ul>';
-	foreach ($groups as $index => $group) {
-		echo '<li>';
-		echo stripslashes($group['name']);
-		echo '<ul>';
-		$users = GroupManager::get_users($group['id']);
-		foreach ($users as $index => $user) {
-			$user_info = api_get_user_info($user);
-			echo '<li>'.api_get_person_name($user_info['firstName'], $user_info['lastName']).'</li>';
-		}
-		echo '</ul>';
-		echo '</li>';
-	}
-	echo '</ul>';
+    echo '<ul>';
+	if (!empty($groups)) {    	
+    	foreach ($groups as $index => $group) {
+    		echo '<li>';
+        		echo Display::tag('h3', Security::remove_XSS($group['name']));
+        		echo '<ul>';
+        		$users = GroupManager::get_users($group['id']);
+                if (!empty($users)) {
+            		foreach ($users as $index => $user) {
+            			$user_info = api_get_user_info($user);
+            			echo '<li>'.api_get_person_name($user_info['firstName'], $user_info['lastName']).'</li>';
+            		}            	
+                } else {
+                    //echo Display::tag('li', get_lang('NoStudents'));            
+                }
+                echo '</ul>';
+    		echo '</li>';
+    	}    	
+    } else {        
+        //echo Display::tag('li', get_lang('NoData'));   
+    }    
+    echo '</ul>';
 }
 
 /*	FOOTER */

+ 17 - 11
main/group/group_space.php

@@ -80,26 +80,21 @@ if (!empty($_GET['selfUnReg']) && GroupManager :: is_self_unregistration_allowed
 }
 echo '<div class="actions">';
 echo '<a href="group.php">'.Display::return_icon('back.png',get_lang('BackToGroupList'),'','32').'</a>';
-/*
- * Edit the group
- */
-if (api_is_allowed_to_edit(false, true) or GroupManager :: is_tutor_of_group(api_get_user_id(), api_get_group_id())) {
-	$my_origin = isset($origin) ? $origin : '';
-	echo '<a href="group_edit.php?origin='.$my_origin.'&gidReq='.api_get_group_id().'">'.Display::return_icon('settings.png', get_lang('EditGroup'),'','32').'</a>';
-}
 
 /*
  * Register to group
  */
+$subscribe_group = '';
 if (GroupManager :: is_self_registration_allowed($_SESSION['_user']['user_id'], $current_group['id'])) {
-	echo '<a href="'.api_get_self().'?selfReg=1&amp;group_id='.$current_group['id'].'" onclick="javascript: if(!confirm('."'".addslashes(api_htmlentities(get_lang("ConfirmYourChoice"), ENT_QUOTES))."'".')) return false;">'.Display::return_icon('groupadd.gif').get_lang("RegIntoGroup").'</a>';
+	$subscribe_group = '<a class="a_button gray small" href="'.api_get_self().'?selfReg=1&amp;group_id='.$current_group['id'].'" onclick="javascript: if(!confirm('."'".addslashes(api_htmlentities(get_lang("ConfirmYourChoice"), ENT_QUOTES))."'".')) return false;">'.get_lang("RegIntoGroup").'</a>';
 }
 
 /*
  * Unregister from group
  */
+$unsubscribe_group = '';
 if (GroupManager :: is_self_unregistration_allowed($_SESSION['_user']['user_id'], $current_group['id'])) {
-	echo '<a href="'.api_get_self().'?selfUnReg=1" onclick="javascript: if(!confirm('."'".addslashes(api_htmlentities(get_lang("ConfirmYourChoice"),ENT_QUOTES))."'".')) return false;">'.Display::return_icon('group_delete.gif').get_lang("StudentUnsubscribe").'</a>';
+	$unsubscribe_group = '<a class="a_button gray small" href="'.api_get_self().'?selfUnReg=1" onclick="javascript: if(!confirm('."'".addslashes(api_htmlentities(get_lang("ConfirmYourChoice"),ENT_QUOTES))."'".')) return false;">'.get_lang("StudentUnsubscribe").'</a>';
 }
 echo '&nbsp;</div>';
 
@@ -119,10 +114,20 @@ $is_course_member = CourseManager :: is_user_subscribed_in_real_or_linked_course
 /*
  * Group title and comment
  */
-echo Display::tag('h2', stripslashes($current_group['name']));
+
+ /*
+ * Edit the group
+ */
+$edit_url = '';
+if (api_is_allowed_to_edit(false, true) or GroupManager :: is_tutor_of_group(api_get_user_id(), api_get_group_id())) {
+    $my_origin = isset($origin) ? $origin : '';
+    $edit_url =  '<a href="group_edit.php?origin='.$my_origin.'&gidReq='.api_get_group_id().'">'.Display::return_icon('edit.png', get_lang('EditGroup'),'','22').'</a>';
+}
+
+echo Display::tag('h2', Security::remove_XSS($current_group['name']).' '.$edit_url.' '.$subscribe_group.' '.$unsubscribe_group);
 
 if (!empty($current_group['description'])) {
-	echo '<p>'.stripslashes($current_group['description']).'</p>';
+	echo '<p>'.Security::remove_XSS($current_group['description']).'</p>';
 }
 
 /*
@@ -134,6 +139,7 @@ if (api_is_allowed_to_edit(false, true) OR GroupManager :: is_user_in_group(api_
 	$tools = '';
 	// Link to the forum of this group
 	$forums_of_groups = get_forums_of_group($current_group['id']);
+    
 	if (is_array($forums_of_groups)) {
 		if ($current_group['forum_state'] != TOOL_NOT_AVAILABLE ) {
 			foreach ($forums_of_groups as $key => $value) {

+ 26 - 3
main/inc/lib/add_course.lib.inc.php

@@ -297,6 +297,9 @@ function update_Db_course($course_db_name = null) {
     $TABLEQUIZQUESTIONLIST      = $course_db_name . 'quiz_question';
     $TABLEQUIZANSWERSLIST       = $course_db_name . 'quiz_answer';
     $TABLEQUIZQUESTIONOPTION    = $course_db_name . 'quiz_question_option';
+	
+	$table_quiz_question_category    	 = $course_db_name . 'quiz_question_category';
+	$table_quiz_question_rel_category    = $course_db_name . 'quiz_question_rel_category';
 
     // Dropbox
     $TABLETOOLDROPBOXPOST       = $course_db_name . 'dropbox_post';
@@ -646,6 +649,7 @@ function update_Db_course($course_db_name = null) {
         session_id smallint default 0,
         propagate_neg INT NOT NULL DEFAULT 0,
         review_answers INT NOT NULL DEFAULT 0,
+        random_by_category INT NOT NULL DEFAULT 0,
         PRIMARY KEY (c_id, id)
         )" . $charset_clause;
     Database::query($sql);
@@ -693,8 +697,6 @@ function update_Db_course($course_db_name = null) {
         )" . $charset_clause;
     Database::query($sql);
     
-    
-    
     // Exercise tool - answer options
     $sql = "
         CREATE TABLE `".$TABLEQUIZQUESTIONOPTION . "` (
@@ -718,7 +720,28 @@ function update_Db_course($course_db_name = null) {
         PRIMARY KEY (c_id, question_id,exercice_id)
         )" . $charset_clause;
     Database::query($sql);
-
+    
+    
+    
+    $sql = "CREATE TABLE `".$table_quiz_question_category . "` (
+	  $add_to_all_tables
+	  id int NOT NULL AUTO_INCREMENT,
+	  name varchar(255) NOT NULL,
+	  description text NOT NULL,
+	  PRIMARY KEY (c_id,id)
+	)" . $charset_clause;
+    Database::query($sql);
+    
+	
+	$sql = "CREATE TABLE `".$table_quiz_question_rel_category . "` (
+	  $add_to_all_tables	  
+	  question_id int NOT NULL,
+	  category_id int NOT NULL,
+	  PRIMARY KEY (c_id,question_id)
+    )" . $charset_clause;
+    Database::query($sql);
+    
+    
     /*        Course description	*/
 
     $sql = "

+ 3 - 0
main/inc/lib/database.constants.inc.php

@@ -15,6 +15,7 @@
  */
 
 //See #3910 defines the default prefix for the single course database
+// Modified by hubert.borderiou 2011-10-21 Add course category
 define('DB_COURSE_PREFIX', 'c_');
 
 // Main database tables
@@ -195,6 +196,8 @@ define('TABLE_QUIZ_TEST',           'quiz');
 define('TABLE_QUIZ_ANSWER',         'quiz_answer');
 define('TABLE_QUIZ_TEST_QUESTION',  'quiz_rel_question');
 define('TABLE_QUIZ_QUESTION_OPTION','quiz_question_option');
+define('TABLE_QUIZ_QUESTION_CATEGORY', 'quiz_question_category');
+define('TABLE_QUIZ_QUESTION_REL_CATEGORY', 'quiz_question_rel_category');
 
 // Linked resource table
 //@todo table exists?

+ 45 - 0
main/inc/lib/export.lib.inc.php

@@ -12,6 +12,8 @@
  * Code
  */
 require_once 'document.lib.php';
+require_once api_get_path(LIBRARY_PATH).'pdf.lib.php';
+
 /**
  *
  * @package chamilo.library
@@ -145,4 +147,47 @@ class Export {
         return $string;
     }
 
+    public static function export_table_pdf($data, $file_name = 'export', $header, $description) {
+        $headers = $data[0];
+        unset($data[0]);
+        $html = '';
+        
+        $headers_in_pdf = '<img src="'.api_get_path(WEB_CSS_PATH).api_get_setting('stylesheets').'/images/header-logo.png">';
+        
+        $html = '<br/><br/><table width="100%" cellspacing="1" cellpadding="5" border="0">                         
+                 <tr><td width="100%" style="text-align: center;" class="title" colspan="4"><h1>'.$header.'</h1></td></tr></table><br />';
+        $html .= $description.'<br />';
+        
+        $table = new HTML_Table(array('class' => 'data_table'));
+        $row = 0;
+        $column = 0;
+        foreach ($headers as $header) {
+            $table->setHeaderContents($row, $column, $header);
+            $column++;
+        }
+        $row++;
+ 
+        foreach ($data as &$printable_data_row) {
+            $column = 0;
+            foreach ($printable_data_row as &$printable_data_cell) {
+                $table->setCellContents($row, $column, $printable_data_cell);
+                $table->updateCellAttributes($row, $column);
+                $column++;
+            }
+            $table->updateRowAttributes($row, $row % 2 ? 'class="row_even"' : 'class="row_odd"', true);
+            $row++;
+        }
+       
+        $html .= $table->toHtml();        
+        $html  = api_utf8_encode($html);        
+        
+        $css_file = api_get_path(TO_SYS, WEB_CSS_PATH).api_get_setting('stylesheets').'/print.css';
+        $css = file_exists($css_file) ? @file_get_contents($css_file) : '';        
+        
+        $pdf = new PDF(); 
+        $pdf->set_custom_header($headers_in_pdf);       
+        $pdf->content_to_pdf($html, $css, $file_name, api_get_course_id());
+        exit;
+    }
+
 }

+ 10 - 0
main/inc/lib/fckeditor/toolbars/default/test_category.php

@@ -0,0 +1,10 @@
+<?php
+	$config['ToolbarSets']['Normal'] = array(	
+	array('Style','FontFormat','FontName','FontSize'),
+  '/',
+	array('Bold','Italic','Underline'),
+  array('SpecialChar', 'mimetex'),
+  array('OrderedList','UnorderedList','-','Outdent','Indent','-','TextColor','BGColor'),
+	array('JustifyLeft','JustifyCenter','JustifyRight','-','Source')
+);
+?>

+ 1 - 1
main/inc/lib/groupmanager.lib.php

@@ -205,7 +205,7 @@ class GroupManager {
 			//if the amount of users per group is not filled in, use the setting from the category
 			$places = $category['max_student'];
 		}
-		echo $sql = "INSERT INTO ".$table_group." SET
+		 $sql = "INSERT INTO ".$table_group." SET
 				c_id = $course_id , 
 				category_id='".Database::escape_string($category_id)."', 
 				max_student = '".$places."', 

+ 2 - 0
main/inc/lib/security.lib.php

@@ -282,6 +282,8 @@ class Security {
             $config->set('HTML.TidyLevel', 'light');
             $config->set('Core.ConvertDocumentToFragment', false);
             $config->set('Core.RemoveProcessingInstructions', true);
+            //Shows _target attribute in anchors
+            $config->set('Attr.AllowedFrameTargets', array('_blank','_top','_self', '_parent')); 
             if ($user_status == STUDENT) {
                 global $allowed_html_student;
                 $config->set('HTML.SafeEmbed', true);

+ 8 - 5
main/install/install.lib.php

@@ -1244,7 +1244,7 @@ function display_requirements($installType, $badUpdatePath, $updatePath = '', $u
 
     if ($installType == 'update' && (empty($updatePath) || $badUpdatePath)) {
         if ($badUpdatePath) { ?>
-            <div style="color:red; background-color:white; font-weight:bold; text-align:center;">
+            <div class="error-message">
                 <?php echo get_lang('Error'); ?>!<br />
                 Chamilo <?php echo (isset($_POST['step2_update_6']) ? implode('|', $update_from_version_6) : implode('|', $update_from_version_8)).' '.get_lang('HasNotBeenFoundInThatDir'); ?>.
             </div>
@@ -1326,15 +1326,18 @@ function display_requirements($installType, $badUpdatePath, $updatePath = '', $u
         //--> The user would have to adjust the permissions manually
         if (count($notwritable) > 0) {
             $error = true;
-            echo '<div style="color:red; background-color:white; font-weight:bold; text-align:center;">';
-            echo get_lang('Warning').':<br />';
-            printf(get_lang('NoWritePermissionPleaseReadInstallGuide'), '</font><a href="../../documentation/installation_guide.html" target="blank">', '</a> <font color="red">');
+            echo '<div class="error-message">';
+	            echo '<center><h3>'.get_lang('Warning').'</h3></center>';
+	            printf(get_lang('NoWritePermissionPleaseReadInstallGuide'), '</font>
+	            <a href="../../documentation/installation_guide.html" target="blank">', '</a> <font color="red">');
+			echo '</div>';
+				
             echo '<ul>';
             foreach ($notwritable as $value) {
                 echo '<li>'.$value.'</li>';
             }
             echo '</ul>';
-            echo '</div>';
+            
         }
 
         // Check wether a Chamilo configuration file already exists.

+ 1 - 0
main/install/migrate-db-1.8.8-1.9.0-pre.sql

@@ -128,4 +128,5 @@ INSERT INTO course_setting(variable,value,category) VALUES ('course_grading_mode
 ALTER TABLE quiz ADD COLUMN review_answers INT NOT NULL DEFAULT 0;
 ALTER TABLE student_publication ADD COLUMN contains_file INTEGER NOT NULL DEFAULT 1;
 ALTER TABLE student_publication ADD COLUMN allow_text_assignment INTEGER NOT NULL DEFAULT 0;
+ALTER TABLE quiz ADD COLUMN random_by_category INT NOT NULL DEFAULT 0;
 

+ 84 - 37
main/user/user.php

@@ -59,6 +59,7 @@ if (!api_is_platform_admin(true)) {
 $currentCourseID 		= Database::escape_string($_course['sysCode']);
 $is_western_name_order 	= api_is_western_name_order();
 $sort_by_first_name 	= api_sort_by_first_name();
+$course_info            = api_get_course_info();
 
 /* Unregistering a user section	*/
 if (api_is_allowed_to_edit(null, true)) {
@@ -82,10 +83,9 @@ if (api_is_allowed_to_edit(null, true)) {
 	if ( isset ($_GET['action'])) {
 		switch ($_GET['action']) {
 			case 'export' :
-				$table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
-				$table_users = Database::get_main_table(TABLE_MAIN_USER);
-				$session_id = 0;
-				$is_western_name_order = api_is_western_name_order(PERSON_NAME_DATA_EXPORT);
+				$table_course_user      = Database::get_main_table(TABLE_MAIN_COURSE_USER);
+				$table_users            = Database::get_main_table(TABLE_MAIN_USER);				
+				$is_western_name_order  = api_is_western_name_order();
 
 				$data = array();
 				$a_users = array();
@@ -98,12 +98,21 @@ if (api_is_allowed_to_edit(null, true)) {
 				
 				$extra_fields = UserManager::get_extra_user_data(api_get_user_id(), false, false, false, true);
 				$extra_fields = array_keys($extra_fields);
+                
 				if ($sort_by_first_name) {
 					$a_users[0] = array(get_lang('FirstName'), get_lang('LastName'), get_lang('Email'), get_lang('Phone'), get_lang('OfficialCode'), get_lang('Active'));
 				} else {
 					$a_users[0] = array(get_lang('LastName'), get_lang('FirstName'), get_lang('Email'), get_lang('Phone'), get_lang('OfficialCode'), get_lang('Active'));
 				}
-				$a_users[0] = array_merge($a_users[0],$extra_fields);
+                
+                if ($_GET['type'] == 'pdf') {
+                    if ($is_western_name_order) {                        
+                        $a_users[0] = array('#', get_lang('OfficialCode'), get_lang('FirstName').', '.get_lang('LastName'));
+                    } else {
+                        $a_users[0] = array('#', get_lang('OfficialCode'), get_lang('LastName').', '.get_lang('FirstName'));
+                    }
+                }
+				$a_users[0] = array_merge($a_users[0], $extra_fields);
 								
 				// users subscribed to the course through a session
 				if (api_get_setting('use_session_mode') == 'true') {
@@ -119,12 +128,13 @@ if (api_is_allowed_to_edit(null, true)) {
 						
 						if ($_configuration['multiple_access_urls']) {				
 							$sql_query .= " AND user.user_id = au.user_id AND access_url_id =  $current_access_url_id  ";
-						}					
-						
+						}
+                        
 						$sql_query .= $sort_by_first_name ? ' ORDER BY user.firstname, user.lastname' : ' ORDER BY user.lastname, user.firstname';
 						
 						$rs = Database::query($sql_query);
-						
+						$counter = 1;
+                        
 						while ($user = Database:: fetch_array($rs, 'ASSOC')) {
 							$extra_fields = UserManager::get_extra_user_data($user['user_id'], false, false, false, true);
 							if (!empty($extra_fields)) {
@@ -133,13 +143,24 @@ if (api_is_allowed_to_edit(null, true)) {
 								}
 							}
 							unset($user['user_id']);
-							$data[] = $user;							
-							$a_users[] = $user;
+							$data[] = $user;			
+                            if ($_GET['type'] == 'pdf') {
+                                if ($is_western_name_order) {
+                                    $user_pdf = array($counter, $user['official_code'], $user['firstname'].', '.$user['lastname'] );
+                                } else {
+                                    $user_pdf = array($counter, $user['official_code'], $user['lastname'].', '.$user['firstname'] );
+                                }
+                                $a_users[] = $user_pdf;
+                            } else {				
+                                $a_users[] = $user;
+                            }
+                            $counter++;
 						}
 					}
 				}
 
 				if ($session_id == 0) {
+				    
 					// users directly subscribed to the course
 					$table_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
 					$sql_query = "SELECT DISTINCT user.user_id, ".($is_western_name_order ? "user.firstname, user.lastname" : "user.lastname, user.firstname").", user.email, phone, user.official_code, active
@@ -152,9 +173,11 @@ if (api_is_allowed_to_edit(null, true)) {
 					if ($_configuration['multiple_access_urls']) {							
 						$sql_query .= " AND user.user_id = au.user_id  AND access_url_id =  $current_access_url_id  ";
 					}
+                    
 					$sql_query .= ($sort_by_first_name ? "ORDER BY user.firstname, user.lastname" : "ORDER BY user.lastname, user.firstname");
 					
 					$rs = Database::query($sql_query);
+                    $counter = 1;
 					while ($user = Database::fetch_array($rs, 'ASSOC')) {
 						$extra_fields = UserManager::get_extra_user_data($user['user_id'], false, false, false, true);
 						if (!empty($extra_fields)) {						
@@ -162,9 +185,19 @@ if (api_is_allowed_to_edit(null, true)) {
 								$user[$key] = $extra_value;
 							}
 						}
-						unset($user['user_id']);						
-						$data[] = $user;						
-						$a_users[] = $user;
+						unset($user['user_id']);
+                        if ($_GET['type'] == 'pdf') {
+                            if ($is_western_name_order) {
+                                $user_pdf = array($counter, $user['official_code'], $user['firstname'].', '.$user['lastname'] );
+                            } else {
+                                $user_pdf = array($counter, $user['official_code'], $user['lastname'].', '.$user['firstname'] );
+                            }
+                            $a_users[] = $user_pdf;
+                        } else {                
+                            $a_users[] = $user;
+                        }                            			
+						$data[] = $user;											
+						$counter++;
 					}										
 				}		
 				
@@ -175,6 +208,18 @@ if (api_is_allowed_to_edit(null, true)) {
 					case 'xls' :
 						Export::export_table_xls($a_users);
 						exit;
+					case 'pdf' :
+					   $header = get_lang('UserList');
+					   $description = '<table class="data_table_no_border">';  
+                       if (api_get_session_id()) {                     
+					       $description .= '<tr><td>'.get_lang('Session').': </td><td class="highlight">'.api_get_session_name(api_get_session_id()).'</td>';
+                       }
+					   $description .= '<tr><td>'.get_lang('Course').': </td><td class="highlight">'.$course_info['name'].'</td>';
+					   $description .= '<tr><td>'.get_lang('Teachers').': </td><td class="highlight">'.CourseManager::get_teacher_list_from_course_code_to_string($course_info['code']).'</td>';
+					   $description .= '<tr><td>'.get_lang('Date').': </td><td class="highlight">'.api_convert_and_format_date(time(), DATE_TIME_FORMAT_LONG).'</td>';
+                       $description .= '</table>';                        
+                       Export::export_table_pdf($a_users, get_lang('UserList'), $header, $description);
+                       exit;
 				}
 		}
 	}
@@ -339,7 +384,10 @@ if ( api_is_allowed_to_edit(null, true)) {
             $actions .= "<a href=\"subscribe_user.php?".api_get_cidreq()."&type=teacher\">".Display::return_icon('teacher_subscribe_course.png', get_lang("SubscribeUserToCourseAsTeacher"),'','32')."</a> ";
         }
 		$actions .= '<a href="user.php?'.api_get_cidreq().'&action=export&amp;type=csv">'.Display::return_icon('export_csv.png', get_lang('ExportAsCSV'),'','32').'</a> ';
-	$actions .= '<a href="user.php?'.api_get_cidreq().'&action=export&amp;type=xls">'.Display::return_icon('export_excel.png', get_lang('ExportAsXLS'),'','32').'</a> ';
+	    $actions .= '<a href="user.php?'.api_get_cidreq().'&action=export&amp;type=xls">'.Display::return_icon('export_excel.png', get_lang('ExportAsXLS'),'','32').'</a> ';      
+        
+        $actions .= '<a href="user.php?'.api_get_cidreq().'&action=export&type=pdf">'.Display::return_icon('pdf.png', get_lang('ExportToPDF'),'','32').'</a> ';
+        
 		$actions .= "<a href=\"../group/group.php?".api_get_cidreq()."\">".Display::return_icon('group.png', get_lang("GroupUserManagement"),'','32')."</a>";
 		
 	if (api_get_setting('use_session_mode') == 'false') {
@@ -412,7 +460,6 @@ function search_keyword($firstname, $lastname, $username, $official_code, $keywo
 	} else {
 		return false;
 	}
-	
 }
 
 
@@ -585,16 +632,16 @@ function modify_filter($user_id) {
 	}
 
 	if (api_is_allowed_to_edit(null, true)) {
-                if (api_get_setting('allow_user_course_subscription_by_course_admin') == 'true') {
-                    // edit
-                    $result .= '<a href="userInfo.php?'.api_get_cidreq().'&origin='.$origin.'&amp;editMainUserInfo='.$user_id.'" title="'.get_lang('Edit').'" >'.Display::return_icon('edit.png', get_lang('Edit'),'','22').'</a>&nbsp;';
-                    // unregister
-                    if ($user_id != $_user['user_id']) {
-                            $result .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&unregister=yes&amp;user_id='.$user_id.'" title="'.get_lang('Unreg').' " onclick="javascript:if(!confirm(\''.addslashes(api_htmlentities(get_lang('ConfirmYourChoice'),ENT_QUOTES,$charset)).'\')) return false;">'.Display::return_icon('unsubscribe_course.png', get_lang('Unreg'),'','22').'</a>&nbsp;';
-                    } else {
-                            $result .= Display::return_icon('unsubscribe_course_na.png', get_lang('Unreg'),'','22').'</a>&nbsp;';
-                    }
-                }
+        if (api_get_setting('allow_user_course_subscription_by_course_admin') == 'true') {
+            // edit
+            $result .= '<a href="userInfo.php?'.api_get_cidreq().'&origin='.$origin.'&amp;editMainUserInfo='.$user_id.'" title="'.get_lang('Edit').'" >'.Display::return_icon('edit.png', get_lang('Edit'),'','22').'</a>&nbsp;';
+            // unregister
+            if ($user_id != $_user['user_id']) {
+                    $result .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&unregister=yes&amp;user_id='.$user_id.'" title="'.get_lang('Unreg').' " onclick="javascript:if(!confirm(\''.addslashes(api_htmlentities(get_lang('ConfirmYourChoice'),ENT_QUOTES,$charset)).'\')) return false;">'.Display::return_icon('unsubscribe_course.png', get_lang('Unreg'),'','22').'</a>&nbsp;';
+            } else {
+                    $result .= Display::return_icon('unsubscribe_course_na.png', get_lang('Unreg'),'','22').'</a>&nbsp;';
+            }
+        }
 	}
 	$result .= "</div>";
 	return $result;
@@ -609,9 +656,9 @@ $table->set_additional_parameters($parameters);
 $header_nr = 0;
 
 if (api_is_allowed_to_edit(null, true)) {
-        if (api_get_setting('allow_user_course_subscription_by_course_admin') == 'true') {
-            $table->set_header($header_nr++, '', false);
-        }
+    if (api_get_setting('allow_user_course_subscription_by_course_admin') == 'true') {
+        $table->set_header($header_nr++, '', false);
+    }
 }
 $table->set_header($header_nr++, get_lang('Photo'), false);
 $table->set_header($header_nr++, get_lang('OfficialCode'));
@@ -625,24 +672,24 @@ if ($is_western_name_order) {
 }
 $table->set_header($header_nr++, get_lang('Description'), false);
 $table->set_header($header_nr++, get_lang('GroupSingle'), false);
-
+        
 if (api_is_allowed_to_edit(null, true)) {
 	// deprecated feature
 	//$table->set_header($header_nr++, get_lang('Tutor'), false);
 	$table->set_header($header_nr++, get_lang('Status'), false);
 	$table->set_header($header_nr++, get_lang('Active'), false);
-        if (api_get_setting('allow_user_course_subscription_by_course_admin') == 'true') {
-            $table->set_column_filter(8, 'active_filter');
-        } else {
-            $table->set_column_filter(7, 'active_filter');
-        }
+    if (api_get_setting('allow_user_course_subscription_by_course_admin') == 'true') {
+        $table->set_column_filter(8, 'active_filter');
+    } else {
+        $table->set_column_filter(7, 'active_filter');
+    }
 	//actions column
 	$table->set_header($header_nr++, get_lang('Action'), false);
 	$table->set_column_filter($header_nr-1, 'modify_filter');
 
-        if (api_get_setting('allow_user_course_subscription_by_course_admin') == 'true') {
-            $table->set_form_actions(array('unsubscribe' => get_lang('Unreg')), 'user');
-        }
+    if (api_get_setting('allow_user_course_subscription_by_course_admin') == 'true') {
+        $table->set_form_actions(array('unsubscribe' => get_lang('Unreg')), 'user');
+    }
 }
 
 $table->display();