Coverage Report - org.kuali.student.lum.program.client.requirements.ProgramRequirementsSummaryView
 
Classes in this File Line Coverage Branch Coverage Complexity
ProgramRequirementsSummaryView
0%
0/228
0%
0/76
2.065
ProgramRequirementsSummaryView$1
0%
0/5
0%
0/2
2.065
ProgramRequirementsSummaryView$10
0%
0/15
0%
0/4
2.065
ProgramRequirementsSummaryView$10$1
0%
0/3
N/A
2.065
ProgramRequirementsSummaryView$10$2
0%
0/9
N/A
2.065
ProgramRequirementsSummaryView$11
0%
0/3
N/A
2.065
ProgramRequirementsSummaryView$12
0%
0/5
0%
0/2
2.065
ProgramRequirementsSummaryView$2
0%
0/5
0%
0/2
2.065
ProgramRequirementsSummaryView$3
0%
0/3
N/A
2.065
ProgramRequirementsSummaryView$4
0%
0/3
N/A
2.065
ProgramRequirementsSummaryView$5
0%
0/5
N/A
2.065
ProgramRequirementsSummaryView$5$1
0%
0/6
N/A
2.065
ProgramRequirementsSummaryView$6
0%
0/9
N/A
2.065
ProgramRequirementsSummaryView$6$1
0%
0/4
N/A
2.065
ProgramRequirementsSummaryView$7
0%
0/3
N/A
2.065
ProgramRequirementsSummaryView$7$1
0%
0/4
N/A
2.065
ProgramRequirementsSummaryView$8
0%
0/3
N/A
2.065
ProgramRequirementsSummaryView$9
0%
0/7
0%
0/4
2.065
ProgramRequirementsSummaryView$9$1
0%
0/6
0%
0/2
2.065
ProgramRequirementsSummaryView$ProgramReqDialogView
0%
0/2
N/A
2.065
 
 1  
 package org.kuali.student.lum.program.client.requirements;
 2  
 
 3  
 import com.google.gwt.core.client.GWT;
 4  
 import com.google.gwt.event.dom.client.ClickEvent;
 5  
 import com.google.gwt.event.dom.client.ClickHandler;
 6  
 import com.google.gwt.event.shared.HandlerManager;
 7  
 import com.google.gwt.user.client.Window;
 8  
 import com.google.gwt.user.client.ui.FlowPanel;
 9  
 import com.google.gwt.user.client.ui.Widget;
 10  
 import org.kuali.student.common.ui.client.application.Application;
 11  
 import org.kuali.student.common.ui.client.application.KSAsyncCallback;
 12  
 import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor;
 13  
 import org.kuali.student.common.ui.client.configurable.mvc.SectionTitle;
 14  
 import org.kuali.student.common.ui.client.configurable.mvc.layouts.BasicLayout;
 15  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.GroupSection;
 16  
 import org.kuali.student.common.ui.client.configurable.mvc.views.VerticalSectionView;
 17  
 import org.kuali.student.common.ui.client.mvc.*;
 18  
 import org.kuali.student.common.ui.client.service.MetadataRpcService;
 19  
 import org.kuali.student.common.ui.client.service.MetadataRpcServiceAsync;
 20  
 import org.kuali.student.common.ui.client.widgets.KSButton;
 21  
 import org.kuali.student.common.ui.client.widgets.KSButtonAbstract;
 22  
 import org.kuali.student.common.ui.client.widgets.KSLabel;
 23  
 import org.kuali.student.common.ui.client.widgets.KSLightBox;
 24  
 import org.kuali.student.common.ui.client.widgets.buttongroups.ButtonEnumerations;
 25  
 import org.kuali.student.common.ui.client.widgets.dialog.ConfirmationDialog;
 26  
 import org.kuali.student.common.ui.client.widgets.field.layout.button.ActionCancelGroup;
 27  
 import org.kuali.student.common.ui.client.widgets.field.layout.element.MessageKeyInfo;
 28  
 import org.kuali.student.common.ui.client.widgets.field.layout.element.SpanPanel;
 29  
 import org.kuali.student.common.ui.client.widgets.progress.BlockingTask;
 30  
 import org.kuali.student.common.ui.client.widgets.progress.KSBlockingProgressIndicator;
 31  
 import org.kuali.student.common.ui.client.widgets.rules.RulePreviewWidget;
 32  
 import org.kuali.student.common.ui.client.widgets.rules.RulesUtil;
 33  
 import org.kuali.student.core.assembly.data.ConstraintMetadata;
 34  
 import org.kuali.student.core.assembly.data.Data;
 35  
 import org.kuali.student.core.assembly.data.Metadata;
 36  
 import org.kuali.student.core.assembly.data.QueryPath;
 37  
 import org.kuali.student.core.dto.RichTextInfo;
 38  
 import org.kuali.student.core.statement.dto.*;
 39  
 import org.kuali.student.core.validation.dto.ValidationResultInfo;
 40  
 import org.kuali.student.lum.common.client.widgets.CluSetDetailsWidget;
 41  
 import org.kuali.student.lum.common.client.widgets.CluSetRetriever;
 42  
 import org.kuali.student.lum.common.client.widgets.CluSetRetrieverImpl;
 43  
 import org.kuali.student.lum.program.client.ProgramConstants;
 44  
 import org.kuali.student.lum.program.client.ProgramSections;
 45  
 import org.kuali.student.lum.program.client.properties.ProgramProperties;
 46  
 import org.kuali.student.lum.program.client.widgets.EditableHeader;
 47  
 import org.kuali.student.lum.program.dto.ProgramRequirementInfo;
 48  
 
 49  
 import java.util.*;
 50  
 
 51  0
 public class ProgramRequirementsSummaryView extends VerticalSectionView {
 52  
 
 53  0
     private MetadataRpcServiceAsync metadataServiceAsync = GWT.create(MetadataRpcService.class);
 54  0
     private static CluSetRetriever cluSetRetriever = new CluSetRetrieverImpl();
 55  
 
 56  
     //view's widgets
 57  0
     private FlowPanel layout = new FlowPanel();
 58  0
     private ActionCancelGroup actionCancelButtons = new ActionCancelGroup(ButtonEnumerations.SaveCancelEnum.SAVE, ButtonEnumerations.SaveCancelEnum.CANCEL);
 59  
     private BasicLayout reqCompController;
 60  0
     private FlowPanel holdFieldsPanel = new FlowPanel();
 61  
 
 62  
     //view's data
 63  
     private ProgramRequirementsViewController parentController;
 64  
     private ProgramRequirementsDataModel rules;
 65  
     private boolean isReadOnly;
 66  
     
 67  0
     public static int tempStmtTreeID = 9999;
 68  
     public static final String NEW_PROG_REQ_ID = "NEWPROGREQ";
 69  
     public static final String NEW_STMT_TREE_ID = "NEWSTMTTREE";
 70  
     public static final String NEW_REQ_COMP_ID = "NEWREQCOMP";
 71  
 
 72  
 
 73  0
     private enum ProgramReqDialogView {
 74  0
         VIEW
 75  
     }
 76  
 
 77  
     private static final String PROG_REQ_MODEL_ID = "progReqModelId";
 78  
     private DataModel progReqData;
 79  0
     private BlockingTask gettingMetadataTask = new BlockingTask("Loading");
 80  0
     private static Metadata dialogMetadata = null;  //simple caching
 81  
 
 82  0
     private Map<String, SpanPanel> perProgramRequirementTypePanel = new LinkedHashMap<String, SpanPanel>();
 83  0
     private Map<String, KSLabel> perProgramRequirementTypeTotalCredits = new LinkedHashMap<String, KSLabel>();
 84  
 
 85  
     public ProgramRequirementsSummaryView(final ProgramRequirementsViewController parentController, HandlerManager eventBus, Enum<?> viewEnum, String name,
 86  
                                           String modelId, boolean isReadOnly) {
 87  0
         super(viewEnum, name, modelId);
 88  0
         init(parentController, eventBus, isReadOnly);
 89  0
     }
 90  
 
 91  
     public ProgramRequirementsSummaryView(final ProgramRequirementsViewController parentController, HandlerManager eventBus, Enum<?> viewEnum, String name,
 92  
                                           String modelId, boolean isReadOnly, EditableHeader header) {
 93  0
         super(viewEnum, name, modelId, header);
 94  0
         init(parentController, eventBus, isReadOnly);
 95  0
     }
 96  
 
 97  
     private void init(ProgramRequirementsViewController parentController, HandlerManager eventBus, boolean isReadOnly) {
 98  0
         this.parentController = parentController;
 99  0
         this.isReadOnly = isReadOnly;
 100  0
         rules = new ProgramRequirementsDataModel(eventBus);
 101  
 
 102  0
         if (!isReadOnly) {
 103  0
             setupSaveCancelButtons();
 104  
         }
 105  0
     }
 106  
 
 107  
     @Override
 108  
     public boolean isDirty() {
 109  0
         return rules.isDirty();
 110  
     }
 111  
 
 112  
     protected ProgramRequirementsDataModel getRules() {
 113  0
         return rules;
 114  
     }
 115  
 
 116  
     @Override
 117  
     public void beforeShow(final Callback<Boolean> onReadyCallback) {
 118  
 
 119  0
         if (!rules.isInitialized() || parentController.reloadFlag) {
 120  0
             retrieveProgramRequirements(onReadyCallback);
 121  0
             return;
 122  
        }
 123  
         
 124  0
         onReadyCallback.exec(true);
 125  0
     }
 126  
 
 127  
     private void retrieveProgramRequirements(final Callback<Boolean> onReadyCallback) {
 128  0
         rules.retrieveProgramRequirements(parentController, new Callback<Boolean>() {
 129  
             @Override
 130  
             public void exec(Boolean result) {
 131  0
                 if (result) {
 132  0
                     displayRules();
 133  
                 }
 134  0
                 onReadyCallback.exec(result);
 135  0
             }
 136  
         });
 137  0
     }
 138  
 
 139  
     public void storeRules(final Callback<Boolean> callback) {
 140  0
         rules.updateProgramEntities(new Callback<List<ProgramRequirementInfo>>() {
 141  
             @Override
 142  
             public void exec(List<ProgramRequirementInfo> programReqInfos) {
 143  0
                 for (ProgramRequirementInfo programReqInfo : programReqInfos) {
 144  0
                     updateRequirementWidgets(programReqInfo);
 145  
                 }
 146  0
                 callback.exec(true);
 147  0
             }
 148  
         });
 149  0
     }
 150  
 
 151  
     public void revertRuleChanges() {
 152  0
         rules.revertRuleChanges();
 153  0
         displayRules();
 154  0
     }
 155  
 
 156  
     protected void updateRequirementWidgets(ProgramRequirementInfo programReqInfo) {
 157  0
         if (programReqInfo != null) {
 158  0
             StatementTypeInfo affectedStatementTypeInfo = rules.getStmtTypeInfo(programReqInfo.getStatement().getType());
 159  0
             SpanPanel reqPanel = perProgramRequirementTypePanel.get(affectedStatementTypeInfo.getId());
 160  
 
 161  
             //this happens if user previously deleted requirement but didn't save when moving to another section
 162  
             //add widget
 163  0
             if (reqPanel.getWidgetCount() == 0) {
 164  0
                 reqPanel.add(addProgramRequirement(reqPanel, programReqInfo));
 165  0
                 return;
 166  
             }
 167  
 
 168  
             //replace widget with a new version
 169  0
             for (int i = 0; i < reqPanel.getWidgetCount(); i++) {
 170  0
                 RulePreviewWidget rulePreviewWidget = (RulePreviewWidget) reqPanel.getWidget(i);
 171  0
                 if (rulePreviewWidget.getInternalProgReqID().equals(rules.getInternalProgReqID(programReqInfo))) {
 172  0
                     RulePreviewWidget newRulePreviewWidget = addProgramRequirement(reqPanel, programReqInfo);
 173  0
                     reqPanel.insert(newRulePreviewWidget, i);
 174  0
                     reqPanel.remove(rulePreviewWidget);
 175  0
                     break;
 176  
                 }
 177  
             }
 178  
         }
 179  0
     }
 180  
 
 181  
     public void displayRules() {
 182  0
         remove(layout);
 183  0
         layout.clear();
 184  
 
 185  
         //display 'Program Requirements' page title (don't add if read only because the section itself will display the title)
 186  0
         if (!isReadOnly) {
 187  0
             SectionTitle pageTitle = SectionTitle.generateH2Title(ProgramProperties.get().programRequirements_summaryViewPageTitle());
 188  
             //pageTitle.setStyleName("KS-Program-Requirements-Section-header");  //make the header orange
 189  0
             pageTitle.addStyleName("ks-layout-header");// change the header to green
 190  
 
 191  0
             layout.add(pageTitle);
 192  
         }
 193  
 
 194  
         //iterate and display rules for each Program Requirement type e.g. Entrance Requirements, Completion Requirements
 195  0
         Boolean firstRequirement = true;
 196  0
         perProgramRequirementTypePanel.clear();
 197  0
         for (StatementTypeInfo stmtTypeInfo : rules.getStmtTypes()) {
 198  
 
 199  
             //create and display one type of program requirement section
 200  0
             SpanPanel requirementsPanel = new SpanPanel();
 201  0
             perProgramRequirementTypePanel.put(stmtTypeInfo.getId(), requirementsPanel);
 202  0
             displayRequirementSectionForGivenType(requirementsPanel, stmtTypeInfo, firstRequirement);
 203  0
             updateTotalCreditPerType(stmtTypeInfo.getId());
 204  0
             firstRequirement = false;
 205  
 
 206  
             //now display each requirement for this Program Requirement type
 207  0
             for (ProgramRequirementInfo ruleInfo : rules.getProgReqInfo(stmtTypeInfo.getId())) {
 208  0
                 RulePreviewWidget rulePreviewWidget = addProgramRequirement(requirementsPanel, ruleInfo);
 209  0
                 requirementsPanel.add(rulePreviewWidget);
 210  0
             }
 211  0
         }
 212  
 
 213  
         //save and cancel buttons
 214  0
         if (!isReadOnly) {
 215  0
             layout.add(actionCancelButtons);
 216  
         }
 217  
 
 218  0
         addWidget(layout);
 219  0
     }
 220  
 
 221  
     private void displayRequirementSectionForGivenType(final SpanPanel requirementsPanel, final StatementTypeInfo stmtTypeInfo, boolean firstRequirement) {
 222  
 
 223  
         //display header for this Program Requirement type e.g. Entrance Requirements; make the header plural
 224  0
         SectionTitle title = SectionTitle.generateH3Title(stmtTypeInfo.getName());
 225  0
         title.setStyleName((firstRequirement ? "KS-Program-Requirements-Preview-Rule-Type-First-Header" : "KS-Program-Requirements-Preview-Rule-Type-Header"));
 226  0
         layout.add(title);
 227  
 
 228  
         //add Total Credits
 229  0
         KSLabel totalCredits = new KSLabel();
 230  0
         totalCredits.addStyleName("KS-Program-Requirements-Preview-Rule-Type-Credits");
 231  0
         perProgramRequirementTypeTotalCredits.put(stmtTypeInfo.getId(), totalCredits);
 232  0
         totalCredits.setVisible(false);
 233  0
         layout.add(totalCredits);
 234  
 
 235  
         //add rule description
 236  0
         if (!isReadOnly) {
 237  0
             KSLabel ruleTypeDesc = new KSLabel(stmtTypeInfo.getDescr());
 238  0
             ruleTypeDesc.addStyleName("KS-Program-Requirements-Preview-Rule-Type-Desc");
 239  0
             layout.add(ruleTypeDesc);
 240  
         }
 241  
 
 242  
         //display "Add Rule" button if user is in 'edit' mode
 243  0
         if (!isReadOnly) {
 244  0
             String addRuleLabel = ProgramProperties.get().programRequirements_summaryViewPageAddRule(stmtTypeInfo.getName());
 245  0
             KSButton addProgramReqBtn = new KSButton(addRuleLabel, KSButtonAbstract.ButtonStyle.FORM_SMALL);
 246  0
             addProgramReqBtn.addClickHandler(new ClickHandler() {
 247  
                 public void onClick(ClickEvent event) {
 248  0
                     showProgramRequirementDialog(requirementsPanel, stmtTypeInfo.getId(), null);
 249  0
                 }
 250  
             });
 251  0
             layout.add(addProgramReqBtn);
 252  
         }
 253  
 
 254  0
         layout.add(requirementsPanel);
 255  0
     }
 256  
 
 257  
     private RulePreviewWidget addProgramRequirement(final SpanPanel requirementsPanel, final ProgramRequirementInfo progReqInfo) {
 258  
 
 259  0
         Integer internalProgReqID = rules.getInternalProgReqID(progReqInfo);
 260  0
         String stmtTypeId = progReqInfo.getStatement().getType();
 261  
 
 262  0
         int minCredits = (progReqInfo.getMinCredits() == null ? 0 : progReqInfo.getMinCredits());
 263  0
         int maxCredits = (progReqInfo.getMaxCredits() == null ? 0 : progReqInfo.getMaxCredits());
 264  0
         String plainDesc = (progReqInfo.getDescr() == null ? "" : progReqInfo.getDescr().getPlain());
 265  0
         final RulePreviewWidget rulePreviewWidget = new RulePreviewWidget(internalProgReqID, progReqInfo.getShortTitle(),
 266  
                 getTotalCreditsString(minCredits, maxCredits),
 267  
                 plainDesc, progReqInfo.getStatement(),
 268  
                 isReadOnly, getCluSetWidgetList(progReqInfo.getStatement()));
 269  0
         addRulePreviewWidgetHandlers(requirementsPanel, rulePreviewWidget, stmtTypeId, internalProgReqID);
 270  0
         return rulePreviewWidget;
 271  
     }
 272  
 
 273  
     private void addRulePreviewWidgetHandlers(final SpanPanel requirementsPanel, final RulePreviewWidget rulePreviewWidget, final String stmtTypeId, final Integer internalProgReqID) {
 274  
 
 275  
         //PROGRAM REQUIREMENT handlers
 276  0
         rulePreviewWidget.addProgReqEditButtonClickHandler(new ClickHandler() {
 277  
             public void onClick(ClickEvent event) {
 278  0
                 showProgramRequirementDialog(requirementsPanel, stmtTypeId, internalProgReqID);
 279  0
             }
 280  
         });
 281  
 
 282  0
         rulePreviewWidget.addProgReqDeleteButtonClickHandler(new ClickHandler() {
 283  
             public void onClick(ClickEvent event) {
 284  0
                 final ConfirmationDialog dialog = new ConfirmationDialog(
 285  
                         ProgramProperties.get().programRequirements_summaryViewPageDeleteRequirementDialogTitle(),
 286  
                         ProgramProperties.get().programRequirements_summaryViewPageDeleteRequirementDialogMsg());
 287  
 
 288  0
                 dialog.getConfirmButton().addClickHandler(new ClickHandler() {
 289  
                     @Override
 290  
                     public void onClick(ClickEvent event) {
 291  0
                         rules.deleteRule(internalProgReqID);
 292  
 
 293  
                         //remove rule from display
 294  0
                         requirementsPanel.remove(rulePreviewWidget);
 295  0
                         perProgramRequirementTypeTotalCredits.get(stmtTypeId).setVisible(false);
 296  0
                         dialog.hide();
 297  0
                     }
 298  
                 });
 299  0
                 dialog.show();
 300  0
             }
 301  
         });
 302  
 
 303  
         //SUBRULE handlers
 304  0
         rulePreviewWidget.addSubRuleAddButtonClickHandler(new ClickHandler() {
 305  
             public void onClick(ClickEvent event) {
 306  0
                 final StatementTreeViewInfo newSubRule = new StatementTreeViewInfo();
 307  0
                 newSubRule.setId(generateStatementTreeId());
 308  0
                 newSubRule.setType(stmtTypeId);
 309  0
                 RichTextInfo text = new RichTextInfo();
 310  0
                 text.setPlain("");
 311  0
                 newSubRule.setDesc(text);
 312  0
                 parentController.getView(ProgramRequirementsViewController.ProgramRequirementsViews.MANAGE, new Callback<View>() {
 313  
 
 314  
                     @Override
 315  
                     public void exec(View result) {
 316  0
                         ((ProgramRequirementsManageView) result).setRuleTree(newSubRule, true, internalProgReqID);
 317  0
                         parentController.showView(ProgramRequirementsViewController.ProgramRequirementsViews.MANAGE);
 318  0
                     }
 319  
                 });
 320  0
             }
 321  
         });
 322  
 
 323  0
         rulePreviewWidget.addSubRuleEditButtonClickHandler(new Callback<RulePreviewWidget.SubRuleInfo>() {
 324  
             public void exec(final RulePreviewWidget.SubRuleInfo subRuleInfo) {
 325  0
                 parentController.getView(ProgramRequirementsViewController.ProgramRequirementsViews.MANAGE, new Callback<View>() {
 326  
                     @Override
 327  
                     public void exec(View result) {
 328  0
                         ((ProgramRequirementsManageView) result).setRuleTree(subRuleInfo.getSubrule(), false, subRuleInfo.getInternalProgReqID());
 329  0
                         parentController.showView(ProgramRequirementsViewController.ProgramRequirementsViews.MANAGE);
 330  0
                     }
 331  
                 });
 332  0
             }
 333  
         });
 334  
 
 335  0
         rulePreviewWidget.addSubRuleDeleteCallback(new Callback<Integer>() {
 336  
             public void exec(final Integer internalProgReqID) {
 337  
                 //deleting subrule does not delete the requirement (rule) itself
 338  0
                 rules.markRuleAsEdited(internalProgReqID);
 339  0
             }
 340  
         });
 341  0
     }
 342  
 
 343  
     protected Map<String, Widget> getCluSetWidgetList(StatementTreeViewInfo rule) {
 344  0
         Map<String, Widget> widgetList = new HashMap<String, Widget>();
 345  0
         Set<String> cluSetIds = new HashSet<String>();
 346  0
         findCluSetIds(rule, cluSetIds);
 347  0
         for (String clusetId : cluSetIds) {
 348  0
             widgetList.put(clusetId, new CluSetDetailsWidget(clusetId, cluSetRetriever));
 349  
         }
 350  
 
 351  0
         return widgetList;
 352  
     }
 353  
 
 354  
     private void findCluSetIds(StatementTreeViewInfo rule, Set<String> list) {
 355  
 
 356  0
         List<StatementTreeViewInfo> statements = rule.getStatements();
 357  0
         List<ReqComponentInfo> reqComponentInfos = rule.getReqComponents();
 358  
 
 359  0
         if ((statements != null) && (statements.size() > 0)) {
 360  
             // retrieve all statements
 361  0
             for (StatementTreeViewInfo statement : statements) {
 362  0
                 findCluSetIds(statement, list); // inside set the children of this statementTreeViewInfo
 363  
             }
 364  0
         } else if ((reqComponentInfos != null) && (reqComponentInfos.size() > 0)) {
 365  
             // retrieve all req. component LEAFS
 366  0
             for (ReqComponentInfo reqComponent : reqComponentInfos) {
 367  0
                 List<ReqCompFieldInfo> fieldInfos = reqComponent.getReqCompFields();
 368  0
                 for (ReqCompFieldInfo fieldInfo : fieldInfos) {
 369  0
                     if (RulesUtil.isCluSetWidget(fieldInfo.getType())) {
 370  0
                         list.add(fieldInfo.getValue());
 371  
                     }
 372  
                 }
 373  0
             }
 374  
         }
 375  0
     }
 376  
 
 377  
     private void showProgramRequirementDialog(final SpanPanel requirementsPanel, final String stmtTypeId, final Integer internalProgReqID) {
 378  
 
 379  0
         boolean isAddProgReq = (internalProgReqID == null);
 380  
 
 381  0
         String addRuleText = (isAddProgReq ? ProgramProperties.get().programRequirements_summaryViewPageAddRule(rules.getStmtTypeName(stmtTypeId)) : "Edit " + rules.getStmtTypeName(stmtTypeId));
 382  0
         final KSLightBox dialog = new KSLightBox(addRuleText);
 383  
 
 384  0
         final ButtonEnumerations.ButtonEnum actionButton = (isAddProgReq ? ButtonEnumerations.AddCancelEnum.ADD : ButtonEnumerations.UpdateCancelEnum.UPDATE);
 385  0
         ActionCancelGroup actionCancelButtons = new ActionCancelGroup(actionButton, ButtonEnumerations.UpdateCancelEnum.CANCEL);
 386  
 
 387  0
         actionCancelButtons.addCallback(new Callback<ButtonEnumerations.ButtonEnum>() {
 388  
             @Override
 389  
             public void exec(ButtonEnumerations.ButtonEnum result) {
 390  0
                 if (result == actionButton) {
 391  
 
 392  0
                     reqCompController.updateModel();
 393  
 
 394  
                     //validate and retrieve fields
 395  0
                     if (progReqData.getRoot().size() > 0) {
 396  0
                         progReqData.validate(new Callback<List<ValidationResultInfo>>() {
 397  
                             @Override
 398  
                             public void exec(List<ValidationResultInfo> validationResults) {
 399  
 
 400  
                                 //do not proceed if the user input is not valid
 401  0
                                 if (!reqCompController.isValid(validationResults, true, true)) {
 402  0
                                     return;
 403  
                                 }
 404  
 
 405  
                                 //retrieve entered values and set the rule info
 406  0
                                 updateProgramInfo(requirementsPanel, stmtTypeId, internalProgReqID);
 407  0
                                 dialog.hide();
 408  0
                             }
 409  
                         });
 410  
                     }
 411  
                 } else {
 412  0
                     dialog.hide();
 413  
                 }
 414  0
             }
 415  
         });
 416  
 
 417  0
         createAddProgramReqDialog(dialog, actionCancelButtons, internalProgReqID);
 418  0
     }
 419  
 
 420  
     private void createAddProgramReqDialog(final KSLightBox dialog, final ActionCancelGroup actionCancelButtons, final Integer internalProgReqID) {
 421  
 
 422  0
         parentController.requestModel(ProgramConstants.PROGRAM_MODEL_ID, new ModelRequestCallback<DataModel>() {
 423  
 
 424  
             @Override
 425  
             public void onRequestFail(Throwable cause) {
 426  0
                 Window.alert(cause.getMessage());
 427  0
                 GWT.log("Unable to retrieve program model for program summary view", cause);
 428  0
             }
 429  
 
 430  
             @Override
 431  
             public void onModelReady(DataModel model) {
 432  
 
 433  
                 //program has to be in the database before we can save program requirements
 434  0
                 String programId = model.getRoot().get(ProgramConstants.ID);
 435  0
                 if (programId == null) {
 436  0
                     final ConfirmationDialog dialog = new ConfirmationDialog("Save Program Key Info", "Before saving rules please save program key info");
 437  0
                     dialog.getConfirmButton().addClickHandler(new ClickHandler() {
 438  
                         @Override
 439  
                         public void onClick(ClickEvent event) {
 440  0
                             dialog.hide();
 441  0
                         }
 442  
                     });
 443  0
                     dialog.show();
 444  0
                     return;
 445  
                 }
 446  
 
 447  0
                 if (dialogMetadata == null) {
 448  0
                     KSBlockingProgressIndicator.addTask(gettingMetadataTask);
 449  0
                     metadataServiceAsync.getMetadataList("org.kuali.student.lum.program.dto.ProgramRequirementInfo", "Active", new KSAsyncCallback<Metadata>() {
 450  
                         public void handleFailure(Throwable caught) {
 451  0
                             KSBlockingProgressIndicator.removeTask(gettingMetadataTask);
 452  0
                             Window.alert(caught.getMessage());
 453  0
                             GWT.log("getMetadataList failed for ProgramRequirementInfo", caught);
 454  0
                         }
 455  
 
 456  
                         public void onSuccess(final Metadata metadata) {
 457  0
                             KSBlockingProgressIndicator.removeTask(gettingMetadataTask);
 458  0
                             dialogMetadata = metadata;
 459  0
                             showDialog(dialog, actionCancelButtons, metadata, internalProgReqID);
 460  0
                         }
 461  
                     });
 462  
                 } else {
 463  0
                     showDialog(dialog, actionCancelButtons, dialogMetadata, internalProgReqID);
 464  
                 }
 465  
 
 466  0
             }
 467  
         });
 468  0
     }
 469  
 
 470  
     private static FieldDescriptor createInputField(final String id, final Metadata metadata, final Map<String, Metadata> fieldDefinitionMetadata, final Map<String, FieldDescriptor> fields) {
 471  0
         FieldDescriptor fd = new FieldDescriptor(id, new MessageKeyInfo("program", "program", "draft", id), metadata);
 472  0
         fields.put(id, fd);
 473  
 
 474  
         //add field to the data model metadata
 475  0
         fieldDefinitionMetadata.put(id, metadata);
 476  
 
 477  0
         return fd;
 478  
     }
 479  
 
 480  
     //TODO rework to use Configurer if possible
 481  
     private void showDialog(final KSLightBox dialog, final ActionCancelGroup actionCancelButtons, Metadata metadata, Integer internalProgReqID) {
 482  
 
 483  0
         Map<String, Metadata> fieldDefinitionMetadata = new HashMap<String, Metadata>();
 484  0
         Map<String, FieldDescriptor> fields = new HashMap<String, FieldDescriptor>();
 485  0
         VerticalSectionView dialogPanel = new VerticalSectionView(ProgramReqDialogView.VIEW, "", PROG_REQ_MODEL_ID, false);
 486  0
         holdFieldsPanel.clear();
 487  
 
 488  0
         dialogPanel.addField(createInputField("shortTitle", metadata.getProperties().get("shortTitle"), fieldDefinitionMetadata, fields));
 489  0
         FieldDescriptor minFd = createInputField("minCredits", metadata.getProperties().get("minCredits"), fieldDefinitionMetadata, fields);
 490  0
         FieldDescriptor maxFd = createInputField("maxCredits", metadata.getProperties().get("maxCredits"), fieldDefinitionMetadata, fields);
 491  0
         GroupSection credits = new GroupSection();
 492  0
         credits.addField(minFd);
 493  0
         credits.addField(maxFd);
 494  0
         dialogPanel.addSection(credits);
 495  0
         final Metadata descrMetadata = metadata.getProperties().get("descr").getProperties().get("plain");
 496  0
         dialogPanel.addField(createInputField("descr", descrMetadata, fieldDefinitionMetadata, fields));
 497  
 
 498  0
         List<ConstraintMetadata> constraints = descrMetadata.getConstraints();
 499  0
         dialogPanel.addWidget(new KSLabel(constraints.get(0).getMaxLength() + getUILabel("descrLimit")));
 500  
 
 501  
         //setup data model
 502  0
         Metadata modelDefinitionMetadata = new Metadata();
 503  0
         modelDefinitionMetadata.setCanView(true);
 504  0
         modelDefinitionMetadata.setDataType(Data.DataType.DATA);
 505  0
         modelDefinitionMetadata.setProperties(fieldDefinitionMetadata);
 506  0
         progReqData = new DataModel();
 507  0
         progReqData.setRoot(new Data());
 508  0
         progReqData.setDefinition(new DataModelDefinition(modelDefinitionMetadata));
 509  
 
 510  
         //initialize fields with values if user is editing an existing rule
 511  0
         if (internalProgReqID != null) {
 512  0
             ProgramRequirementInfo progReq = rules.getProgReqByInternalId(internalProgReqID);
 513  0
             progReqData.set(QueryPath.parse("shortTitle"), progReq.getShortTitle());
 514  0
             progReqData.set(QueryPath.parse("minCredits"), progReq.getMinCredits());
 515  0
             progReqData.set(QueryPath.parse("maxCredits"), progReq.getMaxCredits());
 516  0
             progReqData.set(QueryPath.parse("descr"), (progReq.getDescr() == null ? "" : progReq.getDescr().getPlain()));
 517  
         }
 518  
 
 519  
         //setup controller
 520  0
         reqCompController = new BasicLayout(null);
 521  0
         reqCompController.addView(dialogPanel);
 522  0
         reqCompController.setDefaultModelId(PROG_REQ_MODEL_ID);
 523  0
         reqCompController.registerModel(PROG_REQ_MODEL_ID, new ModelProvider<DataModel>() {
 524  
             @Override
 525  
             public void requestModel(final ModelRequestCallback<DataModel> callback) {
 526  0
                 callback.onModelReady(progReqData);
 527  0
             }
 528  
         });
 529  
 
 530  
         //show fields
 531  0
         holdFieldsPanel.add(reqCompController);
 532  0
         reqCompController.showView(ProgramReqDialogView.VIEW);
 533  
 
 534  
         //layout.addStyleName("KS-Advanced-Search-Window");
 535  0
         holdFieldsPanel.add(actionCancelButtons);
 536  0
         dialog.setSize(550, 530);
 537  0
         dialog.setWidget(holdFieldsPanel);
 538  0
         dialog.show();
 539  0
     }
 540  
 
 541  
     private String getUILabel(final String id) {
 542  0
         return Application.getApplicationContext().getUILabel("program", null, null, id);
 543  
     }
 544  
 
 545  
     private void updateProgramInfo(SpanPanel requirementsPanel, String stmtTypeId, Integer internalProgReqID) {
 546  
 
 547  
         ProgramRequirementInfo progReqInfo;
 548  0
         if (internalProgReqID == null) {
 549  0
             progReqInfo = new ProgramRequirementInfo();
 550  0
             progReqInfo.setId(NEW_PROG_REQ_ID + Integer.toString(tempStmtTreeID++));   //set unique id
 551  0
             progReqInfo.setType("kuali.lu.type.Requirement");
 552  
 
 553  
             //create a top level statement tree
 554  0
             StatementTreeViewInfo stmtTree = new StatementTreeViewInfo();
 555  0
             stmtTree.setId(generateStatementTreeId());
 556  0
             stmtTree.setType(stmtTypeId);
 557  0
             RichTextInfo text2 = new RichTextInfo();
 558  0
             text2.setPlain("");
 559  0
             stmtTree.setDesc(text2);
 560  0
             stmtTree.setOperator(StatementOperatorTypeKey.AND); //AND is top level operator for rules within a Program Requirement
 561  
 
 562  
             //add new statement to the rule because even if user cancel on rule manage screen, we want to have at least one statement present
 563  0
             progReqInfo.setStatement(stmtTree);
 564  0
         } else {
 565  0
             progReqInfo = rules.getProgReqByInternalId(internalProgReqID);
 566  
         }
 567  
 
 568  0
         RichTextInfo text = new RichTextInfo();
 569  0
         text.setPlain((String) (progReqData.getRoot().get("descr")));
 570  0
         progReqInfo.setDescr(text);
 571  0
         progReqInfo.setShortTitle((String) progReqData.getRoot().get("shortTitle"));
 572  0
         progReqInfo.setLongTitle((String) progReqData.getRoot().get("shortTitle"));
 573  0
         progReqInfo.setMinCredits((Integer) progReqData.getRoot().get("minCredits"));
 574  0
         progReqInfo.setMaxCredits((Integer) progReqData.getRoot().get("maxCredits"));
 575  
 
 576  0
         if (internalProgReqID == null) {
 577  0
             rules.addRule(progReqInfo);
 578  0
             RulePreviewWidget rulePreviewWidget = addProgramRequirement(requirementsPanel, progReqInfo);
 579  0
             requirementsPanel.add(rulePreviewWidget);
 580  0
         } else {
 581  0
             rules.updateRule(internalProgReqID, progReqInfo);
 582  0
             for (Object aRequirementsPanel : requirementsPanel) {
 583  0
                 RulePreviewWidget rulePreviewWidget = (RulePreviewWidget) aRequirementsPanel;
 584  0
                 if (rulePreviewWidget.getInternalProgReqID().equals(internalProgReqID)) {
 585  0
                     rulePreviewWidget.updateProgInfoFields(progReqInfo.getShortTitle(),
 586  
                             getTotalCreditsString(progReqInfo.getMinCredits(), progReqInfo.getMaxCredits()),
 587  
                             progReqInfo.getDescr().getPlain());
 588  
                 }
 589  0
             }
 590  
         }
 591  
 
 592  0
         updateTotalCreditPerType(stmtTypeId);
 593  0
     }
 594  
 
 595  
     private String getTotalCreditsString(int min, int max) {
 596  0
         return "Expected Total Credits:" + min + "-" + max;
 597  
     }
 598  
 
 599  
     private void updateTotalCreditPerType(String stmtTypeId) {
 600  0
         int min = 0;
 601  0
         int max = 0;
 602  0
         for (ProgramRequirementInfo ruleInfo : rules.getProgReqInfo(stmtTypeId)) {
 603  0
             min += ruleInfo.getMinCredits();
 604  0
             max += ruleInfo.getMaxCredits();
 605  
         }
 606  
 
 607  0
         if (min != 0 || max != 0) {
 608  
             //update total
 609  0
             perProgramRequirementTypeTotalCredits.get(stmtTypeId).setVisible(true);
 610  0
             perProgramRequirementTypeTotalCredits.get(stmtTypeId).setText(getTotalCreditsString(min, max));
 611  
         }
 612  0
     }
 613  
 
 614  
     private void setupSaveCancelButtons() {
 615  0
         actionCancelButtons.addStyleName("KS-Program-Requirements-Save-Button");
 616  0
         actionCancelButtons.addCallback(new Callback<ButtonEnumerations.ButtonEnum>() {
 617  
             @Override
 618  
             public void exec(ButtonEnumerations.ButtonEnum result) {
 619  0
                 if (result == ButtonEnumerations.SaveCancelEnum.SAVE) {
 620  0
                     storeRules(Controller.NO_OP_CALLBACK);
 621  
                 } else {
 622  
                     //does not work any more: HistoryManager.navigate(AppLocations.Locations.VIEW_PROGRAM.getLocation(), parentController.getViewContext());
 623  0
                     parentController.getParentController().showView(ProgramSections.SUMMARY);
 624  
                 }
 625  0
             }
 626  
         });
 627  0
     }
 628  
 
 629  
     static public String generateStatementTreeId() {
 630  0
         return (NEW_STMT_TREE_ID + Integer.toString(tempStmtTreeID++));
 631  
     }
 632  
 }