1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.student.common.ui.client.configurable.mvc.layouts;
17
18 import java.util.ArrayList;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Map.Entry;
23
24 import org.kuali.student.common.ui.client.configurable.mvc.LayoutController;
25 import org.kuali.student.common.ui.client.configurable.mvc.sections.Section;
26 import org.kuali.student.common.ui.client.configurable.mvc.views.SectionView;
27 import org.kuali.student.common.ui.client.event.ActionEvent;
28 import org.kuali.student.common.ui.client.event.SaveActionEvent;
29 import org.kuali.student.common.ui.client.mvc.ActionCompleteCallback;
30 import org.kuali.student.common.ui.client.mvc.Callback;
31 import org.kuali.student.common.ui.client.mvc.View;
32 import org.kuali.student.common.ui.client.widgets.KSButton;
33 import org.kuali.student.common.ui.client.widgets.containers.KSTitleContainerImpl;
34 import org.kuali.student.common.ui.client.widgets.menus.KSMenuItemData;
35 import org.kuali.student.common.ui.client.widgets.menus.impl.KSBlockMenuImpl;
36 import org.kuali.student.common.ui.client.widgets.tabs.KSTabPanel;
37 import org.kuali.student.common.validation.dto.ValidationResultInfo;
38 import org.kuali.student.common.validation.dto.ValidationResultInfo.ErrorLevel;
39
40 import com.google.gwt.event.dom.client.ClickEvent;
41 import com.google.gwt.event.dom.client.ClickHandler;
42 import com.google.gwt.user.client.ui.Composite;
43 import com.google.gwt.user.client.ui.FlowPanel;
44 import com.google.gwt.user.client.ui.HorizontalPanel;
45 import com.google.gwt.user.client.ui.SimplePanel;
46 import com.google.gwt.user.client.ui.VerticalPanel;
47 import com.google.gwt.user.client.ui.Widget;
48
49 public class TabbedSectionLayout extends LayoutController implements ConfigurableLayout{
50
51
52 private final Map<String, KSMenuItemData> menuHierarchyMap = new HashMap<String, KSMenuItemData>();
53
54 private Map<String, TabLayout> tabLayoutMap = new HashMap<String, TabLayout>();
55
56 private Map<String, String> sectionNameTabMap = new HashMap<String, String>();
57
58 private boolean loaded = false;
59 private final Map<String, Enum<?>> viewEnums = new HashMap<String, Enum<?>>();
60
61 Enum<?> defaultView = null;
62
63 private KSTabPanel tabPanel = new KSTabPanel();
64 private KSTitleContainerImpl container = new KSTitleContainerImpl();
65
66 private boolean updateableSection = true;
67
68 private class TabLayout extends Composite{
69 private FlowPanel layout = new FlowPanel();
70 private SimplePanel content = new SimplePanel();
71 private FlowPanel contentLayout = new FlowPanel();
72 private KSBlockMenuImpl menu = new KSBlockMenuImpl();
73
74 private int currSectionIdx = 0;
75 protected final ArrayList<View> orderedSectionViews = new ArrayList<View>();
76 private final HorizontalPanel sectionButtonPanel = new HorizontalPanel();
77 private final ArrayList<KSMenuItemData> sectionMenuItems = new ArrayList<KSMenuItemData>();
78 private final List<KSMenuItemData> topLevelMenuItems = new ArrayList<KSMenuItemData>();
79 private boolean menuAdded = false;
80 private Enum<?> tabDefaultView = null;
81
82 public Enum<?> getTabDefaultView() {
83 return tabDefaultView;
84 }
85
86 public void setTabDefaultView(Enum<?> tabDefaultView) {
87 this.tabDefaultView = tabDefaultView;
88 }
89
90 public HorizontalPanel getButtonPanel(){
91 return this.sectionButtonPanel;
92 }
93
94 public KSButton getNextButton() {
95 return nextButton;
96 }
97
98 private KSButton nextButton = new KSButton("Save & Continue", new ClickHandler(){
99 public void onClick(final ClickEvent event) {
100
101 final SaveActionEvent saveActionEvent = new SaveActionEvent();
102 saveActionEvent.setAcknowledgeRequired(false);
103 saveActionEvent.setActionCompleteCallback(new ActionCompleteCallback(){
104 public void onActionComplete(ActionEvent action) {
105 int nextSectionIndex = currSectionIdx + 1;
106
107 if (nextSectionIndex < sectionMenuItems.size()) {
108 sectionMenuItems.get(nextSectionIndex).getClickHandler().onClick(event);
109 }
110 }
111 });
112
113 fireApplicationEvent(saveActionEvent);
114 }
115 }
116 );
117
118 public TabLayout(){
119 if (updateableSection) {
120 sectionButtonPanel.add(nextButton);
121 }
122 menu.setTopLevelItems(topLevelMenuItems);
123 contentLayout.add(content);
124 contentLayout.add(sectionButtonPanel);
125
126 layout.add(contentLayout);
127 this.initWidget(layout);
128 }
129
130 public void init(){
131 contentLayout.setStyleName("ks-page-content");
132
133 menu.setStyleName("ks-page-sub-navigation-container");
134 menu.setTopLevelItems(topLevelMenuItems);
135 }
136
137 public void setContent(Widget content){
138 this.content.setWidget(content);
139 }
140
141 public void addMenuItem(String[] hierarchy, final SectionView section) {
142 String path = "";
143 StringBuilder pathBuffer= new StringBuilder();
144 pathBuffer.append(path);
145 KSMenuItemData current = null;
146 for (int i=1; i<hierarchy.length; i++) {
147
148
149 if(hierarchy[i]==null){
150 return;
151 }
152 pathBuffer.append("/");
153 pathBuffer.append(hierarchy[i]);
154 KSMenuItemData item = menuHierarchyMap.get(pathBuffer.toString());
155 if (item == null) {
156 item = new KSMenuItemData(hierarchy[i]);
157 if (current == null) {
158 topLevelMenuItems.add(item);
159 current = item;
160 } else {
161 current.addSubItem(item);
162 current = item;
163 }
164 menuHierarchyMap.put(pathBuffer.toString(), item);
165 } else {
166 current = item;
167 }
168 }
169
170 final KSMenuItemData sectionItem = new KSMenuItemData(section.getName());
171 current.addSubItem(sectionItem);
172 sectionMenuItems.add(sectionItem);
173 orderedSectionViews.add(section);
174
175 sectionItem.setClickHandler(new ClickHandler() {
176 public void onClick(ClickEvent event) {
177
178 int newMenuItemIdx = sectionMenuItems.indexOf(sectionItem);
179 if (currSectionIdx != newMenuItemIdx){
180 currSectionIdx = newMenuItemIdx;
181 sectionButtonPanel.setVisible(true);
182 showView(section.getViewEnum(), NO_OP_CALLBACK);
183 }
184 }
185 });
186
187 if(!menuAdded){
188 layout.insert(menu, 0);
189 menuAdded = true;
190 }
191
192 if (tabDefaultView == null){
193 tabDefaultView = section.getViewEnum();
194 }
195 }
196
197 public void renderView(View view) {
198 content.setWidget((Widget)view);
199 if(menuAdded){
200 if (currSectionIdx == sectionMenuItems.size() - 1){
201 nextButton.setVisible(false);
202 } else {
203 nextButton.setVisible(true);
204 }
205 currSectionIdx = orderedSectionViews.indexOf(view);
206 if(currSectionIdx == -1){
207 return;
208 }
209 sectionMenuItems.get(currSectionIdx).setSelected(true);
210 }
211 else{
212 nextButton.setVisible(false);
213 }
214 }
215
216 public void removeContent() {
217 content.clear();
218 }
219
220 public void addButton(KSButton button) {
221 sectionButtonPanel.add(button);
222 }
223
224 public void clear() {
225 for (View view:orderedSectionViews){
226 view.clear();
227 }
228
229 }
230
231 public void updateModel() {
232 for(View sectionView : orderedSectionViews){
233 sectionView.updateModel();
234 }
235
236 }
237
238 public void beforeShow(final Callback<Boolean> onReadyCallback) {
239 showView(tabDefaultView, onReadyCallback);
240 }
241
242
243 }
244
245 private void init(){
246 for(TabLayout layout: tabLayoutMap.values()){
247 layout.init();
248 }
249 }
250
251 public TabbedSectionLayout(String controllerId){
252 super();
253 container.setContent(tabPanel);
254 container.setTitle("New Course Proposal");
255 super.initWidget(container);
256 }
257
258 public TabbedSectionLayout(String controllerId, KSTitleContainerImpl container){
259 super();
260 this.container.setContent(tabPanel);
261 this.container.setTitle(container.getTitle());
262 this.container.setStatus(container.getStatus());
263 this.container.setLinkText(container.getLinkText());
264 super.initWidget(this.container);
265 }
266
267
268 public KSTitleContainerImpl getContainer(){
269 return this.container;
270 }
271
272 public void setContainer(KSTitleContainerImpl container){
273 this.container=container;
274 }
275
276 @Override
277 public <V extends Enum<?>> void getView(V viewType, Callback<View> callback) {
278 callback.exec(viewMap.get(viewType));
279 }
280
281 @Override
282 public Enum<?> getViewEnumValue(String enumValue) {
283 return viewEnums.get(enumValue);
284 }
285
286 public boolean isUpdateableSection() {
287 return updateableSection;
288 }
289
290 public void setUpdateableSection(boolean isUpdateable) {
291 this.updateableSection = isUpdateable;
292 }
293
294 @Override
295 protected void hideView(View view) {
296
297
298
299
300 }
301
302 @Override
303 protected void renderView(View view) {
304 String tabName = sectionNameTabMap.get(view.getName());
305 if(!(tabPanel.getSelectedTabKey().equals(tabName))){
306 tabPanel.selectTab(tabName);
307 }
308 TabLayout layout = tabLayoutMap.get(tabName);
309
310 layout.renderView(view);
311 view.getName();
312 }
313
314 @Override
315 public void showDefaultView(final Callback<Boolean> onReadyCallback) {
316 if (!loaded){
317 init();
318 loaded = true;
319 }
320
321 super.showDefaultView(onReadyCallback);
322 }
323
324 @Override
325 public void addSection(String[] hierarchy, final SectionView section) {
326 viewEnums.put(section.getViewEnum().toString(), section.getViewEnum());
327 String tabKey = hierarchy[0];
328
329 sectionNameTabMap.put(section.getName(), tabKey);
330 viewMap.put(section.getViewEnum(), section);
331 section.setController(this);
332 section.setLayoutController(this);
333
334 final TabLayout layout;
335 if(!(tabPanel.hasTabKey(tabKey))){
336 layout = new TabLayout();
337 tabLayoutMap.put(tabKey, layout);
338 tabPanel.addTab(tabKey, tabKey, layout);
339 if(section != null){
340 layout.setTabDefaultView(section.getViewEnum());
341 }
342
343
344 tabPanel.addTabCustomCallback(tabKey, new Callback<String>(){
345
346 @Override
347 public void exec(String result) {
348 layout.beforeShow(NO_OP_CALLBACK);
349 }
350
351 });
352 }
353 else{
354 layout = tabLayoutMap.get(tabKey);
355 }
356
357 if(hierarchy.length > 1){
358 layout.addMenuItem(hierarchy, section);
359 }
360 else{
361 layout.renderView(section);
362 }
363
364 if (defaultView == null){
365 defaultView = section.getViewEnum();
366 }
367 }
368
369 public void addToolbar(Widget toolbar){
370 this.container.setToolbar(toolbar);
371 }
372
373 public void showStartSection(final Callback<Boolean> onReadyCallback){
374 this.showStartPopup(onReadyCallback);
375 }
376
377 public SectionView getStartSection(){
378 if(startPopupView instanceof SectionView){
379 return (SectionView)startPopupView;
380 }
381 else{
382 return null;
383 }
384
385 }
386
387 @Override
388 public void addStartSection(final SectionView section){
389 this.addStartViewPopup(section);
390
391 HorizontalPanel buttonPanel = new HorizontalPanel();
392
393 VerticalPanel panel = new VerticalPanel();
394 panel.add(section);
395 buttonPanel.add(new KSButton("Save",new ClickHandler(){
396 public void onClick(ClickEvent event) {
397 section.updateModel();
398 SaveActionEvent saveActionEvent = new SaveActionEvent();
399
400 saveActionEvent.setActionCompleteCallback(new ActionCompleteCallback(){
401 public void onActionComplete(ActionEvent action) {
402 startViewWindow.hide();
403 }
404 });
405
406 fireApplicationEvent(saveActionEvent);
407 }
408 }));
409 buttonPanel.add(new KSButton("Cancel", new ClickHandler(){
410 public void onClick(ClickEvent event) {
411 startViewWindow.hide();
412 }
413 }));
414
415 panel.add(buttonPanel);
416 section.setController(this);
417 startViewWindow.setWidget(panel);
418 }
419
420 public void addButton(String tabKey, KSButton button){
421 TabLayout layout = tabLayoutMap.get(tabKey);
422
423 if(layout != null){
424 layout.addButton(button);
425 }
426
427 }
428
429 public HorizontalPanel getButtonPanel(String tabKey){
430 TabLayout layout = tabLayoutMap.get(tabKey);
431
432 if(layout != null){
433 return layout.getButtonPanel();
434 }
435 return null;
436 }
437
438 public KSButton getNextButton(String tabKey) {
439 TabLayout layout = tabLayoutMap.get(tabKey);
440
441 if (layout != null) {
442 return layout.getNextButton();
443 }
444 return null;
445 }
446
447 public void clear(){
448 super.clear();
449 for(TabLayout layout: tabLayoutMap.values()){
450 layout.clear();
451 }
452
453
454 }
455
456 public void updateModel(){
457 for(TabLayout layout: tabLayoutMap.values()){
458 layout.updateModel();
459 }
460 }
461
462
463
464
465
466
467
468
469 public boolean isValid(List<ValidationResultInfo> validationResults, boolean checkCurrentSectionOnly){
470 boolean isValid = true;
471
472 if (checkCurrentSectionOnly){
473
474 if(this.isStartViewShowing()){
475 isValid = isValid(validationResults, getStartSection());
476 } else {
477 View v = getCurrentView();
478 if(v instanceof Section){
479 isValid = isValid(validationResults, (Section)v);
480 }
481 }
482 } else {
483
484 container.clearMessages();
485 String errorSections = "";
486 StringBuilder errorSectionsbuffer = new StringBuilder();
487 errorSectionsbuffer.append(errorSections);
488 for (Entry<Enum<?>, View> entry:viewMap.entrySet()) {
489 View v = entry.getValue();
490 if (v instanceof Section){
491 if (!isValid(validationResults, (Section)v)){
492 isValid = false;
493 errorSectionsbuffer.append(((SectionView)v).getName() + ", ");
494
495 }
496 }
497 }
498 errorSections = errorSectionsbuffer.toString();
499 if (!errorSections.isEmpty()){
500 errorSections = errorSections.substring(0, errorSections.length()-2);
501 container.addMessage("Following section(s) has errors & must be corrected: " + errorSections);
502 }
503 }
504
505 return isValid;
506 }
507
508 private boolean isValid(List<ValidationResultInfo> validationResults, Section section){
509 section.setFieldHasHadFocusFlags(true);
510 ErrorLevel status = section.processValidationResults(validationResults);
511
512 return (status != ErrorLevel.ERROR);
513 }
514 }