ListWidget.java :  » Web-Framework » aranea-mvc-1.1.1 » org » araneaframework » uilib » list » Java Open Source

Java Open Source » Web Framework » aranea mvc 1.1.1 
aranea mvc 1.1.1 » org » araneaframework » uilib » list » ListWidget.java
/**
 * Copyright 2006 Webmedia Group Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

package org.araneaframework.uilib.list;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.araneaframework.InputData;
import org.araneaframework.backend.list.model.ListItemsData;
import org.araneaframework.core.AraneaRuntimeException;
import org.araneaframework.core.BaseApplicationWidget;
import org.araneaframework.core.StandardEventListener;
import org.araneaframework.core.util.ExceptionUtil;
import org.araneaframework.uilib.ConfigurationContext;
import org.araneaframework.uilib.core.BaseUIWidget;
import org.araneaframework.uilib.event.OnClickEventListener;
import org.araneaframework.uilib.form.FormElement;
import org.araneaframework.uilib.form.FormWidget;
import org.araneaframework.uilib.form.GenericFormElement;
import org.araneaframework.uilib.form.control.ButtonControl;
import org.araneaframework.uilib.list.dataprovider.ListDataProvider;
import org.araneaframework.uilib.list.structure.ListField;
import org.araneaframework.uilib.list.structure.ListFilter;
import org.araneaframework.uilib.list.structure.ListStructure;
import org.araneaframework.uilib.list.structure.filter.FieldFilterHelper;
import org.araneaframework.uilib.list.structure.filter.FilterHelper;
import org.araneaframework.uilib.list.structure.order.FieldOrder;
import org.araneaframework.uilib.list.util.ListUtil;
import org.araneaframework.uilib.support.UiLibMessages;
import org.araneaframework.uilib.util.Event;

/**
 * This class is the base widget for lists. It interacts with the user and uses the data from
 * {@link org.araneaframework.uilib.list.dataprovider.ListDataProvider}to make a user view into the list.
 * It uses helper classes to do ordering, filtering and sequencing (breaking the list into pages).
 * <p>
 * Note that {@link ListWidget} must be initialized before it can be
 * configured.
 * 
 * @author Jevgeni Kabanov (ekabanov <i>at</i> araneaframework <i>dot</i> org)
 * @author Rein Raudjrv
 */
public class ListWidget extends BaseUIWidget implements ListContext {

  private static final long serialVersionUID = 1L;

  protected static final Log log = LogFactory.getLog(ListWidget.class);

  //*******************************************************************
  // FIELDS
  //*******************************************************************

  /** The filter form id. */
  public static final String FILTER_FORM_NAME = "form";

  /** The filter button id */
  public static final String FILTER_BUTTON_ID = "filter";
  /** The rest filter button id */
  public static final String FILTER_RESET_BUTTON_ID = "clearFilter";

  /** The multi-ordering form name. */
  public static final String ORDER_FORM_NAME = "orderForm";

  protected ListStructure listStructure;              // should not be accessible by public methods
  protected ListDataProvider dataProvider;

  protected TypeHelper typeHelper;
  protected FilterHelper filterHelper; 
  protected SequenceHelper sequenceHelper;            // should not be accessible by public methods  

  protected FormWidget form = new FormWidget();          // is transfomed into filter info Map and vice-versa
  protected OrderInfo orderInfo = new OrderInfo();

  protected List itemRange;
  protected Map requestIdToRow = new HashMap();
  
  private List initEvents = new ArrayList();
  
  private boolean changed = true;
  private DataProviderDataUpdateListener dataProviderDataUpdateListener = new DataProviderDataUpdateListener();

  //*********************************************************************
  //* CONSTRUCTOR
  //*********************************************************************
  
  /**
   * Creates a new {@link ListWidget} instance. 
   */
  public ListWidget() {
    typeHelper = createTypeHelper();
    filterHelper = createFilterHelper();
    listStructure = createListStructure();
  }

  //*********************************************************************
  //* PUBLIC METHODS
  //*********************************************************************

  /* ========== List configuration ========== */  

  /**
   * Returns the {@link ListStructure}used to describe the list.
   * 
   * @return the {@link ListStructure}used to describe the list.
   */
  public ListStructure getListStructure() {
    return this.listStructure;
  }

