Package org.zkoss.zss.app.sort

Source Code of org.zkoss.zss.app.sort.CustomSortWindowCtrl

/* CustomSortWindowCtrl.java

{{IS_NOTE
  Purpose:
   
  Description:
   
  History:
    Aug 17, 2010 6:34:44 PM , Created by Sam
}}IS_NOTE

Copyright (C) 2009 Potix Corporation. All Rights Reserved.

*/
package org.zkoss.zss.app.sort;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.zkoss.lang.Objects;
import org.zkoss.poi.ss.usermodel.Cell;
import org.zkoss.zss.model.Worksheet;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Components;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.UiException;
import org.zkoss.zk.ui.event.SelectEvent;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zss.ui.Rect;
import org.zkoss.zss.ui.Spreadsheet;
import org.zkoss.zss.ui.impl.Utils;
import org.zkoss.zul.Button;
import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.Comboitem;
import org.zkoss.zul.Label;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listcell;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.ListitemRenderer;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Window;

/**
* @author Sam
*
*/
public class CustomSortWindowCtrl extends GenericForwardComposer {
  /**
   * Sort by column
   */
  private final static boolean SORT_TOP_TO_BOTTOM = false;
  /**
   * Sort by row
   */
  private final static boolean SORT_LEFT_TO_RIGHT = true;
 

  private final static String ORIENTATION_COLUMN_KEY = "sort.orientation.column";// orientation

  /**
   * Indicate the sort orientation
   * <p> Default: false, sort from top to bottom, means sort by column
   * <p> true, sort from left to right, means sort by row
   */
  private boolean sortOrientation;
 
  /**
   * Selected sort level target by user
   */
  private ListModelList sortLevelModel;
 
  /**
   * Depends on sortOrientation
   * If sort by rows, available sort target include top row to bottom row
   * If sort by columns, available sort target include left column to right column
   *
   * The value build from spreadsheet's selection range.
   */
  private List<String> availableSortIndex = new ArrayList<String>();
  private ListModelList sortIndexModel = new ListModelList();
 
  private Listbox sortLevel;
  private Spreadsheet ss;
  private Checkbox caseSensitive;
  private Checkbox hasHeader;
  private Listbox sortOrientationLB;
  private Window sortWin;
  private Button addBtn;
  private Button delBtn;
  private Button upBtn;
  private Button downBtn;
  private Button okBtn;
 
 
  public CustomSortWindowCtrl () {
    ss = (Spreadsheet)getParam("spreadsheet");
    if (ss == null)
      throw new UiException("Spreadsheet object is empty");
  }
 
  public void doAfterCompose(Component comp) throws Exception {
    super.doAfterCompose(comp);
   
    initSortLevelListbox();
  }

  private void initSortLevelListbox () {
    List<SortLevel> ary = new ArrayList<SortLevel>();
    ary.add(new SortLevel());
    setAvailableSortTarget(availableSortIndex);
   
    sortLevelModel = new ListModelList(ary);
    sortLevel.setModel(sortLevelModel);
    sortLevel.setItemRenderer(sortLevelRenderer);
  }
 
  /**
   * Setup the available sort target
   * <p> Sort target is column if sort direction is from top to bottom
   * <p> Sort target is row if sort direction is from left to right
   */
  private void setAvailableSortTarget (List<String> list) {
    list.clear();
    list.add(new String(""));
    Rect rect = ss.getSelection();
    if (sortOrientation == SORT_TOP_TO_BOTTOM) {
      for (int i = rect.getLeft(); i <= rect.getRight(); i++)
        list.add(new String("Column " + ss.getColumntitle(i)));
    } else {
      for (int i = rect.getTop(); i <= rect.getBottom(); i++)
        list.add(new String("Row " + ss.getRowtitle(i)));
    }
    sortIndexModel.clear();
    sortIndexModel.addAll(list);
  }
 
  public void onSelect$sortLevel () {
    setClickableMoveButtons();
  }
 
