All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wings.SList Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2000,2005 wingS development team.
 *
 * This file is part of wingS (http://wingsframework.org).
 *
 * wingS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 *
 * Please see COPYING for the complete licence.
 */
package org.wings;

import org.wings.event.SViewportChangeEvent;
import org.wings.event.SViewportChangeListener;
import org.wings.event.SMouseEvent;
import org.wings.plaf.ListCG;
import org.wings.style.CSSAttributeSet;
import org.wings.style.CSSProperty;
import org.wings.style.CSSStyleSheet;
import org.wings.style.Selector;
import org.wings.sdnd.TextAndHTMLTransferable;
import org.wings.sdnd.CustomDragHandler;
import org.wings.sdnd.SDropMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import javax.swing.event.EventListenerList;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import java.awt.*;
import java.awt.datatransfer.Transferable;
import java.util.ArrayList;
import java.util.List;


/**
 * Allows the user to select one or more objects from a list.
 * CAVEAT
 * A list in a form has special implications to take care of:
 * Problem with a form request
 * is, that we should fire the selection change events not until the states
 * of all components are consistent. Unfortunately we cannot avoid events
 * before that
 * entirely. Problem is, that we use Swing Models for selection and they
 * don't know anything about asynchronous state change. They will fire their
 * events just after we set a state. But inside a form we have to change
 * many states of many components, all at once. And events should arise
 * first, after we set the new state of all components. So as a trade-off we
 * decided to use the setValueIsAdjusting in the ListSelectionModel as an
 * indicator,
 * if components are consistent. That is, if you get an SelectionEvent with
 * getValueIsAdjusting true, you cannot be sure, that component states are
 * consistent, so don't use that events. But you will get an event without
 * isValueAdjusting. You can work with that event. If you want to avoid that
 * problem, just use the selection events from the list itself, register your
 * listener at SList rather than at the ListSelectionModel...
 *
 * @author Holger Engels
 * @author Armin Haaf
 * @see javax.swing.ListModel
 * @see SDefaultListModel
 * @see javax.swing.ListSelectionModel
 * @see SListCellRenderer
 */
public class SList extends SComponent implements Scrollable, LowLevelEventListener, ListDataListener {
    private static final Logger LOG = LoggerFactory.getLogger(SList.class);

    /**
     * The type for an ordered list. See {@link #setType(String)} and ORDER_TYPE_xxx
     */
    public static final String ORDERED_LIST = "ol";

    /**
     * The type for an unordered list. See {@link #setType(String)}
     */
    public static final String UNORDERED_LIST = "ul";

    /**
     * The type for an menu-like list. See {@link #setType(String)}
     */
    public static final String MENU_LIST = "menu";

    /**
     * The type for an TO-DO list. See {@link #setType(String)}
     */
    public static final String DIR_LIST = "dir";

    /**
     * Order type for for {@link #setOrderType(String)}
     */
    public static final String[] ORDER_TYPE_CIRCLE = {"ul", "circle"};
    /**
     * Order type for for {@link #setOrderType(String)}
     */
    public static final String[] ORDER_TYPE_SQUARE = {"ul", "square"};
    /**
     * Order type for for {@link #setOrderType(String)}
     */
    public static final String[] ORDER_TYPE_DISC = {"ul", "disc"};
    /**
     * Order type for for {@link #setOrderType(String)}
     */
    public static final String[] ORDER_TYPE_BIG_ALPHA = {"ol", "A"};
    /**
     * Order type for for {@link #setOrderType(String)}
     */
    public static final String[] ORDER_TYPE_SMALL_ALPHA = {"ol", "a"};
    /**
     * Order type for for {@link #setOrderType(String)}
     */
    public static final String[] ORDER_TYPE_NUMBER = {"ol", null};
    /**
     * Order type for for {@link #setOrderType(String)}
     */
    public static final String[] ORDER_TYPE_NORMAL = {"ul", null};
    /**
     * Order type for for {@link #setOrderType(String)}
     */
    public static final String[] ORDER_TYPE_BIG_ROMAN = {"ol", "I"};
    /**
     * Order type for for {@link #setOrderType(String)}
     */
    public static final String[] ORDER_TYPE_SMALL_ROMAN = {"ol", "i"};

    /**
     * Table selection model. See {@link SList#setSelectionMode(int)}
     */
    public static final int NO_SELECTION = SListSelectionModel.NO_SELECTION;
    /**
     * Table selection model. See {@link SList#setSelectionMode(int)}
     */
    public static final int SINGLE_SELECTION = SListSelectionModel.SINGLE_SELECTION;
    /**
     * Table selection model. See {@link SList#setSelectionMode(int)}
     */
    public static final int SINGLE_INTERVAL_SELECTION = SListSelectionModel.SINGLE_INTERVAL_SELECTION;
    /**
     * Table selection model. See {@link SList#setSelectionMode(int)}
     */
    public static final int MULTIPLE_SELECTION = SListSelectionModel.MULTIPLE_INTERVAL_SELECTION;
    /**
     * Table selection model. See {@link SList#setSelectionMode(int)}
     */
    public static final int MULTIPLE_INTERVAL_SELECTION = SListSelectionModel.MULTIPLE_INTERVAL_SELECTION;

    /**
     * The Selector for this component.
     */
    public static final Selector SELECTOR_SELECTION = new Selector("SELECTION");

    /**
     * The preferred extent of the list.
     */
    private int visibleRowCount = 8;


    private SListSelectionModel selectionModel;


    private ListModel dataModel;


    private SListCellRenderer cellRenderer;

    /**
     * Implementation of the {@link Scrollable} interface.
     */
    protected Rectangle viewport;

    /**
     * @see LowLevelEventListener#isEpochCheckEnabled()
     */
    private boolean epochCheckEnabled = true;

    /**
     * 
  • */ protected String type = UNORDERED_LIST; /** *
  • */ protected String orderType = null; /** *
  • */ protected int start = 0; /** * used to forward selection events to selection listeners of the list */ private final ListSelectionListener fwdSelectionEvents = e -> { fireSelectionValueChanged(e.getFirstIndex(), e.getLastIndex(), e.getValueIsAdjusting()); if (isUpdatePossible() && SList.class.isAssignableFrom(SList.this.getClass())) { List deselectedIndices = new ArrayList(); List selectedIndices = new ArrayList(); for (int index = e.getFirstIndex(); index <= e.getLastIndex(); ++index) { int visibleIndex = index; if (viewport != null) { visibleIndex = index - viewport.y; if (visibleIndex < 0 || visibleIndex >= viewport.height) continue; } //LKoller - fboss [15.4.09]: Added index range check with model to prevent illegal or outdated indices, // that will result in an error message on the webpage. if (visibleIndex < dataModel.getSize()) { if (isSelectedIndex(index)) { selectedIndices.add(visibleIndex); } else { deselectedIndices.add(visibleIndex); } } } update(((ListCG) getCG()).getSelectionUpdate(SList.this, deselectedIndices, selectedIndices)); } else { reload(); } }; /** * Construct a SList that displays the elements in the specified model. */ public SList(ListModel dataModel) { if (dataModel == null) { throw new IllegalArgumentException("dataModel must not be null"); } if (this.dataModel != null) this.dataModel.removeListDataListener(this); this.dataModel = dataModel; this.dataModel.addListDataListener(this); setSelectionModel(createSelectionModel()); installTransferHandler(); createActionMap(); } /** * Construct a SList that displays the elements in the specified * array. */ public SList(final Object... listData) { this(new AbstractListModel() { @Override public int getSize() { return listData.length; } @Override public Object getElementAt(int i) { return listData[i]; } }); } /** * Construct a SList that displays the elements in the specified * Vector. */ public SList(final List listData) { this(new AbstractListModel() { @Override public int getSize() { return listData.size(); } @Override public Object getElementAt(int i) { return listData.get(i); } }); } /** * Constructs a SList with an empty model. */ public SList() { this(new AbstractListModel() { @Override public int getSize() { return 0; } @Override public Object getElementAt(int i) { return "No Data Model"; } }); } /** * Returns the cell renderer. * * @return the ListCellRenderer * @see #setCellRenderer */ public final SListCellRenderer getCellRenderer() { return cellRenderer; } /** * Sets the renderer that's used to write out each cell in the list. * * @param cellRenderer the SListCellRenderer that paints list cells * description: The component used to draw the cells. * @see #getCellRenderer */ public void setCellRenderer(SListCellRenderer cellRenderer) { SListCellRenderer oldValue = this.cellRenderer; this.cellRenderer = cellRenderer; reloadIfChange(oldValue, cellRenderer); propertyChangeSupport.firePropertyChange("cellRenderer", oldValue, this.cellRenderer); } /** * Return the background color. * * @return the background color */ public Color getSelectionBackground() { return dynamicStyles == null || dynamicStyles.get(SELECTOR_SELECTION) == null ? null : CSSStyleSheet.getBackground((CSSAttributeSet) dynamicStyles.get(SELECTOR_SELECTION)); } /** * Set the foreground color. * * @param color the new foreground color */ public void setSelectionBackground(Color color) { Color oldVal = this.getSelectionBackground(); setAttribute(SELECTOR_SELECTION, CSSProperty.BACKGROUND_COLOR, CSSStyleSheet.getAttribute(color)); propertyChangeSupport.firePropertyChange("selectionBackground", oldVal, this.getSelectionBackground()); } /** * Return the foreground color. * * @return the foreground color */ public Color getSelectionForeground() { return dynamicStyles == null || dynamicStyles.get(SELECTOR_SELECTION) == null ? null : CSSStyleSheet.getForeground((CSSAttributeSet) dynamicStyles.get(SELECTOR_SELECTION)); } /** * Set the foreground color. * * @param color the new foreground color */ public void setSelectionForeground(Color color) { Color oldVal = this.getSelectionForeground(); setAttribute(SELECTOR_SELECTION, CSSProperty.COLOR, CSSStyleSheet.getAttribute(color)); propertyChangeSupport.firePropertyChange("selectionForeground", oldVal, this.getSelectionForeground()); } /** * Set the font. * * @param font the new font */ public void setSelectionFont(SFont font) { SFont oldVal = this.getSelectionFont(); setAttributes(SELECTOR_SELECTION, CSSStyleSheet.getAttributes(font)); propertyChangeSupport.firePropertyChange("selectionFont", oldVal, this.getSelectionFont()); } /** * Return the font. * * @return the font */ public SFont getSelectionFont() { return dynamicStyles == null || dynamicStyles.get(SELECTOR_SELECTION) == null ? null : CSSStyleSheet.getFont((CSSAttributeSet) dynamicStyles.get(SELECTOR_SELECTION)); } /** * Return the preferred number of visible rows. If rendered as a form * component it is used for the size-attribute. * * @return the preferred number of rows to display * @see #setVisibleRowCount */ public final int getVisibleRowCount() { return visibleRowCount; } /** * Set the preferred number of rows in the list that can be displayed * without a scollbar. *

    * The default value of this property is 8. * * @param visibleRowCount the preferred number of visible rows * description: The preferred number of cells that can be displayed without a scrollbar. * @see #getVisibleRowCount */ public void setVisibleRowCount(int visibleRowCount) { if (this.visibleRowCount != visibleRowCount) { int oldVal = this.visibleRowCount; this.visibleRowCount = Math.max(0, visibleRowCount); reload(); propertyChangeSupport.firePropertyChange("visibleRowCount", oldVal, this.visibleRowCount); } } /** * --- ListModel Support --- */ /** * Returns the data model that holds the items. * * @return the ListModel * @see #setModel */ public ListModel getModel() { return dataModel; } /** * Sets the model * * @param model the ListModel that provides the list of items * description: The object that contains the data to be shownin the list. * @see #getModel */ public void setModel(ListModel model) { if (model == null) { throw new IllegalArgumentException("model must be non null"); } if (isDifferent(dataModel, model)) { ListModel oldVal = this.dataModel; clearSelection(); dataModel = model; dataModel.addListDataListener(this); fireViewportChanged(false); reload(); propertyChangeSupport.firePropertyChange("model", oldVal, this.dataModel); } } /** * A convenience method that constructs a ListModel from an array of Objects * and then applies setModel to it. * * @param listData an array of Objects containing the items to display * in the list * @see #setModel */ public void setListData(final Object... listData) { setModel(new AbstractListModel() { @Override public int getSize() { return listData.length; } @Override public Object getElementAt(int i) { return listData[i]; } }); } /** * A convenience method that constructs a ListModel from a List * and then applies setModel to it. * * @param listData a Vector containing the items to display in the list * @see #setModel */ public void setListData(final List listData) { setModel(new MyAbstractListModel(listData)); } /** * creates the default selection model. It uses the swing * DefaultListSelectionModel, and wraps some methods to support * {@link SListSelectionModel#NO_SELECTION} */ protected static SListSelectionModel createSelectionModel() { return new SDefaultListSelectionModel(); } /** * Returns the current selection model. If selection mode is * {@link SListSelectionModel#NO_SELECTION} it return null * * @return the ListSelectionModel that implements list selections. * If selection mode is {@link SListSelectionModel#NO_SELECTION} it return * null * @see #setSelectionMode(int) * @see ListSelectionModel */ public SListSelectionModel getSelectionModel() { return selectionModel; } /** * This method notifies all ListSelectionListeners that * the selection model has changed. * * @see #addListSelectionListener * @see #removeListSelectionListener * @see EventListenerList */ protected void fireSelectionValueChanged(int firstIndex, int lastIndex, boolean isAdjusting) { Object[] listeners = getListenerList(); ListSelectionEvent e = null; for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ListSelectionListener.class) { if (e == null) { e = new ListSelectionEvent(this, firstIndex, lastIndex, isAdjusting); } ((ListSelectionListener) listeners[i + 1]).valueChanged(e); } } } /** * Add a listener to the list that's notified each time a change * to the selection occurs. * *

    * If you want to receive immedate an event when the user clicks a new item * on the client side you have to register additionally a Java script listener * which triggers a form submit.
    * combobox.addScriptListener(ListCG.JS_ON_CHANGE_SUBMIT) * * @param listener A ListSelectionListener to be added * @see #getSelectionModel */ public void addListSelectionListener(ListSelectionListener listener) { addEventListener(ListSelectionListener.class, listener); } /** * Remove a listener from the list that's notified each time a * change to the selection occurs. * * @param listener The ListSelectionListener to remove. * @see #addListSelectionListener * @see #getSelectionModel */ public void removeListSelectionListener(ListSelectionListener listener) { removeEventListener(ListSelectionListener.class, listener); } /** * Returns an array of all the ListSelectionListeners added * to this JList with addListSelectionListener(). * * @return all of the ListSelectionListener added * @since 1.4 */ public ListSelectionListener[] getListSelectionListeners() { return (ListSelectionListener[]) getListeners(ListSelectionListener.class); } /** * Set the selectionModel for the list. * The selection model keeps track of which items are selected. *

    * description: The selection model, recording which cells are selected. * * @see #getSelectionModel */ public void setSelectionModel(SListSelectionModel selectionModel) { if (selectionModel == null) { throw new IllegalArgumentException("selectionModel must be non null"); } SListSelectionModel oldVal = this.selectionModel; if (this.selectionModel != null) this.selectionModel.removeListSelectionListener(fwdSelectionEvents); selectionModel.addListSelectionListener(fwdSelectionEvents); this.selectionModel = selectionModel; propertyChangeSupport.firePropertyChange("selectionModel", oldVal, this.selectionModel); } /** * Allow / permit multiple selection *

      *
    • SINGLE_SELECTION * Only one list index can be selected at a time. *
    • MULTIPLE_INTERVAL_SELECTION * Multiple items can be selected. *
    * * @param selectionMode single or multiple selections * enum: SINGLE_SELECTION ListSelectionModel.SINGLE_SELECTION * MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION * @see #getSelectionMode */ public void setSelectionMode(int selectionMode) { int oldVal = selectionModel.getSelectionMode(); selectionModel.setSelectionMode(selectionMode); propertyChangeSupport.firePropertyChange("selectionMode", oldVal, selectionModel.getSelectionMode()); } /** * Returns whether single-item or multiple-item selections are allowed. * * @return The value of the selectionMode property. * @see #setSelectionMode */ public int getSelectionMode() { return selectionModel.getSelectionMode(); } /** * @return The index that most recently anchored an interval selection. * @see ListSelectionModel#getAnchorSelectionIndex * @see #addSelectionInterval * @see #setSelectionInterval * @see #addListSelectionListener */ public int getAnchorSelectionIndex() { return selectionModel.getAnchorSelectionIndex(); } /** * @return The index that most recently ended a interval selection. * @see ListSelectionModel#getLeadSelectionIndex * @see #addSelectionInterval * @see #setSelectionInterval * @see #addListSelectionListener */ public int getLeadSelectionIndex() { return selectionModel.getLeadSelectionIndex(); } /** * @return The smallest selected cell index. * @see ListSelectionModel#getMinSelectionIndex * @see #addListSelectionListener */ public int getMinSelectionIndex() { return selectionModel.getMinSelectionIndex(); } /** * @return The largest selected cell index. * @see ListSelectionModel#getMaxSelectionIndex * @see #addListSelectionListener */ public int getMaxSelectionIndex() { return selectionModel.getMaxSelectionIndex(); } /** * @return True if the specified index is selected. * @see ListSelectionModel#isSelectedIndex * @see #setSelectedIndex * @see #addListSelectionListener */ public boolean isSelectedIndex(int index) { return selectionModel.isSelectedIndex(index); } /** * @return True if nothing is selected * @see ListSelectionModel#isSelectionEmpty * @see #clearSelection * @see #addListSelectionListener */ public boolean isSelectionEmpty() { return selectionModel.isSelectionEmpty(); } /** * @see ListSelectionModel#clearSelection * @see #isSelectionEmpty * @see #addListSelectionListener */ public void clearSelection() { if (!selectionModel.isSelectionEmpty()) { selectionModel.clearSelection(); reload(); } } /** * @param anchor The first index to select * @param lead The last index to select * @see ListSelectionModel#setSelectionInterval * @see #addSelectionInterval * @see #removeSelectionInterval * @see #addListSelectionListener */ public void setSelectionInterval(int anchor, int lead) { int[] oldVal = {this.getAnchorSelectionIndex(), this.getLeadSelectionIndex()}; selectionModel.setSelectionInterval(anchor, lead); int[] newVal = {this.getAnchorSelectionIndex(), this.getLeadSelectionIndex()}; propertyChangeSupport.firePropertyChange("selectionInterval", oldVal, newVal); } /** * @param anchor The first index to add to the selection * @param lead The last index to add to the selection * @see ListSelectionModel#addSelectionInterval * @see #setSelectionInterval * @see #removeSelectionInterval * @see #addListSelectionListener */ public void addSelectionInterval(int anchor, int lead) { selectionModel.addSelectionInterval(anchor, lead); } /** * @param index0 The first index to remove from the selection * @param index1 The last index to remove from the selection * @see ListSelectionModel#removeSelectionInterval * @see #setSelectionInterval * @see #addSelectionInterval * @see #addListSelectionListener */ public void removeSelectionInterval(int index0, int index1) { selectionModel.removeSelectionInterval(index0, index1); } /** * @param b the value for valueIsAdjusting * @see ListSelectionModel#setValueIsAdjusting */ public void setValueIsAdjusting(boolean b) { boolean oldVal = selectionModel.getValueIsAdjusting(); selectionModel.setValueIsAdjusting(b); boolean newVal = selectionModel.getValueIsAdjusting(); propertyChangeSupport.firePropertyChange("valueIsAdjusting", oldVal, newVal); } /** * @return the value of valueIsAdjusting * @see ListSelectionModel#getValueIsAdjusting */ public boolean getValueIsAdjusting() { return selectionModel.getValueIsAdjusting(); } /** * Return an array of all of the selected indices. * * @return all selected indices. * @see #removeSelectionInterval * @see #addListSelectionListener */ public int[] getSelectedIndices() { ListSelectionModel sm = selectionModel; int iMin = sm.getMinSelectionIndex(); int iMax = sm.getMaxSelectionIndex(); if ((iMin < 0) || (iMax < 0)) { return new int[0]; } int[] rvTmp = new int[1 + (iMax - iMin)]; int n = 0; for (int i = iMin; i <= iMax; i++) { if (sm.isSelectedIndex(i)) { rvTmp[n++] = i; } } int[] rv = new int[n]; System.arraycopy(rvTmp, 0, rv, 0, n); return rv; } /** * Select a single cell. * * @param index The index of the one cell to select * @see ListSelectionModel#setSelectionInterval * @see #isSelectedIndex * @see #addListSelectionListener */ public void setSelectedIndex(int index) { int oldVal = this.getSelectedIndex(); selectionModel.setSelectionInterval(index, index); propertyChangeSupport.firePropertyChange("selectedIndex", oldVal, this.getSelectedIndex()); } /** * Select some cells. * * @param indices The indices of the cells to select * @see ListSelectionModel#addSelectionInterval * @see #isSelectedIndex * @see #addListSelectionListener */ public void setSelectedIndices(int... indices) { ListSelectionModel sm = selectionModel; int[] oldVal = this.getSelectedIndices(); sm.clearSelection(); for (int indice : indices) { sm.addSelectionInterval(indice, indice); } propertyChangeSupport.firePropertyChange("selectedIndices", oldVal, this.getSelectedIndices()); } /** * Return the values of the selected cells. * Returns only the selected elements which are in the model. * If the selection model indices a selection outside the the datamodel it is ignored * * @return the selected values * @see #isSelectedIndex * @see #getModel * @see #addListSelectionListener */ public Object[] getSelectedValues() { ListSelectionModel sm = selectionModel; ListModel dm = dataModel; int iMin = sm.getMinSelectionIndex(); int iMax = sm.getMaxSelectionIndex(); if ((iMin < 0) || (iMax < 0)) { return new Object[0]; } Object[] rvTmp = new Object[1 + (iMax - iMin)]; int n = 0; for (int i = iMin; i <= iMax; i++) { if (sm.isSelectedIndex(i) && i < dm.getSize()) { rvTmp[n++] = dm.getElementAt(i); } } Object[] rv = new Object[n]; System.arraycopy(rvTmp, 0, rv, 0, n); return rv; } /** * A convenience method that returns the first selected index. * * @return The first selected index. * @see #getMinSelectionIndex * @see #addListSelectionListener */ public int getSelectedIndex() { return getMinSelectionIndex(); } /** * A convenience method that returns the first selected value * or null, if nothing is selected. * * @return The first selected value. * @see #getMinSelectionIndex * @see #getModel * @see #addListSelectionListener */ public Object getSelectedValue() { int i = getMinSelectionIndex(); return (i == -1) ? null : dataModel.getElementAt(i); } /** * Selects the specified object. * * @param anObject the Object to be selected */ public void setSelectedValue(Object anObject) { if (anObject == null) setSelectedIndex(-1); else if (!anObject.equals(getSelectedValue())) { int i, c; ListModel dm = dataModel; for (i = 0, c = dm.getSize(); i < c; i++) if (anObject.equals(dm.getElementAt(i))) { setSelectedIndex(i); return; } setSelectedIndex(-1); } } /* * Sets the list type. Use one of the following types: *
      *
    • {@link SConstants#ORDERED_LIST} *
    • {@link SConstants#UNORDERED_LIST} *
    • {@link SConstants#MENU_LIST} *
    • {@link SConstants#DIR_LIST} *
    * null sets default list. * * @param t the type */ public void setType(String t) { String oldVal = this.type; if (t != null) type = t; else type = UNORDERED_LIST; propertyChangeSupport.firePropertyChange("type", oldVal, this.type); } /** * Return the type. * * @return the type; */ public String getType() { return type; } /** *
  • */ public void setOrderType(String t) { String oldVal = this.orderType; orderType = t; propertyChangeSupport.firePropertyChange("orderType", oldVal, this.orderType); } /** *
  • */ public String getOrderType() { return orderType; } /* *
  • * null is default style. */ public void setType(String... t) { if (t == null) { setType((String) null); setOrderType(null); } else if (t.length == 2) { setType(t[0]); setOrderType(t[1]); } } /** *
  • */ public void setStart(int s) { int oldVal = this.start; start = s; propertyChangeSupport.firePropertyChange("start", oldVal, this.start); } /** *
  • */ public int getStart() { return start; } @Override public void fireIntermediateEvents() { selectionModel.fireDelayedIntermediateEvents(); } @Override public void fireFinalEvents() { super.fireFinalEvents(); // fire selection events... selectionModel.fireDelayedFinalEvents(); } /** * @see LowLevelEventListener#isEpochCheckEnabled() */ @Override public boolean isEpochCheckEnabled() { return epochCheckEnabled; } /** * @see LowLevelEventListener#isEpochCheckEnabled() */ public void setEpochCheckEnabled(boolean epochCheckEnabled) { boolean oldVal = this.epochCheckEnabled; this.epochCheckEnabled = epochCheckEnabled; propertyChangeSupport.firePropertyChange("epochCheckEnabled", oldVal, this.epochCheckEnabled); } private int lastSelectedIndex; protected void addSelectionEvent(int index, boolean ctrlKey, boolean shiftKey) { if(index != -1) { if(shiftKey == false && ctrlKey == false) { setSelectionInterval(index, index); lastSelectedIndex = index; } else if(ctrlKey == true && shiftKey == false) { if(!isSelectedIndex(index)) addSelectionInterval(index, index); else removeSelectionInterval(index, index); lastSelectedIndex = index; } else if(ctrlKey == false && shiftKey == true) { setSelectionInterval(lastSelectedIndex, index); } } } /* * Implement {@link LowLevelEventListener} interface. * @param action the name * @param value the value */ @Override public void processLowLevelEvent(String action, String... values) { processKeyEvents(values); if (action.endsWith("_keystroke")) return; // delay events... selectionModel.setDelayEvents(true); selectionModel.setValueIsAdjusting(true); // in a form, we only get events for selected items, so for every // selected item, which is not in values, deselect it... if (getShowAsFormComponent()) { ArrayList selectedIndices = new ArrayList(); for (String indexString : values) { if (indexString.length() < 1) continue; // false format try { int index = Integer.parseInt(indexString); // in a form all parameters are select parameters... selectedIndices.add(index); addSelectionInterval(index, index); } catch (Exception ex) { } } // remove all selected indices, which are not explicitely selected by a parameter for (int i = 0; i < dataModel.getSize(); ++i) { if (isSelectedIndex(i) && !selectedIndices.contains(i)) { removeSelectionInterval(i, i); } } } else { int index = -1; for (String value : values) { String[] paramVals = value.split(";"); boolean shiftKey = false; boolean ctrlKey = false; for (String indexString : paramVals) { if (indexString.length() < 1) continue; // false format if (indexString.startsWith("ctrlKey=")) { ctrlKey = Boolean.parseBoolean(indexString.substring(indexString.indexOf('=') + 1)); continue; } if (indexString.startsWith("shiftKey=")) { shiftKey = Boolean.parseBoolean(indexString.substring(indexString.indexOf("=") + 1)); continue; } try { index = Integer.parseInt(indexString); // toggle selection for given index } catch (Exception ex) { } } addSelectionEvent(index, ctrlKey, shiftKey); } } selectionModel.setValueIsAdjusting(false); selectionModel.setDelayEvents(false); SForm.addArmedComponent(this); } /** * The size of the component in respect to scrollable units. */ @Override public Rectangle getScrollableViewportSize() { return new Rectangle(0, 0, 1, dataModel.getSize()); } /** * Returns the actual visible part of a scrollable. */ @Override public Rectangle getViewportSize() { return viewport; } /** * Sets the actual visible part of a scrollable. */ @Override public void setViewportSize(Rectangle newViewport) { Rectangle oldViewport = viewport; viewport = newViewport; if (isDifferent(oldViewport, newViewport)) { if (oldViewport == null || newViewport == null) { fireViewportChanged(true); fireViewportChanged(false); } else { if (newViewport.x != oldViewport.x || newViewport.width != oldViewport.width) { fireViewportChanged(true); } if (newViewport.y != oldViewport.y || newViewport.height != oldViewport.height) { fireViewportChanged(false); } } reload(); } propertyChangeSupport.firePropertyChange("biewPortSize", oldViewport, this.viewport); } /** * Adds the given SViewportChangeListener to the scrollable. * * @param l the listener to be added */ @Override public void addViewportChangeListener(SViewportChangeListener l) { addEventListener(SViewportChangeListener.class, l); } /** * Removes the given SViewportChangeListener from the scrollable. * * @param l the listener to be removed */ @Override public void removeViewportChangeListener(SViewportChangeListener l) { removeEventListener(SViewportChangeListener.class, l); } /** * Notifies all listeners that have registered interest for notification * on changes to this scrollable's viewport in the specified direction. * * @see EventListenerList */ protected void fireViewportChanged(boolean horizontal) { Object[] listeners = getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == SViewportChangeListener.class) { SViewportChangeEvent event = new SViewportChangeEvent(this, horizontal); ((SViewportChangeListener) listeners[i + 1]).viewportChanged(event); } } } @Override public void setParent(SContainer p) { super.setParent(p); if (cellRendererPane != null) { cellRendererPane.setParent(p); } } @Override protected void setParentFrame(SFrame f) { super.setParentFrame(f); if (cellRendererPane != null) { cellRendererPane.setParentFrame(f); } } // do not initalize with null! private SCellRendererPane cellRendererPane = new SCellRendererPane(); public SCellRendererPane getCellRendererPane() { return cellRendererPane; } public void removeCellRendererPane() { cellRendererPane.setParent(null); cellRendererPane = null; } public void setCG(ListCG cg) { super.setCG(cg); } public String getToggleSelectionParameter(int index) { return isSelectedIndex(index) ? getDeselectionParameter(index) : getSelectionParameter(index); } public static String getSelectionParameter(int index) { return Integer.toString(index); } public static String getDeselectionParameter(int index) { return Integer.toString(index); } // Changes to the model should force a reload. @Override public void contentsChanged(javax.swing.event.ListDataEvent e) { fireViewportChanged(false); reload(); } @Override public void intervalAdded(javax.swing.event.ListDataEvent e) { fireViewportChanged(false); clearSelection(); reload(); } @Override public void intervalRemoved(javax.swing.event.ListDataEvent e) { fireViewportChanged(false); clearSelection(); reload(); } /** * Drag and Drop stuff */ private SDropMode dropMode = null; private boolean dragEnabled = false; protected void createActionMap() { ActionMap map = getActionMap(); map.put(STransferHandler.getCutAction().getValue(Action.NAME), STransferHandler.getCutAction()); map.put(STransferHandler.getCopyAction().getValue(Action.NAME), STransferHandler.getCopyAction()); map.put(STransferHandler.getPasteAction().getValue(Action.NAME), STransferHandler.getPasteAction()); } public static final class DropLocation extends STransferHandler.DropLocation { private int index; public DropLocation(SList list, SPoint point) { super(point); try { index = Integer.parseInt(point.getCoordinates()); Rectangle currentViewport = list.getViewportSize(); if(currentViewport != null) index += currentViewport.y; } catch(Exception e) { index = 0; } } public int getIndex() { return index; } } public void setDropMode(SDropMode dropMode) { this.dropMode = dropMode; getSession().getSDragAndDropManager().addDropTarget(this); } public SDropMode getDropMode() { return this.dropMode; } @Override protected DropLocation dropLocationForPoint(SPoint p) { if(p.getCoordinates() == null) return null; return new SList.DropLocation(this, p); } private void installTransferHandler() { if(getTransferHandler() == null) { setTransferHandler(new DefaultTransferHandler()); } } public void setDragEnabled(boolean dragEnabled) { if(selectionModel == null && dragEnabled == true) throw new IllegalStateException("Unable to enable DND - no selection mode set in " + this); if(getShowAsFormComponent() && dragEnabled == true) { LOG.warn("NOTE: setDragEnabled(true) called when getShowAsFormComponent was false - dragging won't work in internet explorer"); return; } if(dragEnabled != this.dragEnabled) { if(dragEnabled) { this.getSession().getSDragAndDropManager().addDragSource(this); } else { this.getSession().getSDragAndDropManager().removeDragSource(this); } this.dragEnabled = dragEnabled; } } public static class DefaultTransferHandler extends STransferHandler implements CustomDragHandler { public DefaultTransferHandler() { super(null); } @Override protected Transferable createTransferable(SComponent component) { SList list = (SList)component; String htmlData = "
      "; String plainTextData = ""; for(Object obj:list.getSelectedValues()) { plainTextData += obj.toString() + '\n'; htmlData += "
    • " + obj.toString() + "
    • "; } htmlData += "
    "; return new TextAndHTMLTransferable(plainTextData, htmlData); } @Override public int getSourceActions(SComponent component) { return COPY; } @Override public boolean dragStart(SComponent source, SComponent target, int action, SMouseEvent event) { try { String[] coords = event.getPoint().getCoordinates().split(":"); int index = Integer.parseInt(coords[0]); if(coords.length < 3) return false; boolean ctrlKey = false; boolean shiftKey = false; for(int i=1; i




  • © 2015 - 2024 Weber Informatics LLC | Privacy Policy