  /**
   * Saves the {@link ListStructure}used to fill the list with data.
   */
  public void setListStructure(ListStructure listStructure) {
    this.listStructure = listStructure;
  }

  /**
   * Returns the {@link ListDataProvider}used to fill the list with data.
   * 
   * @return the {@link ListDataProvider}used to fill the list with data.
   */
  public ListDataProvider getDataProvider() {
    return this.dataProvider;
  }

  /**
   * Sets the {@link ListDataProvider}used to fill the list with data.
   * 
   * @param dataProvider the {@link ListDataProvider}used to fill the list with data.
   */
  public void setDataProvider(ListDataProvider dataProvider) {
    if (this.dataProvider != null)
      this.dataProvider.removeDataUpdateListener(dataProviderDataUpdateListener);

    this.dataProvider = dataProvider;
    this.dataProvider.addDataUpdateListener(dataProviderDataUpdateListener);

    try {
      if (isInitialized()) {
        initDataProvider();
      }
    } catch (Exception e) {
      ExceptionUtil.uncheckException(e);
    }

    fireChange();
  }

  /**
   * Returns the {@link TypeHelper} used to help with field types.
   * 
   * @return the {@link TypeHelper} used to help with field types.
   */
  public TypeHelper getTypeHelper() {
    return this.typeHelper;
  }  

  /**
   * Sets the {@link TypeHelper} used to help with field types.
   * 
   * @param typeHelper {@link TypeHelper} used to help with field types.
   */
  public void setTypeHelper(TypeHelper typeHelper) {
    this.typeHelper = typeHelper;
  }

  /**
   * Returns the {@link FilterHelper} used to help with adding filters.
   * 
   * @return the {@link FilterHelper} used to help with adding filters.
   */
  public FilterHelper getFilterHelper() {
    return filterHelper;
  }

  /**
   * Sets the {@link FilterHelper} used to help with adding filters.
   * 
   * @param filterHelper {@link FilterHelper} used to help with adding filters.
   */
  public void setFilterHelper(FilterHelper filterHelper) {
    this.filterHelper = filterHelper;
  }

  /**
   * Returns the {@link FieldFilterHelper} used to help with adding filters
   * for specified field.
   * 
   * @return the {@link FieldFilterHelper} used to help with adding filters
   * for specified field.
   */
  public FieldFilterHelper getFilterHelper(String fieldId) {
    return new FieldFilterHelper(filterHelper, fieldId);
  }

  /**
   * Returns the {@link SequenceHelper}used to output pages.
   * 
   * @return the {@link SequenceHelper}used to output pages.
   */
  public SequenceHelper getSequenceHelper() {
    return this.sequenceHelper;
  }

  /**
   * Resets the sequence, starting at first page with all defaults.
   */
  public void resetSequence() {
    this.sequenceHelper = createSequenceHelper();
  }

  /* ========== FormWidget proxy methods ========== */  

  /**
   * Returns the filter form.
   * 
   * @return the filter form.
   */
  public FormWidget getForm() {
    return this.form;
  }

  /**
   * Saves the filter form.
   */
  public void setForm(FormWidget form) {
    this.form = form;
  }

  /**
   * Sets the filter button label.
   * 
   * @param label custom label Id.
   */
  public void setFilterButtonLabel(String label) {
    getForm().getElementByFullName(FILTER_BUTTON_ID).setLabel(label);
  }

  /**
   * Sets the filter reset button label.
   * 
   * @param label custom label Id.
   */
  public void setFilterResetButtonLabel(String label) {
    getForm().getElementByFullName(FILTER_RESET_BUTTON_ID).setLabel(label);
  }    

  /* ========== ListStructure Proxy methods ========== */  

  /**
   * Returns <code>true</code> if all fields are added orderable by default. 
   * 
   * @return <code>true</code> if all fields are added orderable by default.
   */
  public boolean isOrderableByDefault() {
    return getListStructure().isOrderableByDefault();
  }

  /**
   * Sets whether all fields are added orderable by default.
   * 
   * @param orderableByDefault whether all fields are added orderable by
   * default.
   */
  public void setOrderableByDefault(boolean orderableByDefault) {
    getListStructure().setOrderableByDefault(orderableByDefault);
  }  

  /**
   * Returns {@link ListField}s.
   * 
   * @return {@link ListField}s.
   */
  public List getFields() {
    return getListStructure().getFieldList();
  }

