Coverage Report - org.kuali.student.lum.common.client.lo.CategoryManagementTable
 
Classes in this File Line Coverage Branch Coverage Complexity
CategoryManagementTable
0%
0/194
0%
0/82
2.548
CategoryManagementTable$1
0%
0/7
0%
0/2
2.548
CategoryManagementTable$2
0%
0/9
N/A
2.548
CategoryManagementTable$CategoryRow
0%
0/7
N/A
2.548
 
 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.Collections;
 20  
 import java.util.HashSet;
 21  
 import java.util.List;
 22  
 
 23  
 import org.kuali.student.common.search.dto.SearchRequest;
 24  
 import org.kuali.student.common.search.dto.SearchResult;
 25  
 import org.kuali.student.common.search.dto.SearchResultCell;
 26  
 import org.kuali.student.common.search.dto.SearchResultRow;
 27  
 import org.kuali.student.common.ui.client.application.KSAsyncCallback;
 28  
 import org.kuali.student.common.ui.client.mvc.Callback;
 29  
 import org.kuali.student.common.ui.client.service.SearchRpcService;
 30  
 import org.kuali.student.common.ui.client.service.SearchRpcServiceAsync;
 31  
 import org.kuali.student.common.ui.client.service.ServerPropertiesRpcService;
 32  
 import org.kuali.student.common.ui.client.service.ServerPropertiesRpcServiceAsync;
 33  
 import org.kuali.student.common.ui.client.widgets.searchtable.ResultRow;
 34  
 import org.kuali.student.common.ui.client.widgets.table.scroll.Column;
 35  
 import org.kuali.student.common.ui.client.widgets.table.scroll.DefaultTableModel;
 36  
 import org.kuali.student.common.ui.client.widgets.table.scroll.Row;
 37  
 import org.kuali.student.common.ui.client.widgets.table.scroll.Table;
 38  
 import org.kuali.student.lum.lo.dto.LoCategoryInfo;
 39  
 
 40  
 import com.google.gwt.core.client.GWT;
 41  
 import com.google.gwt.user.client.Window;
 42  
 import com.google.gwt.user.client.ui.Composite;
 43  
 import com.google.gwt.user.client.ui.FlowPanel;
 44  
 
 45  
 
 46  
 /**
 47  
  * This is a description of what this class does - Gary Struthers don't forget to fill this in. 
 48  
  * 
 49  
  * @author Kuali Student Team (gstruthers@berkeley.edu)
 50  
  *
 51  
  */
 52  0
 public class CategoryManagementTable extends Composite {
 53  0
     static String NAME_COLUMN_HEADER = "Category";
 54  0
     static String TYPE_COLUMN_HEADER = "Type";
 55  0
     static String STATE_COLUMN_HEADER = "State";
 56  0
     static String ID_COLUMN_KEY = "id";
 57  0
     static String NAME_COLUMN_KEY = "name";
 58  0
     static String TYPE_COLUMN_KEY = "type";
 59  0
     static String TYPE_NAME_COLUMN_KEY = "typeName";
 60  0
     static String STATE_COLUMN_KEY = "state";
 61  0
     private List<ResultRow> resultRows = new ArrayList<ResultRow>();
 62  0
     private DefaultTableModel model = new DefaultTableModel();        //Contains Category rows that go into 'Select Categories' KSLightBox [KSLAB-2091]
 63  0
     private Table table = new Table();
 64  
     //private GenericTableModel<ResultRow> tableModel = new GenericTableModel<ResultRow>(resultRows);
 65  
     //private PagingScrollTableBuilder<ResultRow> builder = new PagingScrollTableBuilder<ResultRow>();
 66  
     //protected PagingScrollTable<ResultRow> pagingScrollTable;
 67  0
     private FlowPanel layout = new FlowPanel();
 68  
     private static Boolean displayOnlyActiveCategories; // static global
 69  0
     private boolean hideInactiveCategories = false;
 70  
 
 71  0
     private SearchRpcServiceAsync searchDispatcherAsync = GWT.create(SearchRpcService.class); //KSLAB-2091
 72  
 
 73  0
     private static ServerPropertiesRpcServiceAsync serverProperties = GWT.create(ServerPropertiesRpcService.class);
 74  
 
 75  
     // Categories to filter out after the are loaded from the backend
 76  
     // See KSLAB-1871
 77  0
     private List<LoCategoryInfo> loCategoriesToFilter = new ArrayList<LoCategoryInfo>();
 78  
     
 79  
     class CategoryRow extends Row{
 80  
             ResultRow row;
 81  
             
 82  0
             public CategoryRow(ResultRow row){
 83  0
                     this.row = row;
 84  0
             }
 85  
                 @Override
 86  
                 public Object getCellData(String columnId) {
 87  0
                         return row.getValue(columnId);
 88  
                 }
 89  
                 @Override
 90  
                 public void setCellData(String columnId, Object newValue) {
 91  0
                         row.setValue(columnId, newValue.toString());                
 92  0
                 }
 93  
                 
 94  
                 public ResultRow getResultRowData(){
 95  0
                         return row;
 96  
                 }
 97  
         }
 98  
     
 99  
     public Table getTable(){
 100  0
             return table;
 101  
     }
 102  
     
 103  
     /**
 104  
      * This method should be called before constructor so config flag is pre-set
 105  
      * only needs to be called once. It's a static flag that only changes when the 
 106  
      * server is started
 107  
      * 
 108  
      */
 109  
     public static void setDisplayOnlyActiveCategories() {
 110  0
         if (null == displayOnlyActiveCategories) {
 111  0
             serverProperties.get("ks.lum.ui.displayOnlyActiveLoCategories", new KSAsyncCallback<String>() {
 112  
                 @Override
 113  
                 public void handleFailure(Throwable caught) {
 114  0
                     GWT.log("get displayOnlyActiveLoCategories failed", caught);
 115  0
                     Window.alert("Failed to get displayOnlyActiveLoCategories setting");
 116  0
                 }
 117  
     
 118  
                 @Override
 119  
                 public void onSuccess(String result) {
 120  0
                     if (result != null) {
 121  0
                         displayOnlyActiveCategories = Boolean.parseBoolean(result);
 122  
                     }
 123  0
                 }
 124  
             });
 125  
         }  
 126  0
     }
 127  
     
 128  
     private void initCategoryManagementTable(boolean isMultiSelect){
 129  0
         layout.setWidth("100%");
 130  0
         table.setWidth("550px");
 131  0
         table.getScrollPanel().setHeight("400px");
 132  0
         initWidget(layout);
 133  0
         createColumnDefs();
 134  0
         if(isMultiSelect){
 135  0
                 model.setMultipleSelectable(true);
 136  0
                 model.installCheckBoxRowHeaderColumn();
 137  
         }
 138  
         else{
 139  0
                 model.setMultipleSelectable(false);
 140  
         }
 141  0
         table.setTableModel(model);
 142  
         
 143  0
         layout.add(table);
 144  0
     }
 145  
     public CategoryManagementTable() {
 146  0
         super();
 147  0
         initCategoryManagementTable(false);
 148  0
     }
 149  
     /**
 150  
      * Constructor that allows us to filter categories.
 151  
      * <p>
 152  
      * Currently used to filter categories that are already in the picker. 
 153  
      * <p>
 154  
      *  See KSLAB-1871
 155  
      *
 156  
      * @param hideInactiveCategories
 157  
      * @param isMultiSelect
 158  
      * @param loCategoriesToFilter categories to filter out
 159  
      */
 160  
     public CategoryManagementTable(boolean hideInactiveCategories, boolean isMultiSelect, List<LoCategoryInfo> loCategoriesToFilter) {
 161  0
         super();
 162  0
         this.hideInactiveCategories = hideInactiveCategories;
 163  0
         this.loCategoriesToFilter = loCategoriesToFilter;  // needed in constructor due to async
 164  0
         initCategoryManagementTable(isMultiSelect);
 165  0
     }
 166  
     /**
 167  
      * This constructs a CategoryManagementTable with an instance option
 168  
      * 
 169  
      * @param hideInactiveCategories
 170  
      */
 171  
     public CategoryManagementTable(boolean hideInactiveCategories, boolean isMultiSelect) {
 172  0
         super();
 173  0
         this.hideInactiveCategories = hideInactiveCategories;
 174  0
         initCategoryManagementTable(isMultiSelect);
 175  0
     }
 176  
     /**
 177  
      * Two flags control whether to show rows with inactive categories and the state column.
 178  
      * hideInactiveCategories can be set per table instance
 179  
      * displayOnlyActiveCategories is set at Lum startup
 180  
      * hideInactiveCategories overrides displayOnlyActiveCategories
 181  
      * @return true to show all rows and State column
 182  
      */
 183  
     public boolean isHideInactiveCategories() {
 184  0
         if(hideInactiveCategories){
 185  0
             return true;
 186  
         } 
 187  0
         if((displayOnlyActiveCategories == null)||( displayOnlyActiveCategories.booleanValue() == false)){
 188  0
             return false;
 189  
         }else {
 190  0
             return true;
 191  
         }
 192  
     }
 193  
     /**
 194  
      * @param show or hide inactive rows and State column 
 195  
      */
 196  
     public void setHideInactiveCategories(boolean show) {
 197  0
         this.hideInactiveCategories = show;
 198  0
     }
 199  
     public void redraw(){
 200  0
             model.clearRows();
 201  0
             for(ResultRow row: resultRows){
 202  0
                     model.addRow(new CategoryRow(row));
 203  
             }
 204  0
             model.fireTableDataChanged();
 205  0
     }
 206  
     
 207  
     public void redraw(List<ResultRow> filteredRows){
 208  0
             model.clearRows();
 209  0
             table.removeAllRows();
 210  0
             for(ResultRow row: filteredRows){
 211  0
                     model.addRow(new CategoryRow(row));
 212  
             }
 213  0
             model.setCurrentIndex(0);
 214  0
             model.fireTableDataChanged();
 215  0
     }
 216  
 
 217  
     public void clearTable(){
 218  0
         resultRows.clear();
 219  0
         redraw();        
 220  0
     }
 221  
     
 222  
     public void removeSelected(){
 223  0
         for(ResultRow r: getSelectedRows()){
 224  0
             resultRows.remove(r);
 225  
         }
 226  0
         this.redraw();
 227  0
     }
 228  
     public List<ResultRow> getAllRows(){
 229  0
         List<ResultRow> rows = new ArrayList<ResultRow>();
 230  0
         for(ResultRow r: resultRows){
 231  0
             rows.add(r);
 232  
         }
 233  0
         return rows;
 234  
     }    
 235  
     public List<ResultRow> getSelectedRows(){
 236  0
         List<ResultRow> rows = new ArrayList<ResultRow>();
 237  0
         List<Row> selectedRows = model.getSelectedRows();
 238  0
         for(Row r: selectedRows){
 239  0
             rows.add(((CategoryRow)r).getResultRowData());
 240  
         }
 241  0
         return rows;
 242  
     }
 243  
     public List<LoCategoryInfo> getSelectedLoCategoryInfos(){
 244  0
         List<LoCategoryInfo> loCategoryInfos = new ArrayList<LoCategoryInfo>();
 245  0
         List<Row> selectedRows = model.getSelectedRows();
 246  0
         if(selectedRows.isEmpty()) {
 247  0
             return loCategoryInfos;
 248  
         }
 249  0
         for(Row r: selectedRows){
 250  0
             LoCategoryInfo loCategoryInfo = new LoCategoryInfo();
 251  0
             loCategoryInfo.setId(r.getCellData(ID_COLUMN_KEY).toString());
 252  0
             loCategoryInfo.setName(r.getCellData(NAME_COLUMN_KEY).toString());
 253  0
             loCategoryInfo.setType(r.getCellData(TYPE_COLUMN_KEY).toString());
 254  0
             loCategoryInfo.setState(r.getCellData(STATE_COLUMN_KEY).toString());
 255  0
             loCategoryInfos.add(loCategoryInfo);
 256  0
         }
 257  0
         return loCategoryInfos;
 258  
     }    
 259  
 
 260  
     public String getSelectedLoCategoryInfoId(){ 
 261  0
         List<Row> selectedRows = model.getSelectedRows();
 262  0
         if(selectedRows.isEmpty()) {
 263  0
             return null;
 264  
         }
 265  0
         String id = null;
 266  0
         for(Row r: selectedRows){
 267  0
             id = r.getCellData(ID_COLUMN_KEY).toString();
 268  0
             break;
 269  
         }
 270  0
         return id;
 271  
 
 272  
     }   
 273  
     
 274  
     private void createColumnDefs() {
 275  
             
 276  0
             Column name = new Column();
 277  0
             name.setName(NAME_COLUMN_HEADER);
 278  0
             name.setId(NAME_COLUMN_KEY);
 279  0
             name.setSortable(false);
 280  0
             model.addColumn(name);
 281  0
             name.setWidth("250px");
 282  
             
 283  0
             Column type = new Column();
 284  0
             type.setName(TYPE_COLUMN_HEADER);
 285  0
             type.setId(TYPE_NAME_COLUMN_KEY);
 286  0
             type.setSortable(false);
 287  0
             model.addColumn(type);
 288  
             
 289  0
         if (!isHideInactiveCategories()) {
 290  0
                 Column state = new Column();
 291  0
                 state.setName(STATE_COLUMN_HEADER);
 292  0
                 state.setId(STATE_COLUMN_KEY);
 293  0
                 state.setSortable(false);
 294  0
                 model.addColumn(state);          
 295  
         }
 296  0
     }
 297  
     
 298  
     /**
 299  
      * 
 300  
      * This method will filter out categories that should be excluded 
 301  
      * from the list (e.g. those already in the picker).
 302  
      * <p>
 303  
      * It is called from the filterResults method.
 304  
      * <p>
 305  
      * See KSLAB-1871
 306  
      * 
 307  
      * @param results
 308  
      * @return
 309  
      */
 310  
     private List<LoCategoryInfo> filterResultsWithExcludedCategories(List<LoCategoryInfo> results){
 311  0
         if (loCategoriesToFilter == null || loCategoriesToFilter.size() == 0){
 312  
             // If nothing to filter just return results passed in
 313  0
             return results;
 314  
         }
 315  0
         List<LoCategoryInfo> filteredResults = new ArrayList<LoCategoryInfo>();
 316  0
         for(LoCategoryInfo result : results) {
 317  0
             boolean shouldExcludeRow = false;
 318  0
             for (LoCategoryInfo toFilter : loCategoriesToFilter) {
 319  0
                 String name = toFilter.getName();
 320  0
                 String type = toFilter.getType();
 321  0
                 if (result.getName().equals(name) && result.getType().equals(type)){
 322  0
                     shouldExcludeRow = true;
 323  0
                     break;
 324  
                 }
 325  0
             } 
 326  0
             if (!shouldExcludeRow){
 327  0
                 filteredResults.add(result);
 328  
             }
 329  0
         }
 330  0
         return filteredResults;
 331  
     }
 332  
 
 333  
     
 334  
     private List<LoCategoryInfo> filterResults(List<LoCategoryInfo> result) {
 335  
 
 336  
        // Filter if already in picker etc
 337  0
        result = filterResultsWithExcludedCategories(result);
 338  
   
 339  0
        if(isHideInactiveCategories()) {
 340  0
             List<LoCategoryInfo> filteredResult = new ArrayList<LoCategoryInfo>();
 341  0
             for(LoCategoryInfo info : result) {
 342  0
                 if (info.getState().equals("active") ) {
 343  0
                     filteredResult.add(info);
 344  
                 }
 345  
             }
 346  0
             return filteredResult;
 347  
         } 
 348  0
         return result;   
 349  
     }
 350  
     
 351  
     public void loadTable(final Callback<Boolean> callback) {
 352  0
             table.displayLoading(true);
 353  
             /* KSLAB-2091
 354  
              * 
 355  
              * This is the new way to initiate a query for loCategories:
 356  
              *                 It is a searchDispatcherAsync call that returns a SearchResult on success;
 357  
              *                         the SearchResult has the necessary CategoryType name info.
 358  
              *                         Furthermore this is the usual way scenarios similar to Browse Categories are implemented.
 359  
              * 
 360  
              *         [The old way was a loCatRpcServiceAsync call that returned LoCategoryInfos on success;
 361  
              *                         the loCategoryInfos did not have necessary CategoryType name info,
 362  
              *                                 and loCategories cannot be changed without affecting versioning 
 363  
              *                                 (which does not seem worth it given this present fix with searchDispatcherAsync).
 364  
              *                         Furthermore the old way was not the usual way scenarios similar to Browse Categories are implemented.]
 365  
              * 
 366  
              * KSLAB-2091         
 367  
              */
 368  0
             searchDispatcherAsync.search(new SearchRequest("lo.search.loCategories"), new KSAsyncCallback<SearchResult>() {
 369  
             @Override
 370  
             public void handleFailure(Throwable caught) {
 371  0
                 GWT.log("lo.search.loCategories failed", caught);
 372  0
                 Window.alert("lo.search.loCategories failed");
 373  0
                 callback.exec(false);
 374  0
             }
 375  
 
 376  
                         @Override
 377  
                         public void onSuccess(SearchResult results) {
 378  0
                                 loadTable(results);
 379  0
                 callback.exec(true);
 380  0
                 table.displayLoading(false);
 381  0
                         }
 382  
         });
 383  
             //KSLAB-2091
 384  0
     }
 385  
     
 386  
     private void loadTable(SearchResult results) {        /*Additional overload of loadTableto accommodate call from new loadTable(final Callback<Boolean> callback), 
 387  
                                                                                                                                                                                                                             which is directly above [KSLAB-2091]*/
 388  
             
 389  0
         resultRows.clear();
 390  
         
 391  0
         HashSet<String> hashSet = new HashSet<String>();
 392  0
         String curCatID = null, curCatNAME= null, curCatTYPEID= null, curCatTYPENAME= null, curCatSTATE=null;
 393  0
         String curSearchResultCellKEY= null;
 394  
         
 395  0
         for(SearchResultRow curSearchResultRow: results.getRows()) {
 396  0
                 for(SearchResultCell curSearchResultCell: curSearchResultRow.getCells()){        //Extracts necessary fields that will be added to resultRow below.
 397  0
                         curSearchResultCellKEY= curSearchResultCell.getKey();
 398  0
                         if(curSearchResultCellKEY.equals("lo.resultColumn.categoryId")){
 399  0
                                 curCatID= curSearchResultCell.getValue();
 400  0
                         }else if(curSearchResultCellKEY.equals("lo.resultColumn.categoryName")){
 401  0
                                 curCatNAME= curSearchResultCell.getValue();
 402  0
                         }else if(curSearchResultCellKEY.equals("lo.resultColumn.categoryType")){
 403  0
                                 curCatTYPEID= curSearchResultCell.getValue();
 404  0
                         }else if(curSearchResultCellKEY.equals("lo.resultColumn.categoryTypeName")){
 405  0
                             curCatTYPENAME= curSearchResultCell.getValue();
 406  0
                 }else if(curSearchResultCellKEY.equals("lo.resultColumn.categoryState")){        //From new bean in lo-search-config.xml
 407  0
                                 curCatSTATE= curSearchResultCell.getValue();
 408  
                 }
 409  
                 }
 410  
                 
 411  0
             if (isHideInactiveCategories() && curCatSTATE.equalsIgnoreCase("inactive")) {
 412  0
                 continue;
 413  
             }
 414  
 
 415  0
             ResultRow resultRow = new ResultRow();
 416  
             
 417  0
             if (!hashSet.contains(curCatID)) {
 418  0
                 hashSet.add(curCatID);
 419  0
                 resultRow.setValue(ID_COLUMN_KEY, curCatID);
 420  0
                 resultRow.setValue(NAME_COLUMN_KEY, curCatNAME);
 421  0
                 resultRow.setValue(TYPE_COLUMN_KEY, curCatTYPEID);
 422  0
                 resultRow.setValue(TYPE_NAME_COLUMN_KEY, curCatTYPENAME);
 423  0
                 resultRow.setValue(STATE_COLUMN_KEY, curCatSTATE);
 424  0
                 resultRows.add(resultRow);                
 425  
             }
 426  0
         }        //Correct resultRows now loaded [KSLAB-2091]
 427  0
         Collections.sort(resultRows);
 428  0
         redraw();
 429  0
     }
 430  
 
 431  
     public List<ResultRow> getRowsByType(String type){
 432  0
         List<ResultRow> bufferList = new ArrayList<ResultRow>();
 433  0
         for(ResultRow row : resultRows) {
 434  0
             if(row.getValue(TYPE_COLUMN_KEY).contains(type)){
 435  0
                 bufferList.add(row);
 436  
             }
 437  
         }
 438  0
         return bufferList;
 439  
     }
 440  
     
 441  
     public List<ResultRow> getRowsLikeName(String name){
 442  0
         List<ResultRow> bufferList = new ArrayList<ResultRow>();
 443  0
         for(ResultRow row : resultRows) {
 444  0
             String nameValue = row.getValue(NAME_COLUMN_KEY);
 445  0
             if(nameValue != null) {
 446  0
                 String[] words = nameValue.split("\\W");
 447  0
                 for(String word : words){
 448  0
                     if(word.toUpperCase().startsWith(name.toUpperCase())){
 449  0
                         bufferList.add(row);
 450  0
                         break;
 451  
                     }                    
 452  
                 }
 453  
             }
 454  0
         }
 455  0
         return bufferList;
 456  
     }
 457  
 }