  public void onInitRender$sortLevel () {
    setClickableMoveButtons();
  }
 
  private void setClickableMoveButtons() {
    int idx = sortLevel.getSelectedIndex();
    upBtn.setDisabled(idx == 0 ? true : false);
    downBtn.setDisabled(idx < ( sortLevel.getItemCount() - 1) ? false : true);
  }
 
  public void onClick$addBtn () {
    sortLevelModel.add(new SortLevel());
  }
 
  public void onClick$delBtn () {
    sortLevelModel.remove(sortLevel.getSelectedIndex());
  }
 
  public void onClick$upBtn () {
    int idx = sortLevel.getSelectedIndex();
    int forward = idx - 1;
    if (forward >= 0) {
      swapSortLevel(sortLevelModel, idx, forward);
      sortLevel.setSelectedIndex(forward);
    }
  }
 
  public void onClick$downBtn () {
    int idx = sortLevel.getSelectedIndex();
    int back = idx + 1;
    if (back < sortLevelModel.getSize()) {
      swapSortLevel(sortLevelModel, idx, back);
      sortLevel.setSelectedIndex(back);
    }
  }
 
  public void onClick$okBtn () {
    if (hasEmptyArgs(sortLevelModel.getInnerList())) {
      Messagebox.show(getLabel("sort.err.hasEmptyField"));
      return;
    }
   
    String dupTarget = checkDuplicateSortIndex(sortLevelModel.getInnerList());
    if (dupTarget != null) {
      Messagebox.show(dupTarget + " " + getLabel("sort.err.duplicateField"));
      return;
    }
   
    int count = 0;
    int size = sortLevelModel.size() <= 3 ? sortLevelModel.size() : 3;
    int[] index = new int[size];
    int[] dataOption = new int[size];
    boolean[] algorithm = new boolean[size];
    for (Iterator iter = sortLevelModel.iterator(); iter.hasNext() && count < index.length; count++) {
      SortLevel l = (SortLevel)iter.next();
      index[count] = l.sortIndex;
      algorithm[count] = l.order;
      dataOption[count] = l.dataOption;
    }
   
    //call utils
    Utils.sort(ss.getSelectedSheet(), ss.getSelection(), index, algorithm, dataOption,  hasHeader.isChecked(), caseSensitive.isChecked(), sortOrientation);
    sortWin.detach();
  }
 
  /**
   * Returns true if there is a
   * @return
   */
  private static boolean hasEmptyArgs (List<SortLevel> list) {
    for (SortLevel s : list) {
      if (s.sortIndex == -1)
        return true;
    }
    return false;
  }
 
  /**
   * Returns the duplicate sort title
   * @param list
   * @return string if there is a duplicate, or null when there is no duplicate.
   */
  private String checkDuplicateSortIndex(List<SortLevel> list) {
    HashMap<Integer, Boolean> map = new HashMap<Integer, Boolean>();
    for (SortLevel s : list) {
      if ( map.containsKey( Integer.valueOf(s.sortIndex) ) ) {
        String title = null;
        if (sortOrientation)
          title = "Row " + ss.getRowtitle(s.sortIndex);
        else
          title = "Column " + ss.getColumntitle(s.sortIndex);
        return title;
      } else
        map.put(Integer.valueOf(s.sortIndex), Boolean.valueOf(true));
    }
    return null;
  }
 

 
  private static void swapSortLevel(ListModelList model, int sourceIdx, int destIdx) {
    SortLevel srcSort = (SortLevel)model.get(sourceIdx);
    SortLevel dstSort = (SortLevel)model.get(destIdx);
    model.set(destIdx, srcSort);
    model.set(sourceIdx, dstSort);
  }
 