  /**
   * Returns {@link ListField}.
   * 
   * @param id
   *            {@link ListField}identifier.
   * @return {@link ListField}.
   */
  public ListField getField(String id) {
    return getListStructure().getField(id);
  }

  /**
   * Returns label of {@link ListField}.
   * 
   * @param columnId
   *            {@link ListField} identifier.
   * @return label of {@link ListField}.
   */
  public String getFieldLabel(String columnId) {
    ListField field = getField(columnId);
    return field == null ? null : field.getLabel();
  }

  /**
   * Adds a list field.
   * <p>
   * The added field is orderable if {@link #isOrderableByDefault()}
   * returns <code>true</code>.
   * 
   * @param id
   *            list field Id.
   * @param label
   *            list field label.
   */
  public FieldFilterHelper addField(String id, String label) {
    getListStructure().addField(id, label);
    return getFilterHelper(id);
  }

  /**
   * Adds a list field.
   * 
   * @param id
   *            list field Id.
   * @param label
   *            list field label.
   * @param orderable
   *            whether this list field should be orderable or not. 
   */
  public FieldFilterHelper addField(String id, String label, boolean orderable) {
    getListStructure().addField(id, label, orderable);
    return getFilterHelper(id);
  }

  /**
   * Adds a list field.
   * <p>
   * The added field is orderable if {@link #isOrderableByDefault()}
   * returns <code>true</code>.
   * 
   * @param id
   *            list field Id.
   * @param label
   *            list field label.
   * @param type
   *            list field type.
   */
  public FieldFilterHelper addField(String id, String label, Class type) {
    getListStructure().addField(id, label, type);
    return getFilterHelper(id);
  }

  /**
   * Adds a list field.
   * 
   * @param id
   *            list field Id.
   * @param label
   *            list field label.
   * @param type
   *            list field type.
   * @param orderable
   *            whether this list field should be orderable or not. 
   */  
  public FieldFilterHelper addField(String id, String label, Class type, boolean orderable) {
    getListStructure().addField(id, label, type, orderable);
    return getFilterHelper(id);
  }

  /**
   * Adds a list field order.
   * 
   * @param order
   *           list field order.
   */
  public void addFilter(FieldOrder order) {
    getListStructure().addOrder(order);
  }

  /**
   * Removes all list orders.
   */
  public void clearOrders() {
    getListStructure().clearOrders();
  }  

  /**
   * Adds a list filter.
   * 
   * @param filter
   *           list filter.
   */
  public void addFilter(ListFilter filter) {
    getListStructure().addFilter(filter);
  }

  /**
   * Removes all list filters.
   */
  public void clearFilters() {
    getListStructure().clearFilters();
  }

  /* ========== TypeHelper Proxy methods ========== */

  /**
   * Returns type of list field. Returns null if no such field or type for
   * this field is available.
   * 
   * @param fieldId
   *            field identifier.
   * @return field type
   */
  public Class getFieldType(String fieldId) {
    return this.typeHelper.getFieldType(fieldId);
  }

  /**
   * Returns {@link Comparator} for the specified field.
   */
  public Comparator getFieldComparator(String fieldId) {
    return this.typeHelper.getFieldComparator(fieldId);
  }

  /**
   * Returns the Locale used by memory-based filters and orders. 
   */
  public Locale getLocale() {
    return this.typeHelper.getLocale();
  }

  /**
   * Returns whether new filters and orders are case insensitive.
   */
  public boolean isIgnoreCase() {
    return this.typeHelper.isIgnoreCase();
  }

  /* ========== SequenceHelper Proxy methods ========== */  

  /**
   * Returns how many items will be displayed on one page.
   * @return how many items will be displayed on one page.
   */
  public long getItemsOnPage() {
    return getSequenceHelper().getItemsOnPage();
  }

  /**
   * Sets how many items will be displayed on one page.
   * @param itemsOnPage how many items will be displayed on one page.
   */
  public void setItemsOnPage(long itemsOnPage) {
    getSequenceHelper().setItemsOnPage(itemsOnPage);
  }

  /**
   * Sets the page which will be displayed. Page index is 0-based.
   * 
   * @param currentPage
   * index of the page.
   */
  public void setCurrentPage(long currentPage) {
    getSequenceHelper().setCurrentPage(currentPage);
  }

