Package jcurses.widgets

Source Code of jcurses.widgets.List

/**
*  This class implements a list widget to select and 'invoke' one ore more items.
* Listeners can be registered to track selecting deselecting and 'invoking' of items.
*/
package jcurses.widgets;


import java.util.ArrayList;

import jcurses.event.ItemEvent;
import jcurses.event.ItemListener;
import jcurses.event.ItemListenerManager;
import jcurses.system.CharColor;
import jcurses.system.InputChar;
import jcurses.system.Toolkit;
import jcurses.util.Paging;
import jcurses.util.Rectangle;



public class List extends Widget implements IScrollable {
 
  
  private int _visibleSize = -1;
  private boolean _multiple = false;
 
  private java.util.List<String> _items = new ArrayList<String>();
  private java.util.List<Boolean> _selected = new ArrayList<Boolean>();
 
  private int _startIndex = 0;
  private int _trackedIndex = 0;
  private int _startPos = 0;
 
  private boolean _selectable = true;
 
  private String _title = null;
 
  private ItemListenerManager _listenerManager = new ItemListenerManager();
 
 
  private static CharColor __listDefaultColors = new CharColor(CharColor.WHITE, CharColor.BLACK);
 
  private ScrollbarPainter _scrollbars = null;
 
 
    /**
    *  The constructor
    *
    * @param visibleSize number of visible items. If the entire number of items
    * is more, the widget scrolls items 'by a window'. If -1 is given, than the
    * visible size is defined dependent of the layout size, that is, the widget
    * has no preferred y size.
    * @param multiple true, if more as one items can be selected a time, false, if only
    * one item can be selected at a time, in this case selecting of an item causes deselecting
    * of the previous selected item.
    */
  public List(int visibleSize, boolean multiple) {
    _visibleSize = visibleSize;
    _multiple = multiple;
    _scrollbars = new ScrollbarPainter(this);
  }
 
 
    /**
    *  The constructor.
    * @param visibleSize number of visible items. If the entire number of items
    * is more, the widget scrolls items 'by a window'. If -1 is given, than the
    * visible size is defined dependent of the layout size, that is, the widget
    * has no preferred y size.
    *
    */
    public List (int visibleSize) {
    this(visibleSize, false);
  }
   
    /**
    *  The constructor
    */
  public List() {
    this(-1, false);
  }
 
 
 
 
 
  public CharColor getDefaultColors() {
    return __listDefaultColors;
  }
 
 
 
  private static CharColor __selectedItemDefaultColors = new CharColor(CharColor.BLUE, CharColor.WHITE, CharColor.REVERSE);
  private CharColor _selectedItemColors = getSelectedItemDefaultColors();
 
 
   
  private CharColor getSelectedItemDefaultColors() {
    return __selectedItemDefaultColors;
  }
 
 
    /**
    *  @return colors used painting selected items.
    */
  public CharColor getSelectedItemColors() {
    return _selectedItemColors;
  }
 
 
    /**
    *  Sets colors used painting selected items.
    *
    * @param colors colors used painting selected items
    */
  public void setSelectedItemColors(CharColor colors) {
    _selectedItemColors = colors;
  }
 
   
  private static CharColor __titleDefaultColors = new CharColor(CharColor.WHITE, CharColor.RED, CharColor.BOLD);
  private CharColor _titleColors = getTitleDefaultColors();
 
 
  private CharColor getTitleDefaultColors() {
    return __titleDefaultColors;
  }
 
  /**
  *  @return colors used painting the title
  */
  public CharColor getTitleColors() {
    return _titleColors;
  }
 
