0001: /*
0002: * Copyright 2000,2005 wingS development team.
0003: *
0004: * This file is part of wingS (http://wingsframework.org).
0005: *
0006: * wingS is free software; you can redistribute it and/or modify
0007: * it under the terms of the GNU Lesser General Public License
0008: * as published by the Free Software Foundation; either version 2.1
0009: * of the License, or (at your option) any later version.
0010: *
0011: * Please see COPYING for the complete licence.
0012: */
0013: package org.wings;
0014:
0015: import org.wings.event.SViewportChangeEvent;
0016: import org.wings.event.SViewportChangeListener;
0017: import org.wings.plaf.ListCG;
0018: import org.wings.style.CSSAttributeSet;
0019: import org.wings.style.CSSProperty;
0020: import org.wings.style.CSSStyleSheet;
0021: import org.wings.style.Selector;
0022:
0023: import javax.swing.*;
0024: import javax.swing.event.EventListenerList;
0025: import javax.swing.event.ListDataListener;
0026: import javax.swing.event.ListSelectionEvent;
0027: import javax.swing.event.ListSelectionListener;
0028:
0029: import java.awt.*;
0030: import java.util.ArrayList;
0031: import java.util.List;
0032:
0033: /**
0034: * Allows the user to select one or more objects from a list.
0035: * <em>CAVEAT</em>
0036: * A list in a form has special implications to take care of:
0037: * Problem with a form request
0038: * is, that we should fire the selection change events not until the states
0039: * of all components are consistent. Unfortunately we cannot avoid events
0040: * before that
0041: * entirely. Problem is, that we use Swing Models for selection and they
0042: * don't know anything about asynchronous state change. They will fire their
0043: * events just after we set a state. But inside a form we have to change
0044: * many states of many components, all at once. And events should arise
0045: * first, after we set the new state of all components. So as a trade-off we
0046: * decided to use the setValueIsAdjusting in the ListSelectionModel as an
0047: * indicator,
0048: * if components are consistent. That is, if you get an SelectionEvent with
0049: * getValueIsAdjusting true, you cannot be sure, that component states are
0050: * consistent, so don't use that events. But you will get an event without
0051: * isValueAdjusting. You can work with that event. If you want to avoid that
0052: * problem, just use the selection events from the list itself, register your
0053: * listener at SList rather than at the ListSelectionModel...
0054: *
0055: * @author Holger Engels
0056: * @author <a href="mailto:armin.haaf@mercatis.de">Armin Haaf</a>
0057: * @see javax.swing.ListModel
0058: * @see SDefaultListModel
0059: * @see javax.swing.ListSelectionModel
0060: * @see SListCellRenderer
0061: */
0062: public class SList extends SComponent implements Scrollable,
0063: LowLevelEventListener, ListDataListener {
0064:
0065: /**
0066: * The type for an ordered list. See {@link #setType(String)} and ORDER_TYPE_xxx
0067: */
0068: public static final String ORDERED_LIST = "ol";
0069:
0070: /**
0071: * The type for an unordered list. See {@link #setType(String)}
0072: */
0073: public static final String UNORDERED_LIST = "ul";
0074:
0075: /**
0076: * The type for an menu-like list. See {@link #setType(String)}
0077: */
0078: public static final String MENU_LIST = "menu";
0079:
0080: /**
0081: * The type for an TO-DO list. See {@link #setType(String)}
0082: */
0083: public static final String DIR_LIST = "dir";
0084:
0085: /**
0086: * Order type for for {@link #setOrderType(String)}
0087: */
0088: public static final String[] ORDER_TYPE_CIRCLE = { "ul", "circle" };
0089: /**
0090: * Order type for for {@link #setOrderType(String)}
0091: */
0092: public static final String[] ORDER_TYPE_SQUARE = { "ul", "square" };
0093: /**
0094: * Order type for for {@link #setOrderType(String)}
0095: */
0096: public static final String[] ORDER_TYPE_DISC = { "ul", "disc" };
0097: /**
0098: * Order type for for {@link #setOrderType(String)}
0099: */
0100: public static final String[] ORDER_TYPE_BIG_ALPHA = { "ol", "A" };
0101: /**
0102: * Order type for for {@link #setOrderType(String)}
0103: */
0104: public static final String[] ORDER_TYPE_SMALL_ALPHA = { "ol", "a" };
0105: /**
0106: * Order type for for {@link #setOrderType(String)}
0107: */
0108: public static final String[] ORDER_TYPE_NUMBER = { "ol", null };
0109: /**
0110: * Order type for for {@link #setOrderType(String)}
0111: */
0112: public static final String[] ORDER_TYPE_NORMAL = { "ul", null };
0113: /**
0114: * Order type for for {@link #setOrderType(String)}
0115: */
0116: public static final String[] ORDER_TYPE_BIG_ROMAN = { "ol", "I" };
0117: /**
0118: * Order type for for {@link #setOrderType(String)}
0119: */
0120: public static final String[] ORDER_TYPE_SMALL_ROMAN = { "ol", "i" };
0121:
0122: /**
0123: * Table selection model. See {@link SList#setSelectionMode(int)}
0124: */
0125: public static final int NO_SELECTION = SListSelectionModel.NO_SELECTION;
0126: /**
0127: * Table selection model. See {@link SList#setSelectionMode(int)}
0128: */
0129: public static final int SINGLE_SELECTION = SListSelectionModel.SINGLE_SELECTION;
0130: /**
0131: * Table selection model. See {@link SList#setSelectionMode(int)}
0132: */
0133: public static final int SINGLE_INTERVAL_SELECTION = SListSelectionModel.SINGLE_INTERVAL_SELECTION;
0134: /**
0135: * Table selection model. See {@link SList#setSelectionMode(int)}
0136: */
0137: public static final int MULTIPLE_SELECTION = SListSelectionModel.MULTIPLE_INTERVAL_SELECTION;
0138: /**
0139: * Table selection model. See {@link SList#setSelectionMode(int)}
0140: */
0141: public static final int MULTIPLE_INTERVAL_SELECTION = SListSelectionModel.MULTIPLE_INTERVAL_SELECTION;
0142:
0143: /**
0144: * The Selector for this component.
0145: */
0146: public static final Selector SELECTOR_SELECTION = new Selector(
0147: "SELECTION");
0148:
0149: /**
0150: * The preferred extent of the list.
0151: */
0152: private int visibleRowCount = 8;
0153:
0154: private SListSelectionModel selectionModel;
0155:
0156: private ListModel dataModel;
0157:
0158: private SListCellRenderer cellRenderer;
0159:
0160: /**
0161: * Implementation of the {@link Scrollable} interface.
0162: */
0163: protected Rectangle viewport;
0164:
0165: /**
0166: * @see LowLevelEventListener#isEpochCheckEnabled()
0167: */
0168: private boolean epochCheckEnabled = true;
0169:
0170: /**
0171: * <li type="...">
0172: */
0173: protected String type = UNORDERED_LIST;
0174:
0175: /**
0176: * <li type="...">
0177: */
0178: protected String orderType = null;
0179:
0180: /**
0181: * <li start="...">
0182: */
0183: protected int start = 0;
0184:
0185: /**
0186: * used to forward selection events to selection listeners of the list
0187: */
0188: private final ListSelectionListener fwdSelectionEvents = new ListSelectionListener() {
0189: public void valueChanged(ListSelectionEvent e) {
0190: fireSelectionValueChanged(e.getFirstIndex(), e
0191: .getLastIndex(), e.getValueIsAdjusting());
0192:
0193: if (isUpdatePossible()
0194: && SList.class.isAssignableFrom(SList.this
0195: .getClass())) {
0196: List deselectedIndices = new ArrayList();
0197: List selectedIndices = new ArrayList();
0198: for (int index = e.getFirstIndex(); index <= e
0199: .getLastIndex(); ++index) {
0200: int visibleIndex = index;
0201: if (getViewportSize() != null) {
0202: visibleIndex = index - getViewportSize().y;
0203: if (visibleIndex < 0
0204: || visibleIndex >= getViewportSize().height)
0205: continue;
0206: }
0207: if (isSelectedIndex(index)) {
0208: selectedIndices.add(new Integer(visibleIndex));
0209: } else {
0210: deselectedIndices
0211: .add(new Integer(visibleIndex));
0212: }
0213: }
0214: update(((ListCG) getCG()).getSelectionUpdate(
0215: SList.this , deselectedIndices, selectedIndices));
0216: } else {
0217: reload();
0218: }
0219: }
0220: };
0221:
0222: /**
0223: * Construct a SList that displays the elements in the specified model.
0224: */
0225: public SList(ListModel dataModel) {
0226: if (dataModel == null) {
0227: throw new IllegalArgumentException(
0228: "dataModel must not be null");
0229: }
0230: if (this .dataModel != null)
0231: this .dataModel.removeListDataListener(this );
0232: this .dataModel = dataModel;
0233: this .dataModel.addListDataListener(this );
0234: setSelectionModel(createSelectionModel());
0235: }
0236:
0237: /**
0238: * Construct a SList that displays the elements in the specified
0239: * array.
0240: */
0241: public SList(final Object[] listData) {
0242: this (new AbstractListModel() {
0243: public int getSize() {
0244: return listData.length;
0245: }
0246:
0247: public Object getElementAt(int i) {
0248: return listData[i];
0249: }
0250: });
0251: }
0252:
0253: /**
0254: * Construct a SList that displays the elements in the specified
0255: * Vector.
0256: */
0257: public SList(final List listData) {
0258: this (new AbstractListModel() {
0259: public int getSize() {
0260: return listData.size();
0261: }
0262:
0263: public Object getElementAt(int i) {
0264: return listData.get(i);
0265: }
0266: });
0267: }
0268:
0269: /**
0270: * Constructs a SList with an empty model.
0271: */
0272: public SList() {
0273: this (new AbstractListModel() {
0274: public int getSize() {
0275: return 0;
0276: }
0277:
0278: public Object getElementAt(int i) {
0279: return "No Data Model";
0280: }
0281: });
0282: }
0283:
0284: /**
0285: * Returns the cell renderer.
0286: *
0287: * @return the ListCellRenderer
0288: * @see #setCellRenderer
0289: */
0290: public final SListCellRenderer getCellRenderer() {
0291: return cellRenderer;
0292: }
0293:
0294: /**
0295: * Sets the renderer that's used to write out each cell in the list.
0296: *
0297: * @param cellRenderer the SListCellRenderer that paints list cells
0298: * description: The component used to draw the cells.
0299: * @see #getCellRenderer
0300: */
0301: public void setCellRenderer(SListCellRenderer cellRenderer) {
0302: SListCellRenderer oldValue = this .cellRenderer;
0303: this .cellRenderer = cellRenderer;
0304: reloadIfChange(oldValue, cellRenderer);
0305: }
0306:
0307: /**
0308: * Return the background color.
0309: *
0310: * @return the background color
0311: */
0312: public Color getSelectionBackground() {
0313: return dynamicStyles == null
0314: || dynamicStyles.get(SELECTOR_SELECTION) == null ? null
0315: : CSSStyleSheet
0316: .getBackground((CSSAttributeSet) dynamicStyles
0317: .get(SELECTOR_SELECTION));
0318: }
0319:
0320: /**
0321: * Set the foreground color.
0322: *
0323: * @param color the new foreground color
0324: */
0325: public void setSelectionBackground(Color color) {
0326: setAttribute(SELECTOR_SELECTION, CSSProperty.BACKGROUND_COLOR,
0327: CSSStyleSheet.getAttribute(color));
0328: }
0329:
0330: /**
0331: * Return the foreground color.
0332: *
0333: * @return the foreground color
0334: */
0335: public Color getSelectionForeground() {
0336: return dynamicStyles == null
0337: || dynamicStyles.get(SELECTOR_SELECTION) == null ? null
0338: : CSSStyleSheet
0339: .getForeground((CSSAttributeSet) dynamicStyles
0340: .get(SELECTOR_SELECTION));
0341: }
0342:
0343: /**
0344: * Set the foreground color.
0345: *
0346: * @param color the new foreground color
0347: */
0348: public void setSelectionForeground(Color color) {
0349: setAttribute(SELECTOR_SELECTION, CSSProperty.COLOR,
0350: CSSStyleSheet.getAttribute(color));
0351: }
0352:
0353: /**
0354: * Set the font.
0355: *
0356: * @param font the new font
0357: */
0358: public void setSelectionFont(SFont font) {
0359: setAttributes(SELECTOR_SELECTION, CSSStyleSheet
0360: .getAttributes(font));
0361: }
0362:
0363: /**
0364: * Return the font.
0365: *
0366: * @return the font
0367: */
0368: public SFont getSelectionFont() {
0369: return dynamicStyles == null
0370: || dynamicStyles.get(SELECTOR_SELECTION) == null ? null
0371: : CSSStyleSheet.getFont((CSSAttributeSet) dynamicStyles
0372: .get(SELECTOR_SELECTION));
0373: }
0374:
0375: /**
0376: * Return the preferred number of visible rows. If rendered as a form
0377: * component it is used for the size-attribute.
0378: *
0379: * @return the preferred number of rows to display
0380: * @see #setVisibleRowCount
0381: */
0382: public final int getVisibleRowCount() {
0383: return visibleRowCount;
0384: }
0385:
0386: /**
0387: * Set the preferred number of rows in the list that can be displayed
0388: * without a scollbar.
0389: * <p/>
0390: * The default value of this property is 8.
0391: *
0392: * @param visibleRowCount the preferred number of visible rows
0393: * description: The preferred number of cells that can be displayed without a scrollbar.
0394: * @see #getVisibleRowCount
0395: */
0396: public void setVisibleRowCount(int visibleRowCount) {
0397: if (this .visibleRowCount != visibleRowCount) {
0398: this .visibleRowCount = Math.max(0, visibleRowCount);
0399: reload();
0400: //firePropertyChange("visibleRowCount", oldValue, visibleRowCount);
0401: }
0402: }
0403:
0404: /**
0405: * --- ListModel Support ---
0406: */
0407:
0408: /**
0409: * Returns the data model that holds the items.
0410: *
0411: * @return the ListModel
0412: * @see #setModel
0413: */
0414: public ListModel getModel() {
0415: return dataModel;
0416: }
0417:
0418: /**
0419: * Sets the model
0420: *
0421: * @param model the ListModel that provides the list of items
0422: * description: The object that contains the data to be shownin the list.
0423: * @see #getModel
0424: */
0425: public void setModel(ListModel model) {
0426: if (model == null) {
0427: throw new IllegalArgumentException("model must be non null");
0428: }
0429: if (isDifferent(dataModel, model)) {
0430: clearSelection();
0431: dataModel = model;
0432: dataModel.addListDataListener(this );
0433:
0434: fireViewportChanged(false);
0435: reload();
0436: }
0437: }
0438:
0439: /**
0440: * A convenience method that constructs a ListModel from an array of Objects
0441: * and then applies setModel to it.
0442: *
0443: * @param listData an array of Objects containing the items to display
0444: * in the list
0445: * @see #setModel
0446: */
0447: public void setListData(final Object[] listData) {
0448: setModel(new AbstractListModel() {
0449: public int getSize() {
0450: return listData.length;
0451: }
0452:
0453: public Object getElementAt(int i) {
0454: return listData[i];
0455: }
0456: });
0457: }
0458:
0459: /**
0460: * A convenience method that constructs a ListModel from a List
0461: * and then applies setModel to it.
0462: *
0463: * @param listData a Vector containing the items to display in the list
0464: * @see #setModel
0465: */
0466: public void setListData(final List listData) {
0467: setModel(new AbstractListModel() {
0468: public int getSize() {
0469: return listData.size();
0470: }
0471:
0472: public Object getElementAt(int i) {
0473: return listData.get(i);
0474: }
0475: });
0476: }
0477:
0478: /**
0479: * creates the default selection model. It uses the swing
0480: * DefaultListSelectionModel, and wraps some methods to support
0481: * {@link SListSelectionModel#NO_SELECTION}
0482: */
0483: protected SListSelectionModel createSelectionModel() {
0484: return new SDefaultListSelectionModel();
0485: }
0486:
0487: /**
0488: * Returns the current selection model. If selection mode is
0489: * {@link SListSelectionModel#NO_SELECTION} it return <em>null</em>
0490: *
0491: * @return the ListSelectionModel that implements list selections.
0492: * If selection mode is {@link SListSelectionModel#NO_SELECTION} it return
0493: * <em>null</em>
0494: * @see #setSelectionMode(int)
0495: * @see ListSelectionModel
0496: */
0497: public SListSelectionModel getSelectionModel() {
0498: return selectionModel;
0499: }
0500:
0501: /**
0502: * This method notifies all ListSelectionListeners that
0503: * the selection model has changed.
0504: *
0505: * @see #addListSelectionListener
0506: * @see #removeListSelectionListener
0507: * @see EventListenerList
0508: */
0509: protected void fireSelectionValueChanged(int firstIndex,
0510: int lastIndex, boolean isAdjusting) {
0511: Object[] listeners = getListenerList();
0512: ListSelectionEvent e = null;
0513:
0514: for (int i = listeners.length - 2; i >= 0; i -= 2) {
0515: if (listeners[i] == ListSelectionListener.class) {
0516: if (e == null) {
0517: e = new ListSelectionEvent(this , firstIndex,
0518: lastIndex, isAdjusting);
0519: }
0520: ((ListSelectionListener) listeners[i + 1])
0521: .valueChanged(e);
0522: }
0523: }
0524: }
0525:
0526: /**
0527: * Add a listener to the list that's notified each time a change
0528: * to the selection occurs.
0529: *
0530: * <p>
0531: * If you want to receive immedate an event when the user clicks a new item
0532: * on the client side you have to register additionally a Java script listener
0533: * which triggers a form submit. <br>
0534: * <code>combobox.addScriptListener(ListCG.JS_ON_CHANGE_SUBMIT)</code>
0535: *
0536: * @param listener A ListSelectionListener to be added
0537: * @see #getSelectionModel
0538: */
0539: public void addListSelectionListener(ListSelectionListener listener) {
0540: addEventListener(ListSelectionListener.class, listener);
0541: }
0542:
0543: /**
0544: * Remove a listener from the list that's notified each time a
0545: * change to the selection occurs.
0546: *
0547: * @param listener The ListSelectionListener to remove.
0548: * @see #addListSelectionListener
0549: * @see #getSelectionModel
0550: */
0551: public void removeListSelectionListener(
0552: ListSelectionListener listener) {
0553: removeEventListener(ListSelectionListener.class, listener);
0554: }
0555:
0556: /**
0557: * Returns an array of all the <code>ListSelectionListener</code>s added
0558: * to this JList with addListSelectionListener().
0559: *
0560: * @return all of the ListSelectionListener added
0561: * @since 1.4
0562: */
0563: public ListSelectionListener[] getListSelectionListeners() {
0564: return (ListSelectionListener[]) getListeners(ListSelectionListener.class);
0565: }
0566:
0567: /**
0568: * Set the selectionModel for the list.
0569: * The selection model keeps track of which items are selected.
0570: * <p/>
0571: * description: The selection model, recording which cells are selected.
0572: *
0573: * @see #getSelectionModel
0574: */
0575: public void setSelectionModel(SListSelectionModel selectionModel) {
0576: if (selectionModel == null) {
0577: throw new IllegalArgumentException(
0578: "selectionModel must be non null");
0579: }
0580:
0581: if (this .selectionModel != null)
0582: this .selectionModel
0583: .removeListSelectionListener(fwdSelectionEvents);
0584:
0585: selectionModel.addListSelectionListener(fwdSelectionEvents);
0586:
0587: this .selectionModel = selectionModel;
0588: }
0589:
0590: /**
0591: * Allow / permit multiple selection
0592: * <ul>
0593: * <li> <code>SINGLE_SELECTION</code>
0594: * Only one list index can be selected at a time.
0595: * <li> <code>MULTIPLE_INTERVAL_SELECTION</code>
0596: * Multiple items can be selected.
0597: * </ul>
0598: *
0599: * @param selectionMode single or multiple selections
0600: * enum: SINGLE_SELECTION ListSelectionModel.SINGLE_SELECTION
0601: * MULTIPLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
0602: * @see #getSelectionMode
0603: */
0604: public void setSelectionMode(int selectionMode) {
0605: selectionModel.setSelectionMode(selectionMode);
0606: }
0607:
0608: /**
0609: * Returns whether single-item or multiple-item selections are allowed.
0610: *
0611: * @return The value of the selectionMode property.
0612: * @see #setSelectionMode
0613: */
0614: public int getSelectionMode() {
0615: return getSelectionModel().getSelectionMode();
0616: }
0617:
0618: /**
0619: * @return The index that most recently anchored an interval selection.
0620: * @see ListSelectionModel#getAnchorSelectionIndex
0621: * @see #addSelectionInterval
0622: * @see #setSelectionInterval
0623: * @see #addListSelectionListener
0624: */
0625: public int getAnchorSelectionIndex() {
0626: return getSelectionModel().getAnchorSelectionIndex();
0627: }
0628:
0629: /**
0630: * @return The index that most recently ended a interval selection.
0631: * @see ListSelectionModel#getLeadSelectionIndex
0632: * @see #addSelectionInterval
0633: * @see #setSelectionInterval
0634: * @see #addListSelectionListener
0635: */
0636: public int getLeadSelectionIndex() {
0637: return getSelectionModel().getLeadSelectionIndex();
0638: }
0639:
0640: /**
0641: * @return The smallest selected cell index.
0642: * @see ListSelectionModel#getMinSelectionIndex
0643: * @see #addListSelectionListener
0644: */
0645: public int getMinSelectionIndex() {
0646: return getSelectionModel().getMinSelectionIndex();
0647: }
0648:
0649: /**
0650: * @return The largest selected cell index.
0651: * @see ListSelectionModel#getMaxSelectionIndex
0652: * @see #addListSelectionListener
0653: */
0654: public int getMaxSelectionIndex() {
0655: return getSelectionModel().getMaxSelectionIndex();
0656: }
0657:
0658: /**
0659: * @return True if the specified index is selected.
0660: * @see ListSelectionModel#isSelectedIndex
0661: * @see #setSelectedIndex
0662: * @see #addListSelectionListener
0663: */
0664: public boolean isSelectedIndex(int index) {
0665: return getSelectionModel().isSelectedIndex(index);
0666: }
0667:
0668: /**
0669: * @return True if nothing is selected
0670: * @see ListSelectionModel#isSelectionEmpty
0671: * @see #clearSelection
0672: * @see #addListSelectionListener
0673: */
0674: public boolean isSelectionEmpty() {
0675: return getSelectionModel().isSelectionEmpty();
0676: }
0677:
0678: /**
0679: * @see ListSelectionModel#clearSelection
0680: * @see #isSelectionEmpty
0681: * @see #addListSelectionListener
0682: */
0683: public void clearSelection() {
0684: if (!getSelectionModel().isSelectionEmpty()) {
0685: getSelectionModel().clearSelection();
0686: reload();
0687: }
0688: }
0689:
0690: /**
0691: * @param anchor The first index to select
0692: * @param lead The last index to select
0693: * @see ListSelectionModel#setSelectionInterval
0694: * @see #addSelectionInterval
0695: * @see #removeSelectionInterval
0696: * @see #addListSelectionListener
0697: */
0698: public void setSelectionInterval(int anchor, int lead) {
0699: getSelectionModel().setSelectionInterval(anchor, lead);
0700: }
0701:
0702: /**
0703: * @param anchor The first index to add to the selection
0704: * @param lead The last index to add to the selection
0705: * @see ListSelectionModel#addSelectionInterval
0706: * @see #setSelectionInterval
0707: * @see #removeSelectionInterval
0708: * @see #addListSelectionListener
0709: */
0710: public void addSelectionInterval(int anchor, int lead) {
0711: getSelectionModel().addSelectionInterval(anchor, lead);
0712: }
0713:
0714: /**
0715: * @param index0 The first index to remove from the selection
0716: * @param index1 The last index to remove from the selection
0717: * @see ListSelectionModel#removeSelectionInterval
0718: * @see #setSelectionInterval
0719: * @see #addSelectionInterval
0720: * @see #addListSelectionListener
0721: */
0722: public void removeSelectionInterval(int index0, int index1) {
0723: getSelectionModel().removeSelectionInterval(index0, index1);
0724: }
0725:
0726: /**
0727: * @param b the value for valueIsAdjusting
0728: * @see ListSelectionModel#setValueIsAdjusting
0729: */
0730: public void setValueIsAdjusting(boolean b) {
0731: getSelectionModel().setValueIsAdjusting(b);
0732: }
0733:
0734: /**
0735: * @return the value of valueIsAdjusting
0736: * @see ListSelectionModel#getValueIsAdjusting
0737: */
0738: public boolean getValueIsAdjusting() {
0739: return getSelectionModel().getValueIsAdjusting();
0740: }
0741:
0742: /**
0743: * Return an array of all of the selected indices.
0744: *
0745: * @return all selected indices.
0746: * @see #removeSelectionInterval
0747: * @see #addListSelectionListener
0748: */
0749: public int[] getSelectedIndices() {
0750: ListSelectionModel sm = getSelectionModel();
0751: int iMin = sm.getMinSelectionIndex();
0752: int iMax = sm.getMaxSelectionIndex();
0753:
0754: if ((iMin < 0) || (iMax < 0)) {
0755: return new int[0];
0756: }
0757:
0758: int[] rvTmp = new int[1 + (iMax - iMin)];
0759: int n = 0;
0760: for (int i = iMin; i <= iMax; i++) {
0761: if (sm.isSelectedIndex(i)) {
0762: rvTmp[n++] = i;
0763: }
0764: }
0765: int[] rv = new int[n];
0766: System.arraycopy(rvTmp, 0, rv, 0, n);
0767: return rv;
0768: }
0769:
0770: /**
0771: * Select a single cell.
0772: *
0773: * @param index The index of the one cell to select
0774: * @see ListSelectionModel#setSelectionInterval
0775: * @see #isSelectedIndex
0776: * @see #addListSelectionListener
0777: */
0778: public void setSelectedIndex(int index) {
0779: getSelectionModel().setSelectionInterval(index, index);
0780: }
0781:
0782: /**
0783: * Select some cells.
0784: *
0785: * @param indices The indices of the cells to select
0786: * @see ListSelectionModel#addSelectionInterval
0787: * @see #isSelectedIndex
0788: * @see #addListSelectionListener
0789: */
0790: public void setSelectedIndices(int[] indices) {
0791: ListSelectionModel sm = getSelectionModel();
0792: sm.clearSelection();
0793: for (int i = 0; i < indices.length; i++) {
0794: sm.addSelectionInterval(indices[i], indices[i]);
0795: }
0796: }
0797:
0798: /**
0799: * Return the values of the selected cells.
0800: * Returns only the selected elements which are in the model.
0801: * If the selection model indices a selection outside the the datamodel it is ignored
0802: *
0803: * @return the selected values
0804: * @see #isSelectedIndex
0805: * @see #getModel
0806: * @see #addListSelectionListener
0807: */
0808: public Object[] getSelectedValues() {
0809: ListSelectionModel sm = getSelectionModel();
0810: ListModel dm = getModel();
0811:
0812: int iMin = sm.getMinSelectionIndex();
0813: int iMax = sm.getMaxSelectionIndex();
0814:
0815: if ((iMin < 0) || (iMax < 0)) {
0816: return new Object[0];
0817: }
0818:
0819: Object[] rvTmp = new Object[1 + (iMax - iMin)];
0820: int n = 0;
0821: for (int i = iMin; i <= iMax; i++) {
0822: if (sm.isSelectedIndex(i) && i < dm.getSize()) {
0823: rvTmp[n++] = dm.getElementAt(i);
0824: }
0825: }
0826: Object[] rv = new Object[n];
0827: System.arraycopy(rvTmp, 0, rv, 0, n);
0828: return rv;
0829: }
0830:
0831: /**
0832: * A convenience method that returns the first selected index.
0833: *
0834: * @return The first selected index.
0835: * @see #getMinSelectionIndex
0836: * @see #addListSelectionListener
0837: */
0838: public int getSelectedIndex() {
0839: return getMinSelectionIndex();
0840: }
0841:
0842: /**
0843: * A convenience method that returns the first selected value
0844: * or null, if nothing is selected.
0845: *
0846: * @return The first selected value.
0847: * @see #getMinSelectionIndex
0848: * @see #getModel
0849: * @see #addListSelectionListener
0850: */
0851: public Object getSelectedValue() {
0852: int i = getMinSelectionIndex();
0853: return (i == -1) ? null : getModel().getElementAt(i);
0854: }
0855:
0856: /**
0857: * Selects the specified object.
0858: *
0859: * @param anObject the Object to be selected
0860: */
0861: public void setSelectedValue(Object anObject) {
0862: if (anObject == null)
0863: setSelectedIndex(-1);
0864: else if (!anObject.equals(getSelectedValue())) {
0865: int i, c;
0866: ListModel dm = getModel();
0867: for (i = 0, c = dm.getSize(); i < c; i++)
0868: if (anObject.equals(dm.getElementAt(i))) {
0869: setSelectedIndex(i);
0870: return;
0871: }
0872: setSelectedIndex(-1);
0873: }
0874: }
0875:
0876: /*
0877: * Sets the list type. Use one of the following types:
0878: * <UL>
0879: * <LI>{@link SConstants#ORDERED_LIST}
0880: * <LI>{@link SConstants#UNORDERED_LIST}
0881: * <LI>{@link SConstants#MENU_LIST}
0882: * <LI>{@link SConstants#DIR_LIST}
0883: * </UL>
0884: * null sets default list.
0885: *
0886: * @param t the type
0887: */
0888: public void setType(String t) {
0889: if (t != null)
0890: type = t;
0891: else
0892: type = UNORDERED_LIST;
0893: }
0894:
0895: /**
0896: * Return the type.
0897: *
0898: * @return the type;
0899: */
0900: public String getType() {
0901: return type;
0902: }
0903:
0904: /**
0905: * <li type="...">
0906: */
0907: public void setOrderType(String t) {
0908: orderType = t;
0909: }
0910:
0911: /**
0912: * <li type="...">
0913: */
0914: public String getOrderType() {
0915: return orderType;
0916: }
0917:
0918: /*
0919: * <li type="...">
0920: * <code>null</code> is default style.
0921: */
0922: public void setType(String[] t) {
0923: if (t == null) {
0924: setType((String) null);
0925: setOrderType(null);
0926: } else if (t.length == 2) {
0927: setType(t[0]);
0928: setOrderType(t[1]);
0929: }
0930: }
0931:
0932: /**
0933: * <li start="...">
0934: */
0935: public void setStart(int s) {
0936: start = s;
0937: }
0938:
0939: /**
0940: * <li start="...">
0941: */
0942: public int getStart() {
0943: return start;
0944: }
0945:
0946: public void fireIntermediateEvents() {
0947: getSelectionModel().fireDelayedIntermediateEvents();
0948: }
0949:
0950: public void fireFinalEvents() {
0951: super .fireFinalEvents();
0952: // fire selection events...
0953: getSelectionModel().fireDelayedFinalEvents();
0954: }
0955:
0956: /**
0957: * @see LowLevelEventListener#isEpochCheckEnabled()
0958: */
0959: public boolean isEpochCheckEnabled() {
0960: return epochCheckEnabled;
0961: }
0962:
0963: /**
0964: * @see LowLevelEventListener#isEpochCheckEnabled()
0965: */
0966: public void setEpochCheckEnabled(boolean epochCheckEnabled) {
0967: this .epochCheckEnabled = epochCheckEnabled;
0968: }
0969:
0970: /*
0971: * Implement {@link LowLevelEventListener} interface.
0972: * @param action the name
0973: * @param value the value
0974: */
0975: public void processLowLevelEvent(String action, String[] values) {
0976: processKeyEvents(values);
0977: if (action.endsWith("_keystroke"))
0978: return;
0979:
0980: // delay events...
0981: getSelectionModel().setDelayEvents(true);
0982: getSelectionModel().setValueIsAdjusting(true);
0983:
0984: // in a form, we only get events for selected items, so for every
0985: // selected item, which is not in values, deselect it...
0986: if (getShowAsFormComponent()) {
0987:
0988: ArrayList selectedIndices = new ArrayList();
0989: for (int i = 0; i < values.length; i++) {
0990:
0991: String indexString = values[i];
0992: if (indexString.length() < 1)
0993: continue; // false format
0994:
0995: try {
0996: int index = Integer.parseInt(indexString);
0997:
0998: // in a form all parameters are select parameters...
0999: selectedIndices.add(new Integer(index));
1000: addSelectionInterval(index, index);
1001: } catch (Exception ex) {
1002: }
1003: }
1004: // remove all selected indices, which are not explicitely selected by a parameter
1005: for (int i = 0; i < getModel().getSize(); ++i) {
1006: if (isSelectedIndex(i)
1007: && !selectedIndices.contains(new Integer(i))) {
1008: removeSelectionInterval(i, i);
1009: }
1010: }
1011: } else {
1012: for (int i = 0; i < values.length; i++) {
1013:
1014: String indexString = values[i];
1015: if (indexString.length() < 1)
1016: continue; // false format
1017:
1018: try {
1019: int index = Integer.parseInt(indexString);
1020:
1021: // toggle selection for given index
1022: if (isSelectedIndex(index))
1023: removeSelectionInterval(index, index);
1024: else
1025: addSelectionInterval(index, index);
1026: } catch (Exception ex) {
1027: }
1028:
1029: }
1030: }
1031: getSelectionModel().setValueIsAdjusting(false);
1032: getSelectionModel().setDelayEvents(false);
1033:
1034: SForm.addArmedComponent(this );
1035: }
1036:
1037: /**
1038: * The size of the component in respect to scrollable units.
1039: */
1040: public Rectangle getScrollableViewportSize() {
1041: return new Rectangle(0, 0, 1, dataModel.getSize());
1042: }
1043:
1044: /**
1045: * Returns the actual visible part of a scrollable.
1046: */
1047: public Rectangle getViewportSize() {
1048: return viewport;
1049: }
1050:
1051: /**
1052: * Sets the actual visible part of a scrollable.
1053: */
1054: public void setViewportSize(Rectangle newViewport) {
1055: Rectangle oldViewport = viewport;
1056: viewport = newViewport;
1057:
1058: if (isDifferent(oldViewport, newViewport)) {
1059: if (oldViewport == null || newViewport == null) {
1060: fireViewportChanged(true);
1061: fireViewportChanged(false);
1062: } else {
1063: if (newViewport.x != oldViewport.x
1064: || newViewport.width != oldViewport.width) {
1065: fireViewportChanged(true);
1066: }
1067: if (newViewport.y != oldViewport.y
1068: || newViewport.height != oldViewport.height) {
1069: fireViewportChanged(false);
1070: }
1071: }
1072: reload();
1073: }
1074: }
1075:
1076: /**
1077: * Adds the given <code>SViewportChangeListener</code> to the scrollable.
1078: *
1079: * @param l the listener to be added
1080: */
1081: public void addViewportChangeListener(SViewportChangeListener l) {
1082: addEventListener(SViewportChangeListener.class, l);
1083: }
1084:
1085: /**
1086: * Removes the given <code>SViewportChangeListener</code> from the scrollable.
1087: *
1088: * @param l the listener to be removed
1089: */
1090: public void removeViewportChangeListener(SViewportChangeListener l) {
1091: removeEventListener(SViewportChangeListener.class, l);
1092: }
1093:
1094: /**
1095: * Notifies all listeners that have registered interest for notification
1096: * on changes to this scrollable's viewport in the specified direction.
1097: *
1098: * @see EventListenerList
1099: */
1100: protected void fireViewportChanged(boolean horizontal) {
1101: Object[] listeners = getListenerList();
1102: for (int i = listeners.length - 2; i >= 0; i -= 2) {
1103: if (listeners[i] == SViewportChangeListener.class) {
1104: SViewportChangeEvent event = new SViewportChangeEvent(
1105: this , horizontal);
1106: ((SViewportChangeListener) listeners[i + 1])
1107: .viewportChanged(event);
1108: }
1109: }
1110: }
1111:
1112: public void setParent(SContainer p) {
1113: super .setParent(p);
1114: if (getCellRendererPane() != null)
1115: getCellRendererPane().setParent(p);
1116: }
1117:
1118: protected void setParentFrame(SFrame f) {
1119: super .setParentFrame(f);
1120: if (getCellRendererPane() != null)
1121: getCellRendererPane().setParentFrame(f);
1122: }
1123:
1124: // do not initalize with null!
1125: private SCellRendererPane cellRendererPane = new SCellRendererPane();
1126:
1127: public SCellRendererPane getCellRendererPane() {
1128: return cellRendererPane;
1129: }
1130:
1131: public void removeCellRendererPane() {
1132: cellRendererPane.setParent(null);
1133: cellRendererPane = null;
1134: }
1135:
1136: public void setCG(ListCG cg) {
1137: super .setCG(cg);
1138: }
1139:
1140: public String getToggleSelectionParameter(int index) {
1141: return isSelectedIndex(index) ? getDeselectionParameter(index)
1142: : getSelectionParameter(index);
1143: }
1144:
1145: public String getSelectionParameter(int index) {
1146: return Integer.toString(index);
1147: }
1148:
1149: public String getDeselectionParameter(int index) {
1150: return Integer.toString(index);
1151: }
1152:
1153: // Changes to the model should force a reload.
1154: public void contentsChanged(javax.swing.event.ListDataEvent e) {
1155: fireViewportChanged(false);
1156: reload();
1157: }
1158:
1159: public void intervalAdded(javax.swing.event.ListDataEvent e) {
1160: fireViewportChanged(false);
1161: reload();
1162: }
1163:
1164: public void intervalRemoved(javax.swing.event.ListDataEvent e) {
1165: fireViewportChanged(false);
1166: reload();
1167: }
1168: }
|