Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -r0144e9d0f7fc574a887933024183a8a9049bc414 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 Binary files differ Index: lams_central/src/java/org/lamsfoundation/lams/authoring/ObjectExtractor.java =================================================================== diff -u -r0144e9d0f7fc574a887933024183a8a9049bc414 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_central/src/java/org/lamsfoundation/lams/authoring/ObjectExtractor.java (.../ObjectExtractor.java) (revision 0144e9d0f7fc574a887933024183a8a9049bc414) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/ObjectExtractor.java (.../ObjectExtractor.java) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -1481,21 +1481,23 @@ private void parseAnnotations(JSONArray annotationList) throws ObjectExtractorException, JSONException { Set existingAnnotations = learningDesign.getAnnotations(); + if (existingAnnotations == null) { + existingAnnotations = new HashSet(); + learningDesign.setAnnotations(existingAnnotations); + } Set updatedAnnotations = new HashSet(); for (int annotationIndex = 0; annotationIndex < annotationList.length(); annotationIndex++) { JSONObject annotationJSON = annotationList.getJSONObject(annotationIndex); boolean found = false; LearningDesignAnnotation annotation = null; - if (existingAnnotations != null) { - for (LearningDesignAnnotation existingAnnotation : existingAnnotations) { - if (existingAnnotation.getAnnotationUIID().equals( - annotationJSON.getInt(AuthoringJsonTags.ANNOTATION_UIID))) { - annotation = existingAnnotation; - found = true; - break; - } + for (LearningDesignAnnotation existingAnnotation : existingAnnotations) { + if (existingAnnotation.getAnnotationUIID().equals( + annotationJSON.getInt(AuthoringJsonTags.ANNOTATION_UIID))) { + annotation = existingAnnotation; + found = true; + break; } } @@ -1520,7 +1522,8 @@ updatedAnnotations.add(annotation); } - learningDesign.setAnnotations(updatedAnnotations); + learningDesign.getAnnotations().clear(); + learningDesign.getAnnotations().addAll(updatedAnnotations); } private Competence getComptenceFromSet(Set competences, String title) { @@ -2244,6 +2247,8 @@ throws JSONException { activity.setGateStartTimeOffset(JsonUtil.optLong(activityDetails, AuthoringJsonTags.GATE_START_OFFSET)); activity.setGateEndTimeOffset(JsonUtil.optLong(activityDetails, AuthoringJsonTags.GATE_END_OFFSET)); + activity.setGateActivityCompletionBased((Boolean) JsonUtil.opt(activityDetails, + AuthoringJsonTags.GATE_ACTIVITY_COMPLETION_BASED)); SystemTool systemTool = getSystemTool(SystemTool.SCHEDULE_GATE); activity.setSystemTool(systemTool); } Index: lams_central/web/author2.jsp =================================================================== diff -u -r0144e9d0f7fc574a887933024183a8a9049bc414 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_central/web/author2.jsp (.../author2.jsp) (revision 0144e9d0f7fc574a887933024183a8a9049bc414) +++ lams_central/web/author2.jsp (.../author2.jsp) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -341,15 +341,15 @@ Title: - + Type: - + + + + Delay: + + + days + + + hours + + + minutes + + + + + Since learner finished previous activity? + + + + + Index: lams_central/web/css/authoring.css =================================================================== diff -u -r9fb16007bc803d29180994effaed30ebb0a2e561 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_central/web/css/authoring.css (.../authoring.css) (revision 9fb16007bc803d29180994effaed30ebb0a2e561) +++ lams_central/web/css/authoring.css (.../authoring.css) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -43,6 +43,10 @@ width: 40px; } +tr.propertiesContentRowGateSchedule input.spinner { + width: 30px; +} + input.propertiesContentFieldTitle { width: 98%; } Index: lams_central/web/includes/javascript/authoring/authoringActivity.js =================================================================== diff -u -r0144e9d0f7fc574a887933024183a8a9049bc414 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision 0144e9d0f7fc574a887933024183a8a9049bc414) +++ lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -79,10 +79,19 @@ /** * Constructor for a Gate Activity. */ - GateActivity : function(id, uiid, x, y, gateType) { + GateActivity : function(id, uiid, x, y, gateType, startTimeOffset, gateActivityCompletionBased) { this.id = +id; this.uiid = +uiid || ++layout.ld.maxUIID; this.gateType = gateType || 'permission'; + if (gateType == 'schedule') { + var day = 24*60; + this.offsetDay = Math.floor(startTimeOffset/day); + startTimeOffset -= this.offsetDay * day; + this.offsetHour = Math.floor(startTimeOffset/60); + this.offsetMinute = startTimeOffset - this.offsetHour * 60; + + this.gateActivityCompletionBased = gateActivityCompletionBased; + }; this.transitions = { 'from' : [], 'to' : [] Index: lams_central/web/includes/javascript/authoring/authoringGeneral.js =================================================================== diff -u -r0144e9d0f7fc574a887933024183a8a9049bc414 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision 0144e9d0f7fc574a887933024183a8a9049bc414) +++ lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -517,7 +517,9 @@ activityData.activityUIID, activityData.xCoord, activityData.yCoord, - gateType); + gateType, + activityData.gateStartTimeOffset, + activityData.gateActivityCompletionBased); break; // Parallel Activity @@ -1009,6 +1011,9 @@ 'activityTypeID' : activityTypeID, 'orderID' : activity.orderID, 'defaultActivityUIID' : activity.defaultActivityUIID, + 'gateStartTimeOffset' : activity.gateType == 'schedule' ? + activity.offsetDay*24*60 + activity.offsetHour*60 + activity.offsetMinute : null, + 'gateActivityCompletionBased' : activity.gateActivityCompletionBased, 'gradebookToolOutputDefinitionName' : null, 'helpText' : null, Index: lams_central/web/includes/javascript/authoring/authoringProperty.js =================================================================== diff -u -r0144e9d0f7fc574a887933024183a8a9049bc414 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_central/web/includes/javascript/authoring/authoringProperty.js (.../authoringProperty.js) (revision 0144e9d0f7fc574a887933024183a8a9049bc414) +++ lams_central/web/includes/javascript/authoring/authoringProperty.js (.../authoringProperty.js) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -326,8 +326,9 @@ .show().data('parentObject', activity); $('.propertiesContentFieldTitle', content).val(activity.title); $('.propertiesContentFieldGateType', content).val(activity.gateType); - - $('input, select', content).change(function(){ + + // make onChange function a local variable, because it's used several times + var changeFunction = function(){ // extract changed properties and redraw the activity var content = $(this).closest('.dialogContainer'), activity = content.data('parentObject'), @@ -338,13 +339,56 @@ redrawNeeded = true; } activity.gateType = $('.propertiesContentFieldGateType', content).val(); + if (activity.gateType == 'schedule') { + $(".propertiesContentRowGateSchedule").show(); + activity.offsetDay = +$('.propertiesContentFieldOffsetDay', content).val(); + activity.offsetHour = +$('.propertiesContentFieldOffsetHour', content).val(); + activity.offsetMinute = +$('.propertiesContentFieldOffsetMinute', content).val(); + activity.gateActivityCompletionBased = $('.propertiesContentFieldActivityCompletionBased').is(':checked'); + } else { + $(".propertiesContentRowGateSchedule").hide(); + } if (redrawNeeded) { activity.draw(); ActivityLib.addSelectEffect(activity, true); } - }); + }; + + // create groups/learners spinners + $('.propertiesContentFieldOffsetDay', content).spinner({ + 'min' : 0, + 'max' : 364 + }).spinner('value', activity.offsetDay || 0) + .on('spinchange', changeFunction); + + $('.propertiesContentFieldOffsetHour', content).spinner({ + 'min' : 0, + 'max' : 23 + }).spinner('value', activity.offsetHour || 0) + .on('spinchange', changeFunction); + + $('.propertiesContentFieldOffsetMinute', content).spinner({ + 'min' : 0, + 'max' : 59 + }).spinner('value', activity.offsetMinute || 0) + .on('spinchange', changeFunction); + + $('.propertiesContentFieldActivityCompletionBased', content) + .attr('checked', activity.gateActivityCompletionBased? 'checked' : null); + + $('input, select', content).change(changeFunction); + changeFunction.call(content); } + + if (activity.transitions.to.length == 0){ + $('.propertiesContentFieldActivityCompletionBased', content) + .attr('checked', null) + .attr('disabled', 'disabled'); + } else { + $('.propertiesContentFieldActivityCompletionBased', content) + .attr('disabled', null); + } }, Index: lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/learningdesign/Activity.hbm.xml =================================================================== diff -u -rc135649b64e98c9233da20bdcfb7689598116314 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/learningdesign/Activity.hbm.xml (.../Activity.hbm.xml) (revision c135649b64e98c9233da20bdcfb7689598116314) +++ lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/learningdesign/Activity.hbm.xml (.../Activity.hbm.xml) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -263,6 +263,7 @@ true + @hibernate.class Index: lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch02040025.sql =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch02040025.sql (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch02040025.sql (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -0,0 +1,15 @@ +-- Turn off autocommit, so nothing is committed if there is an error + +SET AUTOCOMMIT = 0; +SET FOREIGN_KEY_CHECKS=0; + +-- LDEV-3207 New type of schedule gate, based on activity completion + +ALTER TABLE lams_learning_activity ADD COLUMN gate_activity_completion_based TINYINT(1) + AFTER gate_end_date_time; + + +-- If there were no errors, commit and restore autocommit to on +SET FOREIGN_KEY_CHECKS=0; +COMMIT; +SET AUTOCOMMIT = 1; \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/ScheduleGateActivity.java =================================================================== diff -u -rc135649b64e98c9233da20bdcfb7689598116314 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/ScheduleGateActivity.java (.../ScheduleGateActivity.java) (revision c135649b64e98c9233da20bdcfb7689598116314) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/ScheduleGateActivity.java (.../ScheduleGateActivity.java) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -92,6 +92,8 @@ *

*/ private Date gateEndDateTime; + + private Boolean gateActivityCompletionBased; /** full constructor */ public ScheduleGateActivity(Long activityId, Integer id, String description, String title, Integer xcoord, @@ -154,6 +156,7 @@ newScheduleGateActivity.setGateStartTimeOffset(this.getGateStartTimeOffset()); newScheduleGateActivity.setGateEndDateTime(this.getGateEndDateTime()); newScheduleGateActivity.setGateStartDateTime(this.getGateStartDateTime()); + newScheduleGateActivity.setGateActivityCompletionBased(this.getGateActivityCompletionBased()); return newScheduleGateActivity; } @@ -195,6 +198,14 @@ this.gateEndTimeOffset = gateEndTimeOffset; } + public Boolean getGateActivityCompletionBased() { + return gateActivityCompletionBased; + } + + public void setGateActivityCompletionBased(Boolean gateActivityCompletionBased) { + this.gateActivityCompletionBased = gateActivityCompletionBased; + } + /** *

* Returns the gate open time for a particular lesson according to the s ettings done by the author. @@ -208,31 +219,30 @@ * * Note: the time will also be translated against server timezone. * - * @param lessonStartTime + * @param referenceTime * the start time of the lesson. this should be the server local time. the UTC time is only used for * persistent. * * @return the server local date time that the gate will be opened. */ - public Date getLessonGateOpenTime(Date lessonStartTime) { + public Date getGateOpenTime(Date referenceTime) { Calendar openTime = new GregorianCalendar(TimeZone.getDefault()); - openTime.setTime(lessonStartTime); + openTime.setTime(referenceTime); // compute the real opening time based on the lesson start time. if (isScheduledByStartTimeOffset()) { openTime.add(Calendar.MINUTE, getGateStartTimeOffset().intValue()); - this.setGateStartDateTime(openTime.getTime()); - } - - else if (isScheduledByStartDateTime()) + if (!Boolean.TRUE.equals(gateActivityCompletionBased)) { + this.setGateStartDateTime(openTime.getTime()); + } + } else if (isScheduledByStartDateTime()) { openTime.setTime(getGateStartDateTime()); - + } /** * else throw new ActivityBehaviorException("No way of scheduling has " + * "been setup - this usually should be done at authoring " + * "interface. Fail to calculate gate open time for lesson."); */ return openTime.getTime(); - } /** @@ -247,17 +257,16 @@ * * Note: the time will also be translated against proper timezone. * - * @param lessonStartTime + * @param referenceTime * * @return the date time that the gate will be closed. */ - public Date getLessonGateCloseTime(Date lessonStartTime) { + public Date getGateCloseTime(Date referenceTime) { Calendar closeTime = new GregorianCalendar(TimeZone.getDefault()); - closeTime.setTime(lessonStartTime); + closeTime.setTime(referenceTime); // compute the real opening time based on the if (isScheduledByEndTimeOffset()) { closeTime.add(Calendar.MINUTE, getGateEndTimeOffset().intValue()); - this.setGateEndDateTime(closeTime.getTime()); } else if (isScheduledByEndDateTime()) closeTime.setTime(getGateEndDateTime()); /** @@ -361,5 +370,4 @@ public boolean isScheduled() { return isScheduledByTimeOffset() || isScheduledByDateTime(); } - -} +} \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/AuthoringActivityDTO.java =================================================================== diff -u -rc135649b64e98c9233da20bdcfb7689598116314 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/AuthoringActivityDTO.java (.../AuthoringActivityDTO.java) (revision c135649b64e98c9233da20bdcfb7689598116314) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/AuthoringActivityDTO.java (.../AuthoringActivityDTO.java) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -179,6 +179,8 @@ private Date gateStartDateTime; private Date gateEndDateTime; + + private Boolean gateActivityCompletionBased; private Boolean applyGrouping; @@ -463,6 +465,7 @@ gateStartTimeOffset = activity.getGateStartTimeOffset(); gateEndDateTime = activity.getGateEndDateTime(); gateEndTimeOffset = activity.getGateEndTimeOffset(); + gateActivityCompletionBased = activity.getGateActivityCompletionBased(); } /******************************************************************************************************************* @@ -567,6 +570,14 @@ return gateStartTimeOffset; } + public Boolean getGateActivityCompletionBased() { + return gateActivityCompletionBased; + } + + public void setGateActivityCompletionBased(Boolean gateActivityCompletionBased) { + this.gateActivityCompletionBased = gateActivityCompletionBased; + } + /** * @return Returns the groupingID. */ Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/LibraryActivityDTO.java =================================================================== diff -u -rc135649b64e98c9233da20bdcfb7689598116314 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/LibraryActivityDTO.java (.../LibraryActivityDTO.java) (revision c135649b64e98c9233da20bdcfb7689598116314) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/LibraryActivityDTO.java (.../LibraryActivityDTO.java) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -98,6 +98,7 @@ private Long gateEndTimeOffset; private Date gateStartDateTime; private Date gateEndDateTime; + private Boolean gateActivityCompletionBased; /** Used for I18N the URLS. Does not need to be sent to clients, so no getter exists. */ private String languageCode; @@ -249,6 +250,7 @@ gateStartTimeOffset = activity.getGateStartTimeOffset(); gateEndDateTime = activity.getGateEndDateTime(); gateEndTimeOffset = activity.getGateEndTimeOffset(); + gateActivityCompletionBased = activity.getGateActivityCompletionBased(); } private void addConditionGateActivityAttributes(ConditionGateActivity activity) { @@ -508,6 +510,10 @@ return gateStartTimeOffset; } + public Boolean getGateActivityCompletionBased() { + return gateActivityCompletionBased; + } + /** * @return Returns the maxOptions. */ Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/strategy/GateActivityStrategy.java =================================================================== diff -u -r209087915bc219f430c282ad00e5d1e6462f9b5f -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/strategy/GateActivityStrategy.java (.../GateActivityStrategy.java) (revision 209087915bc219f430c282ad00e5d1e6462f9b5f) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/strategy/GateActivityStrategy.java (.../GateActivityStrategy.java) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -48,43 +48,39 @@ //--------------------------------------------------------------------- // Template methods //--------------------------------------------------------------------- - /** - * Returns wether we should open the gate or close the gate. It's - * implementation depends on the type of the gate we are dealing with. - * Generally, it needs the check up the current gate status. If the gate - * is already opened, we will keep it open for current learner. Otherwise, - * we need to validate the open condition for this learner. - * - * @param learner the learner who just arrived at the gate. - * @param activity the gate activity. - * @param lessonLearners all learners who have started the lesson - * @return whether we should open it or not. - */ - public boolean shouldOpenGateFor(User learner, List lessonLearners) { - gateActivity.addLeaner(learner, false); + /** + * Returns wether we should open the gate or close the gate. It's implementation depends on the type of the gate we + * are dealing with. Generally, it needs the check up the current gate status. If the gate is already opened, we + * will keep it open for current learner. Otherwise, we need to validate the open condition for this learner. + * + * @param learner + * the learner who just arrived at the gate. + * @param activity + * the gate activity. + * @param lessonLearners + * all learners who have started the lesson + * @return whether we should open it or not. + */ + public boolean shouldOpenGateFor(User learner, List lessonLearners) { + gateActivity.addLeaner(learner, false); - if (!gateActivity.getGateOpen().booleanValue()) { - if (isOpenConditionMet(lessonLearners)) { - gateActivity.setGateOpen(new Boolean(true)); - //always clear all lists if the gate is opened - gateActivity.getAllGateUsers().clear(); - gateActivity.getWaitingLearners().clear(); - gateActivity.getAllowedToPassLearners().clear(); - } - else { - return gateActivity.getAllowedToPassLearners().contains(learner); - } - } - //always clear all lists if the gate is already opened. - else { - gateActivity.getAllGateUsers().clear(); - gateActivity.getWaitingLearners().clear(); - gateActivity.getAllowedToPassLearners().clear(); - } - return gateActivity.getGateOpen().booleanValue(); + boolean isOpen = gateActivity.getGateOpen().booleanValue(); + + if (!isOpen) { + if (isOpenConditionMet(lessonLearners)) { + gateActivity.setGateOpen(new Boolean(true)); + } else { + return gateActivity.getAllowedToPassLearners().contains(learner); + } } - //--------------------------------------------------------------------- + gateActivity.getAllGateUsers().clear(); + gateActivity.getWaitingLearners().clear(); + gateActivity.getAllowedToPassLearners().clear(); + return isOpen; + } + + // --------------------------------------------------------------------- // Abstract methods //--------------------------------------------------------------------- /** Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/strategy/ScheduleGateActivityStrategy.java =================================================================== diff -u -r08950e1090443c3423a3d1c587416a2fccd8bbdf -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/strategy/ScheduleGateActivityStrategy.java (.../ScheduleGateActivityStrategy.java) (revision 08950e1090443c3423a3d1c587416a2fccd8bbdf) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/strategy/ScheduleGateActivityStrategy.java (.../ScheduleGateActivityStrategy.java) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -23,54 +23,92 @@ package org.lamsfoundation.lams.learningdesign.strategy; import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; import java.util.List; +import java.util.Set; +import java.util.TimeZone; +import org.lamsfoundation.lams.learningdesign.Activity; import org.lamsfoundation.lams.learningdesign.ContributionTypes; import org.lamsfoundation.lams.learningdesign.GateActivity; +import org.lamsfoundation.lams.learningdesign.ScheduleGateActivity; +import org.lamsfoundation.lams.lesson.CompletedActivityProgress; +import org.lamsfoundation.lams.lesson.LearnerProgress; +import org.lamsfoundation.lams.usermanagement.User; - /** - * Activity strategy that deals with the calculation specific to schedule gate - * activity. The major part of this strategy will be overiding the methods that - * defined in the abstract level. + * Activity strategy that deals with the calculation specific to schedule gate activity. The major part of this strategy + * will be overiding the methods that defined in the abstract level. * * @author Jacky Fang - * @since 2005-4-6 + * @since 2005-4-6 * @version 1.1 * */ -public class ScheduleGateActivityStrategy extends GateActivityStrategy -{ - public ScheduleGateActivityStrategy(GateActivity gateActivity) { - super(gateActivity); - } +public class ScheduleGateActivityStrategy extends GateActivityStrategy { + public ScheduleGateActivityStrategy(GateActivity gateActivity) { + super(gateActivity); + } - - //--------------------------------------------------------------------- + // --------------------------------------------------------------------- // Overriden methods - //--------------------------------------------------------------------- + // --------------------------------------------------------------------- /** - * @see org.lamsfoundation.lams.learningdesign.strategy.GateActivityStrategy#setUpContributionType(org.lamsfoundation.lams.learningdesign.Activity, java.util.ArrayList) + * @see org.lamsfoundation.lams.learningdesign.strategy.GateActivityStrategy#setUpContributionType(org.lamsfoundation.lams.learningdesign.Activity, + * java.util.ArrayList) */ - protected void setUpContributionType(ArrayList contributionTypes) - { - contributionTypes.add(ContributionTypes.SCHEDULE_GATE); + @Override + protected void setUpContributionType(ArrayList contributionTypes) { + contributionTypes.add(ContributionTypes.SCHEDULE_GATE); } /** - * Regarding schedule gate, we don't validate the open condition for the - * learner because the decision of opening the gate or not comes from the - * system scheduler. Lams opens the gate when the start time is reached and - * closes the gate when the end time is reached. + * Regarding schedule gate, we don't validate the open condition for the learner because the decision of opening the + * gate or not comes from the system scheduler. Lams opens the gate when the start time is reached and closes the + * gate when the end time is reached. * * @see org.lamsfoundation.lams.learningdesign.strategy.GateActivityStrategy#isOpenConditionMet() */ - protected boolean isOpenConditionMet(List lessonLearners) - { - if ( gateActivity != null ) { - return gateActivity.getGateOpen().booleanValue(); - } - return true; + @Override + protected boolean isOpenConditionMet(List lessonLearners) { + if (gateActivity != null) { + return gateActivity.getGateOpen().booleanValue(); + } + return true; } + + @SuppressWarnings({ "rawtypes" }) + @Override + public boolean shouldOpenGateFor(User learner, List lessonLearners) { + ScheduleGateActivity scheduleGate = (ScheduleGateActivity) gateActivity; + if (Boolean.TRUE.equals((scheduleGate.getGateActivityCompletionBased()))) { + Date previousActivityCompletionTime = getPreviousActivityCompletionDate(scheduleGate, learner); + if (previousActivityCompletionTime != null) { + Date openTime = scheduleGate.getGateOpenTime(previousActivityCompletionTime); + if (openTime.compareTo(new Date()) <= 0) { + gateActivity.addLeaner(learner, true); + return true; + } + } + return false; + } + return super.shouldOpenGateFor(learner, lessonLearners); + } + + @SuppressWarnings({ "unchecked" }) + public static Date getPreviousActivityCompletionDate(ScheduleGateActivity scheduleGate, User learner) { + Activity previousActivity = scheduleGate.getTransitionTo().getFromActivity(); + if (previousActivity != null) { + for (LearnerProgress progress : (Set) learner.getLearnerProgresses()) { + CompletedActivityProgress completion = progress.getCompletedActivities().get(previousActivity); + if (completion != null) { + return completion.getFinishDate(); + } + } + } + return null; + } } Index: lams_common/src/java/org/lamsfoundation/lams/util/AuthoringJsonTags.java =================================================================== diff -u -r0144e9d0f7fc574a887933024183a8a9049bc414 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_common/src/java/org/lamsfoundation/lams/util/AuthoringJsonTags.java (.../AuthoringJsonTags.java) (revision 0144e9d0f7fc574a887933024183a8a9049bc414) +++ lams_common/src/java/org/lamsfoundation/lams/util/AuthoringJsonTags.java (.../AuthoringJsonTags.java) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -88,6 +88,7 @@ public static final String GATE_START_OFFSET = "gateStartTimeOffset"; public static final String GATE_END_OFFSET = "gateEndTimeOffset"; public static final String GATE_OPEN = "gateOpen"; + public static final String GATE_ACTIVITY_COMPLETION_BASED = "gateActivityCompletionBased"; /** Grouping Activity specific tags */ public static final String CREATE_GROUPING_ID = "createGroupingID"; Index: lams_learning/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -rc3cc819ade1f0545299bb448e6235b8dffe0eb3a -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_learning/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision c3cc819ade1f0545299bb448e6235b8dffe0eb3a) +++ lams_learning/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -29,8 +29,16 @@ label.permission.gate.title =Permission Gate label.permission.gate.message =You have stopped at a gate. You cannot continue until the gate is opened in Monitoring. label.schedule.gate.title =Schedule Gate -label.schedule.gate.open.message =Schedule Gate will be opened at: -label.schedule.gate.close.message =Schedule Gate will be closed at: +label.schedule.gate.reach =You have reached the gate on +label.schedule.gate.offset.1 =The gate will only be opened +label.schedule.gate.offset.2 =after. +label.days =days +label.hours =hours +label.minutes =minutes +label.seconds =seconds +label.schedule.gate.open.remaining =You can only move through the gate and attempt the remaining activities in +label.schedule.gate.open.message =The gate will be opened at: +label.schedule.gate.close.message =The gate will be closed at: label.gate.waiting.learners ={0} out of {1} are waiting in front of the gate. label.gate.refresh.message =Click Next if you are told that the gate is open. This page will refresh automatically in 1 minute. label.gate.preview.message =As this is a preview, clicking Next will go to the next activity. Normally the learner would have to wait until the gate is opened. Index: lams_learning/conf/language/lams/ApplicationResources_en_AU.properties =================================================================== diff -u -rc3cc819ade1f0545299bb448e6235b8dffe0eb3a -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_learning/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision c3cc819ade1f0545299bb448e6235b8dffe0eb3a) +++ lams_learning/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -29,8 +29,16 @@ label.permission.gate.title =Permission Gate label.permission.gate.message =You have stopped at a gate. You cannot continue until the gate is opened in Monitoring. label.schedule.gate.title =Schedule Gate -label.schedule.gate.open.message =Schedule Gate will be opened at: -label.schedule.gate.close.message =Schedule Gate will be closed at: +label.schedule.gate.reach =You have reached the gate on +label.schedule.gate.offset.1 =The gate will only be opened +label.schedule.gate.offset.2 =after. +label.days =days +label.hours =hours +label.minutes =minutes +label.seconds =seconds +label.schedule.gate.open.remaining =You can only move through the gate and attempt the remaining activities in +label.schedule.gate.open.message =The gate will be opened at: +label.schedule.gate.close.message =The gate will be closed at: label.gate.waiting.learners ={0} out of {1} are waiting in front of the gate. label.gate.refresh.message =Click Next if you are told that the gate is open. This page will refresh automatically in 1 minute. label.gate.preview.message =As this is a preview, clicking Next will go to the next activity. Normally the learner would have to wait until the gate is opened. Index: lams_learning/conf/xdoclet/struts-forms.xml =================================================================== diff -u -r8386a3fecd9c7baf6ed69d499016dedd8a83eac6 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_learning/conf/xdoclet/struts-forms.xml (.../struts-forms.xml) (revision 8386a3fecd9c7baf6ed69d499016dedd8a83eac6) +++ lams_learning/conf/xdoclet/struts-forms.xml (.../struts-forms.xml) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -15,6 +15,9 @@ + + + Index: lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java =================================================================== diff -u -r733eb2e21e1eb54366032ebb068168f7315c6cf5 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java (.../LearnerService.java) (revision 733eb2e21e1eb54366032ebb068168f7315c6cf5) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java (.../LearnerService.java) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -918,7 +918,6 @@ // the database. activityDAO.update(gate); return new GateActivityDTO(gate, lessonLearners, gateOpen); - } /** Index: lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/GateAction.java =================================================================== diff -u -r8386a3fecd9c7baf6ed69d499016dedd8a83eac6 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/GateAction.java (.../GateAction.java) (revision 8386a3fecd9c7baf6ed69d499016dedd8a83eac6) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/GateAction.java (.../GateAction.java) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -25,6 +25,10 @@ package org.lamsfoundation.lams.learning.web.action; import java.io.IOException; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -42,6 +46,7 @@ import org.lamsfoundation.lams.learning.web.util.LearningWebUtil; import org.lamsfoundation.lams.learningdesign.Activity; import org.lamsfoundation.lams.learningdesign.ScheduleGateActivity; +import org.lamsfoundation.lams.learningdesign.strategy.ScheduleGateActivityStrategy; import org.lamsfoundation.lams.lesson.LearnerProgress; import org.lamsfoundation.lams.lesson.Lesson; import org.lamsfoundation.lams.usermanagement.User; @@ -185,8 +190,30 @@ return mapping.findForward(GateAction.VIEW_SYNCH_GATE); } else if (gate.isScheduleGate()) { ScheduleGateActivity scheduleGate = (ScheduleGateActivity) gate.getGateActivity(); - gateForm.set("startingTime", scheduleGate.getGateStartDateTime()); - gateForm.set("endingTime", scheduleGate.getGateEndDateTime()); + if (Boolean.TRUE.equals(scheduleGate.getGateActivityCompletionBased())) { + // so it is in seconds + gateForm.set("startOffset", scheduleGate.getGateStartTimeOffset() * 60); + + ICoreLearnerService learnerService = LearnerServiceProxy.getLearnerService(getServlet() + .getServletContext()); + User learner = LearningWebUtil.getUser(learnerService); + Date reachTime = ScheduleGateActivityStrategy.getPreviousActivityCompletionDate(scheduleGate, learner); + gateForm.set("reachDate", reachTime); + + Calendar startingTime = new GregorianCalendar(TimeZone.getDefault()); + startingTime.setTime(reachTime); + startingTime.add(Calendar.MINUTE, scheduleGate.getGateStartTimeOffset().intValue()); + long diff = startingTime.getTimeInMillis() - new Date().getTime(); + long remainTime = diff / 1000; + gateForm.set("remainTime", remainTime); + } else { + gateForm.set("reachDate", null); + long diff = scheduleGate.getGateStartDateTime().getTime() - new Date().getTime(); + long remainTime = diff / 1000; + gateForm.set("remainTime", remainTime); + gateForm.set("startingTime", scheduleGate.getGateStartDateTime()); + gateForm.set("endingTime", scheduleGate.getGateEndDateTime()); + } return mapping.findForward(GateAction.VIEW_SCHEDULE_GATE); } else if (gate.isConditionGate()) { gateForm.set("monitorCanOpenGate", false); Index: lams_learning/web/gate/scheduleGateContent.jsp =================================================================== diff -u -r08950e1090443c3423a3d1c587416a2fccd8bbdf -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_learning/web/gate/scheduleGateContent.jsp (.../scheduleGateContent.jsp) (revision 08950e1090443c3423a3d1c587416a2fccd8bbdf) +++ lams_learning/web/gate/scheduleGateContent.jsp (.../scheduleGateContent.jsp) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -25,9 +25,72 @@ <%@ taglib uri="tags-core" prefix="c" %> <%@ taglib uri="tags-fmt" prefix="fmt" %> <%@ taglib uri="tags-lams" prefix="lams" %> + + +


+ +

+ + + +

+
+ +

+
+
+ -

- -

-
- \ No newline at end of file + + + \ No newline at end of file Index: lams_monitoring/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -r15045d0b9b0dbb930f42a9da7757207e7a325341 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_monitoring/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 15045d0b9b0dbb930f42a9da7757207e7a325341) +++ lams_monitoring/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -12,6 +12,7 @@ label.synch.gate.title =Synch Gate label.permission.gate.title =Permission Gate label.schedule.gate.title =Schedule Gate +label.schedule.gate.activity.completion.based =This gate is based on each learner's previous activity completion time. label.schedule.gate.open.message =Schedule Gate will be opened at: label.schedule.gate.close.message =Schedule Gate will be closed at: label.gate.you.open.message =You may open the gate for the whole class Index: lams_monitoring/conf/xdoclet/struts-forms.xml =================================================================== diff -u -r418a30a76094c56762b5beb23cb2dd72619e316c -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_monitoring/conf/xdoclet/struts-forms.xml (.../struts-forms.xml) (revision 418a30a76094c56762b5beb23cb2dd72619e316c) +++ lams_monitoring/conf/xdoclet/struts-forms.xml (.../struts-forms.xml) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -5,6 +5,7 @@ + Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java =================================================================== diff -u -r42844312f7e8f8330c1b4892a8e036ff6b0813d8 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java (.../MonitoringService.java) (revision 42844312f7e8f8330c1b4892a8e036ff6b0813d8) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java (.../MonitoringService.java) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -888,7 +888,10 @@ if (activity.getActivityTypeId().intValue() == Activity.SCHEDULE_GATE_ACTIVITY_TYPE) { ScheduleGateActivity gateActivity = (ScheduleGateActivity) activityDAO.getActivityByActivityId(activity .getActivityId()); - activity = runGateScheduler(gateActivity, lessonStartTime, lessonName); + // do not run the scheduler if the gate is basen on user completing previous activity + if (!Boolean.TRUE.equals(gateActivity.getGateActivityCompletionBased())) { + activity = runGateScheduler(gateActivity, lessonStartTime, lessonName); + } activity.setInitialised(true); } if (activity.isBranchingActivity() && (activity.getGrouping() == null)) { @@ -949,10 +952,10 @@ // create customized triggers Trigger openGateTrigger = new SimpleTrigger("openGateTrigger:" + scheduleGate.getActivityId(), - Scheduler.DEFAULT_GROUP, scheduleGate.getLessonGateOpenTime(schedulingStartTime)); + Scheduler.DEFAULT_GROUP, scheduleGate.getGateOpenTime(schedulingStartTime)); Trigger closeGateTrigger = new SimpleTrigger("closeGateTrigger:" + scheduleGate.getActivityId(), - Scheduler.DEFAULT_GROUP, scheduleGate.getLessonGateCloseTime(schedulingStartTime)); + Scheduler.DEFAULT_GROUP, scheduleGate.getGateCloseTime(schedulingStartTime)); // start the scheduling job try { Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/GateAction.java =================================================================== diff -u -r43e9b0375bdc58481bfeedc5dcb6ce68f7db662a -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/GateAction.java (.../GateAction.java) (revision 43e9b0375bdc58481bfeedc5dcb6ce68f7db662a) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/GateAction.java (.../GateAction.java) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -300,8 +300,12 @@ */ private ActionForward viewScheduleGate(ActionMapping mapping, DynaActionForm gateForm, ScheduleGateActivity scheduleGate) { - gateForm.set("startingTime", scheduleGate.getGateStartDateTime()); - gateForm.set("endingTime", scheduleGate.getGateEndDateTime()); + if (Boolean.TRUE.equals(scheduleGate.getGateActivityCompletionBased())) { + gateForm.set("activityCompletionBased", true); + } else { + gateForm.set("startingTime", scheduleGate.getGateStartDateTime()); + gateForm.set("endingTime", scheduleGate.getGateEndDateTime()); + } return mapping.findForward(GateAction.VIEW_SCHEDULE_GATE); } Index: lams_monitoring/web/gate/scheduleGateContent.jsp =================================================================== diff -u -r614080cb0cdefaf39c8453eeaa7977e17d2b0882 -r88e98be30293b57a81d4a8a6e5cdaf5c62e97883 --- lams_monitoring/web/gate/scheduleGateContent.jsp (.../scheduleGateContent.jsp) (revision 614080cb0cdefaf39c8453eeaa7977e17d2b0882) +++ lams_monitoring/web/gate/scheduleGateContent.jsp (.../scheduleGateContent.jsp) (revision 88e98be30293b57a81d4a8a6e5cdaf5c62e97883) @@ -31,14 +31,20 @@

<%@ include file="gateInfo.jsp" %> - - -

-
- - -

-
+ + + + + + +

+
+ + +

+
+
+
<%@ include file="gateStatus.jsp" %>