View Javadoc

1   /**
2    * Copyright 2010 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   */
15  
16  package org.kuali.student.lum.common.client.lo;
17  
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  import org.kuali.student.common.assembly.data.Metadata;
22  import org.kuali.student.common.ui.client.application.Application;
23  import org.kuali.student.common.ui.client.configurable.mvc.CanProcessValidationResults;
24  import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor;
25  import org.kuali.student.common.ui.client.configurable.mvc.sections.Section;
26  import org.kuali.student.common.ui.client.configurable.mvc.sections.VerticalSection;
27  import org.kuali.student.common.ui.client.widgets.KSButton;
28  import org.kuali.student.common.ui.client.widgets.KSLabel;
29  import org.kuali.student.common.ui.client.widgets.KSButtonAbstract.ButtonStyle;
30  import org.kuali.student.common.ui.client.widgets.list.SelectionChangeEvent;
31  import org.kuali.student.common.ui.client.widgets.list.SelectionChangeHandler;
32  import org.kuali.student.common.ui.client.widgets.search.KSPicker;
33  import org.kuali.student.common.validation.dto.ValidationResultInfo;
34  import org.kuali.student.common.validation.dto.ValidationResultInfo.ErrorLevel;
35  import org.kuali.student.lum.common.client.lu.LUUIConstants;
36  
37  import com.google.gwt.event.dom.client.ChangeEvent;
38  import com.google.gwt.event.dom.client.ChangeHandler;
39  import com.google.gwt.event.dom.client.ClickEvent;
40  import com.google.gwt.event.dom.client.ClickHandler;
41  import com.google.gwt.event.logical.shared.ValueChangeEvent;
42  import com.google.gwt.event.logical.shared.ValueChangeHandler;
43  import com.google.gwt.event.shared.HandlerRegistration;
44  import com.google.gwt.user.client.ui.HasValue;
45  import com.google.gwt.user.client.ui.HorizontalPanel;
46  
47  /**
48   * This class manages the users interactions when building/updating Learning
49   * Objectives within the context of managing CLUs. It allows the user to type in
50   * LO text directly or execute a search and select one or more of the returned
51   * LOs.
52   * 
53   * Users can then re-organize LOs on the screen including altering the sequence
54   * and creating sub LOs
55   * 
56   * @author Kuali Student Team
57   * 
58   */
59  public class LOBuilder extends VerticalSection implements HasValue<List<OutlineNode<LOPicker>>>, CanProcessValidationResults {
60  
61  	private static String type;
62  	private static String state;
63  	private static String repoKey;
64  	private static String messageGroup;
65      private static String startOfPath;
66      private static String endOfPath = "loInfo/desc/plain";
67      private static String middleOfPath = "loDisplayInfoList";
68  	HorizontalPanel searchMainPanel = new HorizontalPanel();
69  	KSPicker searchWindow;
70  
71  	LearningObjectiveList loList;
72  	KSLabel instructions;
73  
74  	protected LOBuilder() {
75  	}
76  
77      public LOBuilder(String luType, String luState, String luGroup, String loRepoKey, String queryPathStart, final Metadata metadata) {
78  		super();
79  
80  		type = luType;
81  		state = luState;
82  		repoKey = loRepoKey;
83  		messageGroup = luGroup;
84          startOfPath = queryPathStart;
85  
86  		 if(metadata.getInitialLookup() != null) {
87  		 	searchWindow = new KSPicker(metadata.getInitialLookup(), metadata.getAdditionalLookups());
88  		  	searchWindow.addValuesChangeHandler(new ValueChangeHandler<List<String>>() {
89  		  		public void onValueChange(ValueChangeEvent<List<String>> event) {
90  		  		        List<String> selection = event.getValue();
91  		  				loList.addSelectedLOs(selection);
92  		  			}
93  		  	    }
94  		  	);
95  		  	searchMainPanel.add(searchWindow);
96  		  }
97  		 		 
98  
99  		instructions = new KSLabel(getLabel(LUUIConstants.LO_INSTRUCTIONS_KEY));
100 
101         loList = new LearningObjectiveList();
102 
103 		searchMainPanel.addStyleName("KS-LOBuilder-Search-Panel");
104 
105         loList.addStyleName(LUUIConstants.STYLE_SECTION);
106         loList.addStyleName(LUUIConstants.STYLE_SECTION_DIVIDER);
107 
108 		instructions.addStyleName("KS-LOBuilder-Instructions");
109 
110         this.addWidget(searchMainPanel);
111         this.addWidget(instructions);
112         this.addSection(loList);
113 	}
114 
115 	/**
116 	 * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object,
117 	 *      boolean)
118 	 */
119 	@Override
120 	public void setValue(List<OutlineNode<LOPicker>> value, boolean fireEvents) {
121 		setValue(value);
122 	}
123 
124 	/**
125 	 * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object)
126 	 */
127 	@Override
128 	public void setValue(List<OutlineNode<LOPicker>> data) {
129 		loList.setValue(data);
130 	}
131 
132 	/**
133 	 * @see com.google.gwt.user.client.ui.HasValue#getValue()
134 	 */
135 	@Override
136 	public List<OutlineNode<LOPicker>> getValue() {
137 		return loList.getValue();
138 	}
139 
140 	/**
141 	 * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler)
142 	 */
143 	@Override
144 	public HandlerRegistration addValueChangeHandler(ValueChangeHandler<List<OutlineNode<LOPicker>>> handler) {
145 		return loList.addValueChangeHandler(handler);
146 	}
147 
148 	private static String getLabel(String labelKey) {
149 		return Application.getApplicationContext().getUILabel(messageGroup,
150 				type, state, labelKey);
151 	}
152 
153 	/**
154 	 * @return the type
155 	 */
156 	public static String getType() {
157 		return type;
158 	}
159 
160 	/**
161 	 * @return the state
162 	 */
163 	public static String getState() {
164 		return state;
165 	}
166 
167 	public static String getRepoKey() {
168 		return repoKey;
169 	}
170 
171 	/**
172 	 * @return the messageGroup
173 	 */
174 	public static String getMessageGroup() {
175 		return messageGroup;
176 	}
177 
178     public static class LearningObjectiveList extends VerticalSection implements HasValue<List<OutlineNode<LOPicker>>> {
179 		OutlineNodeModel<LOPicker> outlineModel = new OutlineNodeModel<LOPicker>();
180         KSButton addNew;
181         OutlineManager outlineComposite;
182 		
183 		SelectionChangeHandler loPickerChangeHandler = new SelectionChangeHandler(){
184 			public void onSelectionChange(SelectionChangeEvent event) {
185 				fireChangeEvent();
186 			}			
187 		};
188 		
189         public LearningObjectiveList() {
190             addNew = new KSButton("Add item", ButtonStyle.SECONDARY, new ClickHandler() {
191 				public void onClick(ClickEvent event) {
192 					setValue(getValue());
193 					appendLO("");
194 					reDraw();
195 				}
196 			});
197 			
198             addNew.addStyleName("KS-LOBuilder-New");
199 
200 			outlineModel.addChangeHandler(new ChangeHandler() {
201 				public void onChange(ChangeEvent event) {
202                     reDraw();
203 					fireChangeEvent();
204 				}
205 			});
206 
207             initEmptyLoList();
208 		}
209 
210 		protected void initEmptyLoList(){
211 			List<String> list = new ArrayList<String>();
212 			list.add("");
213 			list.add("");
214 			list.add("");
215 			list.add("");
216 			list.add("");
217 			addSelectedLOs(list);			
218 		}
219 		
220 		protected void fireChangeEvent(){
221 			ValueChangeEvent.fire(this, outlineModel.getOutlineNodes());
222 		}
223 		
224 		public List<OutlineNode<LOPicker>> getValue() {
225 			return outlineModel.getOutlineNodes();
226 		}
227 
228 		public void setValue(List<OutlineNode<LOPicker>> value) {
229 			outlineModel.clearNodes();
230 			outlineModel.getOutlineNodes().addAll(value);
231 
232 			if (value == null || value.isEmpty()){
233 				initEmptyLoList();
234 			} else {
235 				//Add selection change handler to LOPickers if not set
236 				for (OutlineNode<LOPicker> node:value){
237 					LOPicker picker = node.getUserObject();
238 					if (!picker.hasChangeHandler()){
239 						picker.addSelectionChangeHandler(loPickerChangeHandler);
240 					}
241 				}
242 				
243 				reDraw();
244 			}
245 		}
246 
247         private void appendLO(String loValue) {
248 			OutlineNode<LOPicker> aNode = new OutlineNode<LOPicker>();
249 			LOPicker newPicker = new LOPicker(messageGroup, type, state,
250 					repoKey);
251 
252 			newPicker.addSelectionChangeHandler(loPickerChangeHandler);
253 			newPicker.setLOText(loValue);
254 			aNode.setUserObject(newPicker);
255 			aNode.setModel(outlineModel);
256 
257 			outlineModel.addOutlineNode(aNode);
258 		}
259 
260 		// add one or more description by going through existing LO box and
261 		// populating the empty ones
262 		// if not enough empty LO boxes then add new ones
263 		public void addSelectedLOs(List<String> loDescription) {
264 
265 			List<OutlineNode<LOPicker>> existingLOs = outlineModel.getOutlineNodes();
266 
267 			int ix = existingLOs.size();
268 			for (String strValue : loDescription) {
269 
270 				boolean foundEmptyBox = false;
271 				
272 				for(int i=0;i<ix;i++)
273 				{
274 					if (existingLOs.get(i).getUserObject().getLOText().trim()
275 							.length() == 0) {
276 						existingLOs.get(i).getUserObject().setLOText(strValue);
277 						foundEmptyBox = true;
278 						i=ix;
279 					}
280 				}
281 
282 				// we didn't find empty LO box so add a new one
283 				if (foundEmptyBox == false) {
284 					appendLO(strValue);
285 				}
286 			}
287 			reDraw();
288 		}
289 
290 		private void reDraw() {
291             if (null != outlineComposite) {
292                 this.removeSection(outlineComposite);
293             }
294             this.removeWidget(addNew); // no error if it's not currently there
295             outlineComposite = new OutlineManager(startOfPath, middleOfPath, endOfPath);
296             outlineComposite.setValue(outlineModel);
297             this.addSection(outlineComposite);
298             this.addWidget(addNew);
299 			outlineComposite.render();
300 		}
301 
302 		public HandlerRegistration addValueChangeHandler(ValueChangeHandler<List<OutlineNode<LOPicker>>> handler) {
303 			return addHandler(handler, ValueChangeEvent.getType());
304 		}
305 		
306 		public SelectionChangeHandler getChangeHandlerForLOPicker(){
307 			return loPickerChangeHandler;
308 		}
309 
310 		@Override
311 		public void setValue(List<OutlineNode<LOPicker>> value,
312 				boolean fireEvents) {
313 			setValue(value);
314 		}
315 	}
316 
317     @Override
318     public ErrorLevel processValidationResults(FieldDescriptor fd, List<ValidationResultInfo> results) {
319         return processValidationResults(fd, results, true);
320     }
321 
322     @Override
323     public ErrorLevel processValidationResults(FieldDescriptor fd, List<ValidationResultInfo> results, boolean clearErrors) {
324 
325         ErrorLevel status = ErrorLevel.OK;
326         
327         for (Section section : getSections()) {
328             ErrorLevel level = section.processValidationResults(results, clearErrors);
329             if (level.getLevel() > status.getLevel()) {
330                 status = level;
331             }
332         }
333         return status;
334     }
335 
336 }