  /**
   * Gets first item to be displayed on the current page.
   * 
   * @return index of the first element from the list to be displayed.
   */
  public long getCurrentPageFirstItemIndex() {
    return getSequenceHelper().getCurrentPageFirstItemIndex();
  }

  /**
   * Gets last item to be displayed on the current page.
   * 
   * @return index of the last element from the list to be displayed.
   */
  public long getCurrentPageLastItemIndex() {
    return getSequenceHelper().getCurrentPageLastItemIndex();
  }

  /**
   * Expands the list showing all items.
   */
  public void showFullPages() {
    getSequenceHelper().showFullPages();
  }

  /**
   * Collapses the list, showing only the current page.
   */
  public void showDefaultPages() {
    getSequenceHelper().showDefaultPages();
  }

  /* ========== List State reading and modifying ========== */  

  /**
   * Returns the filter information from filter form.
   * @return <code>Map</code> containing filter information.
   */
  public Map getFilterInfo() {
    return ListUtil.readFilterInfo(this.form);
  }

  /**
   * Sets the filter information to list data provider and filter form.
   * 
   * @param filterInfo <code>Map</code> containing filter information.
   */
  public void setFilterInfo(Map filterInfo) {    
    if (filterInfo != null) {
      if (isInitialized()) {
        propagateListDataProviderWithFilter(filterInfo);        
      }
      ListUtil.writeFilterInfo(this.form, filterInfo);
    }
  }

  private void propagateListDataProviderWithFilter(Map filterInfo) {
    if (this.dataProvider != null) {
      this.dataProvider.setFilterInfo(filterInfo);
    }
  }

  /**
   * Returns the order info.
   * 
   * @return the order info.
   */
  public OrderInfo getOrderInfo() {
    return this.orderInfo;
  }

  /**
   * Sets the initial order of the list.
   * 
   * @param fieldId the name of the column to order by.
   * @param ascending whether ordering should be ascending.
   */
  public void setInitialOrder(String fieldId, boolean ascending) {
    OrderInfo orderInfo = new OrderInfo();
    OrderInfoField orderInfoField = new OrderInfoField(fieldId, ascending);
    orderInfo.addField(orderInfoField);
    setOrderInfo(orderInfo);
  }

  /**
   * Sets the order information to list data provider and list widget.
   * 
   * @param orderInfo <code>OrderInfo</code> containing order information.
   */
  public void setOrderInfo(OrderInfo orderInfo) {    
    this.orderInfo = orderInfo;
    if (isInitialized()) {
      propagateListDataProviderWithOrderInfo(orderInfo);      
    }
  }

  protected void propagateListDataProviderWithOrderInfo(OrderInfo orderInfo) {
    if (this.dataProvider != null) {
      this.dataProvider.setOrderInfo(orderInfo);
    }
    fireChange();
  }

  /**
   * Forces the list data provider to refresh the data.
   */
  public void refresh() {
    if (this.dataProvider == null)
      throw new IllegalStateException("DataProvider was NULL in ListWidget.refresh().");

    try {
      this.dataProvider.refreshData();
    }
    catch (Exception e) {
      ExceptionUtil.uncheckException(e);
    }
    fireChange();
  }

  /**
   * Refreshes the current item range, reloading the shown items.
   */
  public void refreshCurrentItemRange() {
    if (this.dataProvider == null)
      throw new IllegalStateException("DataProvider was NULL in ListWidget.refreshCurrentItemRange().");

    ListItemsData itemRangeData;
    
    try {
      itemRangeData = this.dataProvider.getItemRange(new Long(this.sequenceHelper
          .getCurrentPageFirstItemIndex()), new Long(this.sequenceHelper.getItemsOnPage()));
    }
    catch (Exception e) {
      throw new AraneaRuntimeException(e);
    }

    this.itemRange = itemRangeData.getItemRange();
    this.sequenceHelper.setTotalItemCount(itemRangeData.getTotalCount().intValue());
    this.sequenceHelper.validateSequence();
    
    makeRequestIdToRowMapping();
  }

  /**
   * Returns the current item range.
   * 
   * @return the current item range.
   */
  public List getItemRange() {
    if (itemRange == null || this.checkChanged() || sequenceHelper.checkChanged() || typeHelper.checkChanged() || filterHelper.checkChanged()) {
      refreshCurrentItemRange();

            // trigger all checks to reliably reset the change status of the list. 
      this.checkChanged();
      sequenceHelper.checkChanged();
      typeHelper.checkChanged();
      filterHelper.checkChanged();
    }

    return this.itemRange;
  }