  /**
  *  Sets colors used painting the title
    *
    * @param colors colors used painting the title
  */
  public void setTitleColors(CharColor colors) {
    _titleColors = colors;
  }
 
 
    /**
    *  @return list's title
    */
  public String getTitle() {
    return _title;
  }
 
 
    /**
    *  Sets the title of the list.
    * @param title the title of the list
    */
  public void setTitle(String title) {
    _title = title;
  }
 
 
  private void drawTitle() {
    String text = null;
    if (_title!=null) {
      text = (_title.length()>(getSize().getWidth()-2))?_title.substring(0,(getSize().getWidth()-2)):_title;
      Toolkit.printString(text, getAbsoluteX()+(getSize().getWidth()-text.length())/2, getAbsoluteY(),getTitleColors());
    }
  }
 
 
 
 
  /**
  *  Adds an item to the list at the specified position
    *
    * @param pos the position to insert the item
    * @param item item to add
  */
  public void add(int pos, String item) {
    _items.add(pos, item);
    _selected.add(pos, new Boolean(false));
    reset();
  }
 
 
    /**
  *  Adds an item to the end of the list
    *
    * @param item item to add
  */
  public void add(String item) {
    add(_items.size(), item);
  }
 
 
    /**
    *  @return number of items
    */
  public int getItemsCount() {
    return _items.size();
  }
 
 
    /**
    * @param index specified position
    *  @return item at the specified position
    */
  public String getItem(int index) {
    return (String)_items.get(index);
  }
 
 
 
    /**
    *  Removes an item from the list at the specified position
    *
    * @param pos position
    */
  public void remove(int pos) {
    _items.remove(pos);
    _selected.remove(pos);
    reset();
  }
 
 
    /**
    *  Removes the first occurence of <code>item</code> from the list.
    *
    * @param item string, whose first occurence is to remove from the list.
    */
  public void remove(String item) {
    int index = _items.indexOf(item);
    if (index != -1) {
      _items.remove(index);
      _selected.remove(index);
    }
   
  }
 
 
 
  private void dispatchEvent(int index, boolean value) {
    ItemEvent event = new ItemEvent(this, index, _items.get(index),
                                    value?ItemEvent.SELECTED:ItemEvent.DESELECTED);
    _listenerManager.handleEvent(event);
  }
   
 
 
  private void select(int index, boolean value) {
   
    if (!(isSelected(index) == value)) {   
      int selected = getSelectedIndex();
      _selected.set(index, new Boolean(value));
      if ((!_multiple)&&value) {
        if (selected!=-1) {
           deselect(selected);
        }
      }
    }
   
  }
 
 
 
  private void redrawItemBySelecting(int index) {
    if (!((index ==_trackedIndex) && hasFocus())) {
      redrawItem(index, getRectangle());
    }
  }
 
    /**
    *  Selects an item at the specified position
    *
    * @param index position
    */
  public void select(int index) {
    select(index, true);
    if (isVisible()) {
      redrawItemBySelecting(index);
    }
    dispatchEvent(index, true);
  }
 
 
    /**
    *  Deselects an item at the specified position
    *
    * @param index position
    */
  public void deselect(int index) {
    select(index, false);
    if (isVisible()) {
      redrawItemBySelecting(index);
    }
    dispatchEvent(index, false);
  }
 
 
    /**
    * @param pos the position to test, whether selected
    * @return true, if the item at the specified position is selected, false otherwise
    *
    *
    */
  public boolean isSelected(int pos) {
    return  ((Boolean)_selected.get(pos)).booleanValue();
  }
 
 
    /**
    *  @return items, contained in the list
    */
  public java.util.List<String> getItems() {
    return new ArrayList<String>(_items);
  }
 
 
    /**
    * @return all selected items, contained in the list
    */
  public java.util.List<String> getSelectedItems() {
        java.util.List<String> result = new ArrayList<String>();
    for (int i=0; i<_items.size(); i++) {
      boolean selected = isSelected(i);
      if (selected) {
        result.add(_items.get(i));
      }
    }
   
    return result;
  }
 
 
    /**
    * @return indexes of all selected items, contained in the list
    */
  public int [] getSelectedIndexes() {
    int size = 0;
    for (int i=0; i<_items.size(); i++) {
      boolean selected = isSelected(i);
      if (selected) {
        size++;
      }
    }
   
    int [] result = new int [size];
    int currentIndex = 0;
    for (int i=0; i<_items.size(); i++) {
      boolean selected = isSelected(i);
      if (selected) {
        result[currentIndex] = i;
        currentIndex++;
      }
    }
   
    return result;
  }
 
 
    /**
    *  @return the selected item, if only one item is selected, <code>null</code> otherwise.
    */
  public String getSelectedItem() {
        java.util.List<String> results = getSelectedItems();
    String result = null;
    if (results.size() == 1) {
      result = results.get(0);
    }
   
    return result;
  }
 