  public void onSelect$sortOrientationLB () {
    boolean orientation;
    Listitem seld = sortOrientationLB.getSelectedItem();
    orientation = getLabel(ORIENTATION_COLUMN_KEY).equals(seld) ?
        SORT_TOP_TO_BOTTOM : SORT_LEFT_TO_RIGHT;
    if (sortOrientation != orientation) {
      sortOrientation = orientation;
      setAvailableSortTarget(availableSortIndex);
    }
  }
 
  private static Object getParam (String key) {
    return Executions.getCurrent().getArg().get(key);
  }
 
  private ListitemRenderer sortLevelRenderer = new ListitemRenderer() {

    public void render(Listitem item, Object obj) throws Exception {
      Listcell cell = new Listcell();
      SortLevel sort = (SortLevel)obj;
      SortLevel first = (SortLevel)sortLevelModel.get(0);
      cell.appendChild(sort.equals(first) ?
          (Component)new Label(getLabel("sort.sortBy")) : (Component)new Label(getLabel("sort.thenBy")));
      item.appendChild(cell);
     
      cell = new Listcell();
      SortIndexSelector idxSel = new SortIndexSelector(sort);
      cell.appendChild(idxSel);
      item.appendChild(cell);
     
      cell = new Listcell();
      SortAlgorithm sortMethod = new SortAlgorithm(sort);
      cell.appendChild(sortMethod);
      idxSel.setAttribute(SortAlgorithm.class.getCanonicalName(), sortMethod);
      item.appendChild(cell);
    }

    @Override
    public void render(Listitem item, Object data, int index)
        throws Exception {
      render(item, data);
    }
  };
 
 
  public class SortIndexSelector extends Combobox {
    SortLevel sort;
   
    public SortIndexSelector (SortLevel sort) {
      setWidth("100%");
      setReadonly(true);
      setMold("rounded");
      this.sort = sort;
      setModel(sortIndexModel);
    }
   
    public void onAfterRender() {
      if (sort.sortIndex >= 0 && getItemCount() > 0) {
        int idx = getSpreadsheetIndexOffset(ss, sort.sortIndex, sortOrientation);
        setSelectedIndex(idx >= 0 ? idx : 0);
      }
    }

    public void onSelect () {
      String seldLabel = getSelectedItem().getLabel();
      if (seldLabel != null && seldLabel.length() > 0) {
        int blankIdx = seldLabel.lastIndexOf(" ");
        if (blankIdx >= 0) {
          String title = seldLabel.substring( seldLabel.lastIndexOf(" ") + " ".length() );
          int idx = getSpreadsheetIndexBy(ss, title, sortOrientation);
          if (idx != -1) {
            sort.sortIndex = idx;
            SortAlgorithm alg = (SortAlgorithm)getAttribute(SortAlgorithm.class.getCanonicalName());
            alg.refresh();
          }
        }
      }
    }
  }
 
  public class SortAlgorithm extends Combobox {
    private SortLevel sort;
   
    /**
     * Default display the String
     */
    private final static String STR_ASCENDING_KEY = "sort.str.ascending";
    private final static String STR_DESCENDING_KEY = "sort.str.descending";
    private final static String NUM_ASCENDING_KEY = "sort.num.ascending";
    private final static String NUM_DESCENDING_KEY = "sort.num.descending";

    /**
     * Sort index has number
     * <p> default false means sort target is string
     */
    private boolean sortNumber;
   
    public SortAlgorithm(SortLevel sort) {
      this.sort = sort;
      setWidth("100%");
      setReadonly(true);
      setMold("rounded");
      appendComboitemsBySortIndex(sort.sortIndex);
      setSelectedIndex(sort.order == SortLevel.ASCENDING ? 0 : 1);
    }
   
    public void refresh() {
      setSelectedIndex(-1);
      Components.removeAllChildren(this);
     
      appendComboitemsBySortIndex(sort.sortIndex);
      setSelectedIndex(0);
    }
   