  /**
   * Returns row object according to the request identifier.
   * 
   * @param requestId request identifier.
   * @return list row object.
   */
  public Object getRowFromRequestId(String requestId) {  
    return this.requestIdToRow.get(requestId);
  }


  //*******************************************************************
  // WIDGET METHODS
  //*******************************************************************  
  
  public void addInitEvent(Event event) {
    if (isAlive()) {
      event.run();
    } else if (!isInitialized()){
      if (initEvents == null)
        initEvents = new ArrayList();
      initEvents.add(event);
    }    
  }
  
  protected void runInitEvents() {
    if (initEvents != null) {
      for (Iterator it = initEvents.iterator(); it.hasNext();) {
        Runnable event = (Runnable) it.next();
        event.run();
      }
    }
    initEvents = null;
  }
  
  /**
   * Initilizes the list, initializing contained filter form and the {@link ListDataProvider}and
   * getting the initial item range.
   */
  protected void init() throws Exception {
    this.sequenceHelper = createSequenceHelper();

    addEventListener("nextPage", new NextPageEventHandler());
    addEventListener("previousPage", new PreviousPageEventHandler());
    addEventListener("nextBlock", new NextBlockEventHandler());
    addEventListener("previousBlock", new PreviousBlockEventHandler());
    addEventListener("firstPage", new FirstPageEventHandler());
    addEventListener("lastPage", new LastPageEventHandler());
    addEventListener("jumpToPage", new JumpToPageEventHandler());
    addEventListener("showAll", new ShowAllEventHandler());
    addEventListener("showSlice", new ShowSliceEventHandler());
    addEventListener("order", new OrderEventHandler());

    initFilterForm();
    initSequenceHelper();
    
    this.typeHelper.init(getEnvironment());
    this.filterHelper.init(getEnvironment());
    this.listStructure.init(getEnvironment());
    
    runInitEvents();

    if (getDataProvider() != null) {      
      initDataProvider();
    }    
  }

  protected SequenceHelper createSequenceHelper() {
    return new SequenceHelper(getConfiguration());
  }  
  protected TypeHelper createTypeHelper() {
    return new TypeHelper();
  }  
  protected ListStructure createListStructure() {
    return new ListStructure(getTypeHelper());
  }
  protected FilterHelper createFilterHelper() {
    return new FilterHelper(this);
  }

  protected void initFilterForm() throws Exception {
    if (this.form == null) {
      this.form = new FormWidget();
    }

    FormElement filterButton = this.form.addElement(FILTER_BUTTON_ID, UiLibMessages.LIST_FILTER_BUTTON_LABEL, new ButtonControl(), null, false);
    ((ButtonControl) (filterButton.getControl())).addOnClickEventListener(new FilterEventHandler());

    FormElement clearButton = this.form.addElement(FILTER_RESET_BUTTON_ID, UiLibMessages.LIST_FILTER_CLEAR_BUTTON_LABEL, new ButtonControl(), null, false);
    ((ButtonControl) (clearButton.getControl())).addOnClickEventListener(new FilterClearEventHandler());

    this.form.markBaseState();

    addWidget(FILTER_FORM_NAME, this.form);    
  }

  protected void initSequenceHelper() {
    Long defaultListSize = (Long) getConfiguration().getEntry(ConfigurationContext.DEFAULT_LIST_ITEMS_ON_PAGE);
    if (defaultListSize != null) {
      this.sequenceHelper.setItemsOnPage(defaultListSize.longValue());
    }    
  }

  protected void initDataProvider() throws Exception {
    this.dataProvider.setListStructure(getListStructure());
    propagateListDataProviderWithOrderInfo(getOrderInfo());
    propagateListDataProviderWithFilter(getFilterInfo());    
    this.dataProvider.init();
  }

  /**
   * Destoys the list and contained data provider and filter form.
   * @throws Exception 
   */
  protected void destroy() throws Exception {
        if (this.dataProvider != null)
          this.dataProvider.destroy();
        
        if (this.listStructure != null)
          this.listStructure.destroy();
        
        if (this.filterHelper != null)
          this.filterHelper.destroy();
        
        if (this.typeHelper != null)
          this.typeHelper.destroy();
  }