  /**
    *  @return index of the selected item, if only one item is selected, <code>null</code> otherwise.
    */
  public int getSelectedIndex() {
    int [] results = getSelectedIndexes();
    int result = -1;
    if (results.length == 1) {
      result = results [0];
    }
   
    return result;
  }
 
    /**
    *  Removes all items from the list
    */
  public void clear() {
    _items.clear();
    _selected.clear();
    reset();
  }
 
 
 
  protected Rectangle getPreferredSize() {
    return new Rectangle(-1,(_visibleSize < 0)?-1:_visibleSize+2);
  }
 
 
 
  private int getVisibleSize() {
    return getSize().getHeight()-2;
  }
 
 
//  private int getMaximumStartIndex() {
//    return (_items.size()<getVisibleSize())?0:(_items.size()-getVisibleSize());
//  }
 
 
  private boolean isVisible(int index) {
    if (_items.size() == 0) {
      return false;
    } else {
      return ((index >=_startIndex) && (index < _startIndex+getVisibleSize()));
    }
  }
 
 
 
 
  private boolean findNextSelectableItem(int pos, int searchDirection, boolean onlySearchDirection, int stepping) {
    if (getItemsCount() == 0) {
      return false;
    }
    int page = getPageNumber(pos);
    int start = getPageStartIndex(page);
    int end = getPageEndIndex(page);
    boolean found = false;
    if (isSelectable(pos)) {
      found = true;
    } else {
      int searchPos = pos;
      while ((searchPos <= end) && (searchPos >= start) && (!found)) {
        searchPos+=searchDirection;
        found = isSelectable(searchPos);
      }
      if (!found && !onlySearchDirection) {
        searchPos = pos;
        while ((searchPos <= end) && (searchPos >= start) && (!found)) {
          searchPos-=searchDirection;
          found = isSelectable(searchPos);
        }
      }
      pos = searchPos;
    }
   
    if (found) {
      if (stepping == 0) {
        _startIndex = start;
      } else if (stepping == -1) {
        if (!isVisible(pos)) {
          _startIndex = pos;
        }
      } else {
        if (!isVisible(pos)) {
          _startIndex = Math.max(0,pos-getVisibleSize()+1);
        }
      }
        _trackedIndex = pos;
    }
   
    return found;
   
  }
 
 
  private boolean incrementTrack() {
    boolean found = false;
    if (_trackedIndex < (getItemsCount()-1)) {
      found =  findNextSelectableItem(_trackedIndex+1,1,true,1);
    }
    return found;
  }
 
 
  private Paging getPaging() {
    return new Paging(getVisibleSize(), getItemsCount());
  }
 
 
 

  private int getPageNumber(int index) {
     return getPaging().getPageNumber(index);
  }
 
 
  private int getPageSize() {
     return getPaging().getPageSize();
  }
 
  private int getCurrentPageNumber() {
    return getPageNumber(_trackedIndex);
  }
 
 
  int getPageStartIndex(int pageNumber) {
      return getPaging().getPageStartIndex(pageNumber);
  }
 

  int getPageEndIndex(int pageNumber) {
      return getPaging().getPageEndIndex(pageNumber);
  }
 
  int getCurrentPageOffset() {
    return getPaging().getPageOffset(_trackedIndex);
  }
 

  private boolean incrementPage() {
    int nextPos = 0;
    if (getCurrentPageNumber() < (getPageSize()-1)) {
      nextPos = getPaging().getIndexByPageOffset(getCurrentPageNumber()+1, getCurrentPageOffset());
    } else {
      nextPos = getItemsCount()-1;
    }
   
    return findNextSelectableItem(nextPos, 1, false,0);
 
  }


  private boolean decrementPage() {
    int nextPos = 0;
    if (getCurrentPageNumber() > 0) {
      nextPos = getPaging().getIndexByPageOffset(getCurrentPageNumber()-1, getCurrentPageOffset());
    } else {
      nextPos = 0;
    }
   
    return findNextSelectableItem(nextPos, -1, false,0);
  }

 
  /**
   * Gets the currently tracked item (i.e. where the 'cursor' line is
   * when the user is navigating the list).
   *
   * @return the index of the current tracked item.
   */
  public int getTrackedItem() {
    return _trackedIndex;
  }

