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