  /**
   * Returns {@link ViewModel}- list widget view model.
   * 
   * @return {@link ViewModel}- list widget view model.
   */
  public Object getViewModel() {
    return new ViewModel();
  }

  //*******************************************************************
  // EVENT HANDLERS
  //*******************************************************************

  /**
   * Handles page advancing.
   */
  protected class NextPageEventHandler extends StandardEventListener {

    public void processEvent(Object eventId, String eventParam, InputData input) throws Exception {
      sequenceHelper.goToNextPage();
    }
  }

  /**
   * Handles page preceeding.
   */
  protected class PreviousPageEventHandler  extends StandardEventListener {

    public void processEvent(Object eventId, String eventParam, InputData input) throws Exception {
      sequenceHelper.goToPreviousPage();
    }
  }

  /**
   * Handles block advancing.
   */
  protected class NextBlockEventHandler  extends StandardEventListener {

    public void processEvent(Object eventId, String eventParam, InputData input) throws Exception {
      sequenceHelper.goToNextBlock();
    }
  }

  /**
   * Handles block preceeding.
   */
  protected class PreviousBlockEventHandler  extends StandardEventListener {

    public void processEvent(Object eventId, String eventParam, InputData input) throws Exception {
      sequenceHelper.goToPreviousBlock();
    }
  }

  /**
   * Handles going to first page
   */
  protected class FirstPageEventHandler  extends StandardEventListener {

    public void processEvent(Object eventId, String eventParam, InputData input) throws Exception {
      sequenceHelper.goToFirstPage();
    }
  }

  /**
   * Handles going to last page
   */
  protected class LastPageEventHandler  extends StandardEventListener {

    public void processEvent(Object eventId, String eventParam, InputData input) throws Exception {
      sequenceHelper.goToLastPage();
    }
  }

  /**
   * Handles going to any page by number.
   */
  protected class JumpToPageEventHandler  extends StandardEventListener {

    public void processEvent(Object eventId, String eventParam, InputData input) throws Exception {
      int page;
      try {
        page = Integer.parseInt(eventParam);
      }
      catch (Exception e) {
        throw new AraneaRuntimeException("Invalid page index provided.", e);
      }
      sequenceHelper.goToPage(page);
    }
  }

  /**
   * Handles showing all records.
   */
  protected class ShowAllEventHandler  extends StandardEventListener {
    public void processEvent(Object eventId, String eventParam, InputData input) throws Exception {
      filter();
      sequenceHelper.showFullPages();
    }
  }

  /**
   * Handles showing only current records.
   */
  protected class ShowSliceEventHandler extends StandardEventListener {
    public void processEvent(Object eventId, String eventParam, InputData input) throws Exception {
      filter();
      sequenceHelper.showDefaultPages();
    }
  }

  /**
   * Handles single column ordering.
   */  
  protected void order(String fieldName) throws Exception {    
    log.debug("Processing Single Column Order");      

    boolean ascending = true;

    List orderFields = orderInfo.getFields();
    OrderInfoField currentOrderField = (OrderInfoField) (orderFields.size() > 0 ? orderFields.get(0) : null);
    if (currentOrderField != null) {
      if (currentOrderField.getId().equals(fieldName) && currentOrderField.isAscending()) {
        ascending = false;
      }
    }

    orderInfo.clearFields();
    orderInfo.addField(new OrderInfoField(fieldName, ascending));

    propagateListDataProviderWithOrderInfo(orderInfo);    

    // XXX: why is this commented code here?
    // listDataProvider.setOrderInfo(orderInfo);   

    filter();
  }

  protected class OrderEventHandler extends StandardEventListener {
    public void processEvent(Object eventId, String eventParam, InputData input) throws Exception {
      // single column ordering
      if (eventParam.length() > 0) {
        order(eventParam);
        return;
      }

      // multi column ordering
      OrderInfo orderInfo = MultiOrderHelper.getOrderInfo(getOrderInfoMap(input.getScopedData(getScope().toPath())));

      propagateListDataProviderWithOrderInfo(orderInfo);
    }