  /**
   * Sets the currently tracked item (i.e. where the 'cursor' line is
   * when the user is navigating the list).
   *
   * @param pos the index of the current tracked item.
   * @exception IllegalArgumentException if pos is out of range.
   */
  public void setTrackedItem(int pos) {
    if (pos < 0 || pos >= getItemsCount()) {
      throw new IllegalArgumentException("pos must be in the range: 0," + (getItemsCount() - 1));
    }
    int backupStartIndex = _startIndex;
    int backupTrackedIndex = _trackedIndex;
    if (setTrack(pos)) {
      redraw((backupStartIndex == _startIndex), _trackedIndex, backupTrackedIndex);
    }
  }
 
 

 
 

  protected boolean setTrack(int pos) {
    return findNextSelectableItem(pos, 1, false,0);
  }
 
 
 
 

  private boolean decrementTrack() {
   
    boolean found = false;
    if (_trackedIndex > 0) {
      found =  findNextSelectableItem(_trackedIndex-1, -1, true,-1);
    }
    return found;
  }
 
 
  private void reset() {
    _startIndex = 0;
    _trackedIndex = 0;
    _startPos = 0;
  }
 
 
  private int getMaxLength() {
    int result = 0;
    for (int i=0; i<_items.size(); i++) {
      String item = (String)_items.get(i);
      if (item.length() > result) {
        result = item.length();
      }
    }
   
    return result;
  }
 
 
  private int getMaxStartPos() {
    Rectangle rect = (Rectangle)getSize().clone();
    int width = rect.getWidth()-2;
    int result = getMaxLength() - width;
    result = (result < 0)?0:result;
   
    return result;
   
  }
 
 
  private boolean incrementStartPos() {
    if (_startPos < getMaxStartPos()) {
      _startPos++;
      return true;
    }
   
    return false;
  }
 
 
  private boolean decrementStartPos() {
    if (_startPos > 0) {
      _startPos--;
      return true;
    }
   
    return false;
  }
 
 
 
    /**
    *  Sets, whether items can be selected at all
    *
    * @param value true, if items can be selected, false otherwise ( in this case items can only be 'invoked')
    */
  public void setSelectable(boolean value) {
    _selectable = value;
  }
 
  /**
    *  Sets, whether items can be selected at all
    *
    * @return true, if items can be selected, false otherwise ( in this case items can only be 'invoked')
    */
  public boolean getSelectable() {
    return _selectable;
  }
 
 
 
 
 
 
  /**
    *  This method tests, if the item at the specified position can be selected and invoked at all.
    *  The sense is, to give derived classes the posssibility to implement 'separators'. Here returns
    * always <code>true</code>.
    *  @param i the position to test
  *  @return true if the item at the specified position can be selected and invoked, false otherwise
  */
  protected boolean isSelectable(int i) {
    return true;
  }
 
 
 
  private void drawRectangle() {
    Rectangle rect = (Rectangle)getSize().clone();
    rect.setWidth(rect.getWidth()-2);
    rect.setHeight(rect.getHeight()-2);
    rect.setLocation(getAbsoluteX()+1, getAbsoluteY()+1);
    Toolkit.drawRectangle(rect, getColors());
  }
 
 
  private void drawItems() {
    Rectangle rect = (Rectangle)getSize().clone();
    rect.setLocation(getAbsoluteX(), getAbsoluteY());
    for (int i=0; i<getVisibleSize(); i++) {
      int index = _startIndex +i;
      if ( index < _items.size()) {
        printItem(index, rect);
      } else {
        Toolkit.drawRectangle(new Rectangle(rect.getX()+1,rect.getY()+i+1,rect.getWidth()-2,1),getColors());
      }
    }
    if (_items.size() == 0) {
      drawFirstRowSelected();
    }
  }
 
 
  protected void doPaint() {
    Rectangle rect = (Rectangle)getSize().clone();
    rect.setLocation(getAbsoluteX(), getAbsoluteY());
    Toolkit.drawBorder(rect, getColors());
    drawTitle();
    _scrollbars.paint();
    drawRectangle();
    drawItems()
  }
 
 
 