    private void appendComboitemsBySortIndex(int index) {
      if (index < 0) { //default sort target is string
        sortNumber = false;
        appendChild(new Comboitem(getLabel(STR_ASCENDING_KEY)));
        appendChild(new Comboitem(getLabel(STR_DESCENDING_KEY)));
      } else {
        if (isAllCellNumberType(index)) {
          sortNumber = true;
          appendChild(new Comboitem(getLabel(NUM_ASCENDING_KEY)));
          appendChild(new Comboitem(getLabel(NUM_DESCENDING_KEY)));
        } else {
          sortNumber = false;
          appendChild(new Comboitem(getLabel(STR_ASCENDING_KEY)));
          appendChild(new Comboitem(getLabel(STR_DESCENDING_KEY)));
        }
      }
    }
   
    /**
     * Returns true indicate spreadsheet index column/row is number
     * @return
     */
    private boolean isAllCellNumberType(int idx) {
      Worksheet sheet = ss.getSelectedSheet();
      Rect rect = ss.getSelection();
      int top = sortOrientation ? idx : rect.getTop();
      int left = sortOrientation ? rect.getLeft() : idx;
      int bottom = sortOrientation ? idx : rect.getBottom();
      int right = sortOrientation ? rect.getRight() : idx;

      for (int row = top; row <= bottom; row++) {
        for (int col = left; col <= right; col++) {
          Cell c = Utils.getCell(sheet, row, col);
          if (c != null) {
            int type = c.getCellType() != Cell.CELL_TYPE_FORMULA ?
                  c.getCellType() : c.getCachedFormulaResultType();
            if (type != Cell.CELL_TYPE_NUMERIC)
              return false;
          }
        }
      }
      return true;
    }

    public void onSelect (SelectEvent evt) {
      Iterator<Comboitem> iter =  evt.getSelectedItems().iterator();
      if (iter.hasNext()) {
        Comboitem item = iter.next();
        if (!sortNumber) { //sort string
          sort.order = getLabel(STR_ASCENDING_KEY).equals(item.getLabel()) ?
              SortLevel.ASCENDING : SortLevel.DESCENDING;
        } else { //sort number
          sort.order = getLabel(NUM_ASCENDING_KEY).equals(item.getLabel()) ?
              SortLevel.ASCENDING : SortLevel.DESCENDING;
        }
      }
    }
  }
 
  /**
   * Returns the string from i-18n, if not found, return empty string
   * @return
   */
  private static String getLabel(String key) {
    String val = Labels.getLabel(key);
    return val != null ? val : "";
  }

  private static int getSpreadsheetIndexOffset (Spreadsheet spreadsheet, int index, boolean sortAlgorithm) {
    Rect rect = spreadsheet.getSelection();
    int baseIdx = sortAlgorithm == SORT_TOP_TO_BOTTOM ? rect.getLeft() : rect.getTop();
    int idx = index - baseIdx + 1;
    return idx >= 0 ? idx : -1;
  }
 
 
  /**
   * Returns the index of column or row by title on selection range of spreadsheet
   * @param spreadsheet
   * @param title
   * @param sortAlgorithm
   * @return
   */
  private static int getSpreadsheetIndexBy (Spreadsheet spreadsheet, String title, boolean sortAlgorithm) {
    Rect rect = spreadsheet.getSelection();
    if (sortAlgorithm == SORT_TOP_TO_BOTTOM) {
      for (int i = rect.getLeft(); i <= rect.getRight(); i++) {
        String t = spreadsheet.getColumntitle(i);
        if (Objects.equals(title, t))
          return i;
      }
    } else {
      for (int i = rect.getTop(); i <= rect.getBottom(); i++) {
        String t = spreadsheet.getRowtitle(i);
        if (Objects.equals(title, t))
          return i;
      }
    }
    return -1;
  }
}
TOP

Related Classes of org.zkoss.zss.app.sort.CustomSortWindowCtrl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
ww.google-analytics.com/analytics.js','ga'); ga('create', 'UA-20639858-1', 'auto'); ga('send', 'pageview');