    private Map getOrderInfoMap(Map data) {
      Map orderInfoMap = new HashMap();      
      for (Iterator i = data.entrySet().iterator(); i.hasNext();) {
        Map.Entry entry = (Map.Entry) i.next();
        String key = (String) entry.getKey();
        if (key.startsWith(ORDER_FORM_NAME)) {
          orderInfoMap.put(key.substring(ORDER_FORM_NAME.length()), entry.getValue());
        }
      }
      return orderInfoMap;
    }
  }
  
  
  /**
   * Creates mapping between rows and request ids.
   * 
   * @since 1.1
   */
  protected void makeRequestIdToRowMapping() {
    if (this.dataProvider == null)
      return;

    requestIdToRow.clear();
    for (ListIterator i = itemRange.listIterator(); i.hasNext();) {
      Object row = i.next();
      requestIdToRow.put(Integer.toString(i.previousIndex()), row);
    }
  }

  /**
   * Handles filtering.
   */
  protected void filter() throws Exception {
    if (form.convertAndValidate() && form.isStateChanged()) {

      Map filterInfo = ListUtil.readFilterInfo(form);

      propagateListDataProviderWithFilter(filterInfo);

      form.markBaseState();
      sequenceHelper.setCurrentPage(0);
      
      fireChange();
    }
  }

  /**
   * Handles filter clearing. 
   */
  protected void clearFilter() {
    clearForm(form);
    propagateListDataProviderWithFilter(Collections.EMPTY_MAP);
    sequenceHelper.setCurrentPage(0);
    fireChange();
  }

  protected static void clearForm(FormWidget compositeFormElement) {
    for (Iterator i = compositeFormElement.getElements().values().iterator(); i.hasNext();) {
      GenericFormElement element = (GenericFormElement) i.next();

      if (element instanceof FormElement) {
        ((FormElement) element).setValue(null);
        element.markBaseState();
      } else if (element instanceof FormWidget) {
        clearForm((FormWidget) element);
      }
    }
  }
  
  /** 
   * @since 1.1
   */
  protected boolean checkChanged() {
    boolean result = changed;
    changed = false;
    return result;
  }
  
  /** 
   * @since 1.1
   */
  protected void fireChange() {
    changed = true;
  }

  protected class FilterEventHandler implements OnClickEventListener {
    public void onClick() throws Exception {
      filter();
    }
  }

  protected class FilterClearEventHandler implements OnClickEventListener {
    public void onClick() throws Exception {
      clearFilter();
    }
  }
  
  protected class DataProviderDataUpdateListener implements ListDataProvider.DataUpdateListener {
    public void onDataUpdate() {
      fireChange();
    }
  }

  //*********************************************************************
  //* VIEW MODEL
  //*********************************************************************

  /**
   * Represents a list widget view model.
   * 
   * @author <a href="mailto:ekabanov@webmedia.ee">Jevgeni Kabanov </a>
   *  
   */
  public class ViewModel extends BaseApplicationWidget.ViewModel {

    private static final long serialVersionUID = 1L;

    private List itemRange;
    private SequenceHelper.ViewModel sequence;
    private ListStructure.ViewModel listStructure;
    private OrderInfo.ViewModel orderInfo;
    private FormWidget.ViewModel filterForm;

    /**
     * Takes a snapshot of outer class state.
     * @throws Exception 
     */
    protected ViewModel() {      
      this.itemRange = ListWidget.this.getItemRange();
      this.sequence = ListWidget.this.sequenceHelper.getViewModel();
      this.listStructure = ListWidget.this.listStructure.getViewModel();
      this.orderInfo = ListWidget.this.getOrderInfo().getViewModel();
      this.filterForm = (FormWidget.ViewModel) ListWidget.this.form._getViewable().getViewModel();
    }

    /**
     * Returns item range.
     * 
     * @return item range.
     */
    public List getItemRange() {
      return itemRange;
    }

    /**
     * Returns sequence helper.
     * 
     * @return sequence helper.
     */
    public SequenceHelper.ViewModel getSequence() {
      return sequence;
    }

    /**
     * Returns list structure.
     * 
     * @return list structure.
     */
    public ListStructure.ViewModel getListStructure() {
      return listStructure;
    }

    /**
     * Returns order info.
     * 
     * @return order info.
     */
    public OrderInfo.ViewModel getOrderInfo() {
      return orderInfo;
    }

    /**
     * Returns filter form view model.
     * 
     * @return filter form view model.
     */
    public FormWidget.ViewModel getFilterForm() {
      return filterForm;
    }
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.