  private void refresh() {
     _scrollbars.refresh();
     drawRectangle();
     drawItems();
    
  }
 
 
 
 
  private void drawFirstRowSelected() {
    if (hasFocus()) {
      Toolkit.drawRectangle(getAbsoluteX()+1, getAbsoluteY()+1,getSize().getWidth()-2,1,getSelectedItemColors());
    }
  }
 
 
 
  private void redrawItem(int index, Rectangle rect) {
    int x = rect.getX()+1;
    int y = rect.getY()+1+index-_startIndex;
    int width = rect.getWidth()-2;
    Rectangle itemRect = new Rectangle(x,y,width,1);
    boolean toSelect = (((index == _trackedIndex) && hasFocus()) ||
              (isSelected(index)));
    CharColor colors = toSelect?getSelectedItemColors():getColors();
    Toolkit.changeColors(itemRect,colors);
   
  }
 
 
  private void redrawSelectedItems() {
    for (int i=0; i<getVisibleSize(); i++) {
      int index = _startIndex +i;
      if ( index < _items.size()) {
        boolean toSelect = ((index == _trackedIndex) ||
              (isSelected(index)));
        if (toSelect) {
          redrawItem(index, getRectangle());
        }
       
      }
    }
  }
 
 
 
 
  private void printItem(int index, Rectangle rect) {
    int x = rect.getX()+1;
    int y = rect.getY()+1+index-_startIndex;
    int width = rect.getWidth()-2;
    boolean toSelect = (((index == _trackedIndex) && hasFocus()) ||
              (isSelected(index)));
             
    CharColor colors = toSelect?getSelectedItemColors():getColors();
   
    String item = getItemRepresentation((String)_items.get(index));
    if (item.length() < (_startPos +1)) {
      item = "";
    } else {
      if (_startPos!=0) {
         item = item.substring(_startPos, item.length());
      }
    }
   
    if ((item.length() < width) && (toSelect)) {
      StringBuffer itemBuffer = new StringBuffer();
      itemBuffer.append(item);
      for (int i=0;i<(width - item.length()); i++) {
        itemBuffer.append(' ');
      }
      item = itemBuffer.toString();
    }
    Toolkit.printString(item, x, y, width,1,colors);
   
  }
 
  /**
    * The method returns the display representation of the string und is
    * called by the widget before it paints an item. The idea is to make
    * it possible in derived classes to paint other strings as managed in the widget.
    * Here returns always the same string as <code>item</code>
    * @param item string to give display representation
  * @return display representation of the string
  */
  protected String getItemRepresentation(String item) {
    return item;
  }
 
 
 
  protected boolean isFocusable() {
    return true;
  }
 
 
  protected void doRepaint() {
    doPaint();
  }
 
 
  private static InputChar __changeStatusChar = new InputChar(' ');
  private static InputChar __callItemChar = new InputChar('\n');
 
 
  protected InputChar getChangeStatusChar() {
    return __changeStatusChar;
  }
 
 
  private void callItem(int index) {
    ItemEvent event = new ItemEvent(this, index, _items.get(index), ItemEvent.CALLED);
    _listenerManager.handleEvent(event);
  }
 
 
  private void redraw(boolean flag, int trackedIndex, int backupTrackedIndex) {
    if (flag) {
      redrawItem(trackedIndex, getRectangle());
      redrawItem(backupTrackedIndex, getRectangle());
    } else {
      paint();
    }
  }
 
 
 
  protected boolean handleInput(InputChar ch) {
   
    int backupStartIndex = _startIndex;
    int backupTrackedIndex = _trackedIndex;
    // Keine Items - keine Eingabe
    if (_items.size() == 0) {
      return false;
    }
   
    if (ch.getCode() == InputChar.KEY_RIGHT) {
      if (incrementStartPos()) {
        refresh();
      }
      return true;
    } else if (ch.getCode() == InputChar.KEY_LEFT) {
      if (decrementStartPos()) {
        refresh();
      }
      return true;
    } else if (ch.getCode() == InputChar.KEY_UP) {
      if (decrementTrack()) {
        redraw(( backupStartIndex == _startIndex),_trackedIndex,backupTrackedIndex);
      }
      return true;
    } else if (ch.getCode() == InputChar.KEY_DOWN) {
      if (incrementTrack()) {
        redraw(( backupStartIndex == _startIndex),_trackedIndex,backupTrackedIndex);
      }
      return true;
    } else if (ch.getCode() == InputChar.KEY_HOME) {
      if (setTrack(0)) {
        redraw(( backupStartIndex == _startIndex),_trackedIndex,backupTrackedIndex);
      }
      return true;
    } else if (ch.getCode() == InputChar.KEY_END) {
      if (setTrack(getItemsCount() - 1)) {
        redraw(( backupStartIndex == _startIndex),_trackedIndex,backupTrackedIndex);
      }
      return true;
    } else if (ch.getCode() == InputChar.KEY_NPAGE) {
      if (incrementPage()) {
        redraw(( backupStartIndex == _startIndex),_trackedIndex,backupTrackedIndex);
      }
      return true;
    } else if (ch.getCode() == InputChar.KEY_PPAGE) {
      if (decrementPage()) {
        redraw(( backupStartIndex == _startIndex),_trackedIndex,backupTrackedIndex);
      }
      return true;
    } else if (ch.equals(__changeStatusChar) && getSelectable()) {
      if (isSelected(_trackedIndex)) {
        deselect(_trackedIndex);
      } else {
        select(_trackedIndex);
      }
      return true;
    } else if (ch.equals(__callItemChar)) {
      callItem(_trackedIndex);
      return true;
    }
   
   
    return false;
  }
 
 
  protected void focus() {
     redrawSelectedItems();
  }
 
 
  protected void unfocus() {
    redrawSelectedItems();
  }
 
 
    /**
    *  Adds a listener to the widget
    *
    * @param listener listener to add
    */
  public void addListener(ItemListener listener) {
    _listenerManager.addListener(listener);
  }
 
 
    /**
    *  Removes a listener from the widget
    *
    * @param listener listener to remove
    */
  public void removeListener(ItemListener listener) {
    _listenerManager.removeListener(listener);
  }
 
  //Scrollbars
 
  public boolean hasHorizontalScrollbar() {
    return true;
  }
 

  public boolean hasVerticalScrollbar() {
    return true;
  }
 
 
 
  public Rectangle getBorderRectangle() {
    Rectangle rect = (Rectangle)getSize().clone();
    rect.setLocation(getAbsoluteX(), getAbsoluteY());
    return rect;
  }
 
 
  private int getWidth() {
    return (getSize().getWidth()-2);
  }
 
  public float getHorizontalScrollbarOffset() {
    if ((_items.size() == 0) || (getMaxLength() <= getWidth())) {
      // Keine Items - kein scrollbar
      return 0;
    }
    if (getMaxLength() > getWidth()) {
      return ((float)_startPos)/((float)getMaxLength());
    } else {
      return 0;
    }
  }
 
 
  public float getHorizontalScrollbarLength() {
      if ((_items.size() == 0) || (getMaxLength() <= getWidth())) {
      // Keine Items - kein scrollbar
      return 0;
    }
    if (getMaxLength() > getWidth()) {
      return ((float)getWidth())/((float)getMaxLength());
    } else {
      return 0;
    }
  }
 
 
  public float getVerticalScrollbarOffset() {
    if (_items.size() == 0) {
      // Keine Items - kein scrollbar
      return 0;
    }
   
    if (_items.size() > getVisibleSize()) {
      return ((float)_startIndex)/((float)_items.size());
    } else {
      return 0;
    }
  }
 
 
  public float getVerticalScrollbarLength() {
     if (_items.size() == 0) {
      // Keine Items - kein scrollbar
      return 0;
    }
   
    if (_items.size() > getVisibleSize()) {
      return ((float)getVisibleSize())/((float)_items.size());
    } else {
      return 0;
    }
  }
 
 
  public CharColor getBorderColors() {
    return getColors();
  }
 
 
  public CharColor getScrollbarColors() {
    CharColor colors = new CharColor(getColors().getForeground(),getColors().getBackground());
    colors.setBlackWhiteAttribute((colors.getBlackWhiteAttribute() == CharColor.REVERSE)?CharColor.NORMAL:CharColor.REVERSE);
    return colors;
  }
 
}
TOP

Related Classes of jcurses.widgets.List

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.