0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package java.awt;
0019:
0020: import java.awt.event.ActionEvent;
0021: import java.awt.event.ActionListener;
0022: import java.awt.event.FocusEvent;
0023: import java.awt.event.FocusListener;
0024: import java.awt.event.ItemEvent;
0025: import java.awt.event.ItemListener;
0026: import java.awt.event.KeyEvent;
0027: import java.awt.event.KeyListener;
0028: import java.awt.event.MouseEvent;
0029: import java.awt.event.MouseListener;
0030: import java.awt.event.MouseMotionListener;
0031: import java.awt.font.FontRenderContext;
0032: import java.util.EventListener;
0033: import java.util.Iterator;
0034: import java.util.ArrayList;
0035: import java.util.Locale;
0036: import javax.accessibility.Accessible;
0037: import javax.accessibility.AccessibleContext;
0038: import javax.accessibility.AccessibleRole;
0039: import javax.accessibility.AccessibleSelection;
0040: import javax.accessibility.AccessibleState;
0041: import javax.accessibility.AccessibleStateSet;
0042: import org.apache.harmony.awt.ScrollStateController;
0043: import org.apache.harmony.awt.Scrollable;
0044: import org.apache.harmony.awt.internal.nls.Messages;
0045: import org.apache.harmony.awt.state.ListState;
0046:
0047: public class List extends Component implements ItemSelectable,
0048: Accessible {
0049: private static final long serialVersionUID = -3304312411574666869L;
0050:
0051: private final static int BORDER_SIZE = 2;
0052:
0053: private final static Font DEFAULT_FONT = new Font(
0054: "dialog", Font.PLAIN, 12); //$NON-NLS-1$
0055:
0056: private final AWTListenerList<ActionListener> actionListeners = new AWTListenerList<ActionListener>(
0057: this );
0058:
0059: private final AWTListenerList<ItemListener> itemListeners = new AWTListenerList<ItemListener>(
0060: this );
0061:
0062: private int rows;
0063:
0064: private boolean multipleMode;
0065:
0066: private final ArrayList<String> items = new ArrayList<String>();
0067:
0068: private final ArrayList<Integer> selection = new ArrayList<Integer>();
0069:
0070: private int visibleIndex = -1;
0071:
0072: private int currentIndex; // "focused" item index
0073:
0074: private final ListStateController stateController;
0075:
0076: private final ListScrollable scrollable;
0077:
0078: private final State state;
0079:
0080: private final ScrollPaneAdjustable hAdjustable;
0081:
0082: private final ScrollPaneAdjustable vAdjustable;
0083:
0084: private transient Point scrollLocation;
0085:
0086: private transient int prefWidth;
0087:
0088: protected class AccessibleAWTList extends AccessibleAWTComponent
0089: implements AccessibleSelection, ItemListener,
0090: ActionListener {
0091: private static final long serialVersionUID = 7924617370136012829L;
0092:
0093: protected class AccessibleAWTListChild extends
0094: AccessibleAWTComponent implements Accessible {
0095: private static final long serialVersionUID = 4412022926028300317L;
0096:
0097: private final int accessibleIndexInParent;
0098:
0099: private List parent;
0100:
0101: public AccessibleAWTListChild(List parent, int indexInParent) {
0102: accessibleIndexInParent = indexInParent;
0103: this .parent = parent;
0104: setAccessibleParent(parent);
0105: }
0106:
0107: public AccessibleContext getAccessibleContext() {
0108: return this ;
0109: }
0110:
0111: @Override
0112: public void addFocusListener(FocusListener l) {
0113: // do nothing
0114: }
0115:
0116: @Override
0117: public boolean contains(Point p) {
0118: return false;
0119: }
0120:
0121: @Override
0122: public Accessible getAccessibleAt(Point p) {
0123: return null;
0124: }
0125:
0126: @Override
0127: public Accessible getAccessibleChild(int i) {
0128: return null;
0129: }
0130:
0131: @Override
0132: public int getAccessibleChildrenCount() {
0133: return 0;
0134: }
0135:
0136: @Override
0137: public int getAccessibleIndexInParent() {
0138: return accessibleIndexInParent;
0139: }
0140:
0141: @Override
0142: public AccessibleRole getAccessibleRole() {
0143: return AccessibleRole.LIST_ITEM;
0144: }
0145:
0146: @Override
0147: public AccessibleStateSet getAccessibleStateSet() {
0148: AccessibleStateSet aStateSet = super
0149: .getAccessibleStateSet();
0150: if (isAccessibleChildSelected(accessibleIndexInParent)) {
0151: aStateSet.add(AccessibleState.SELECTED);
0152: }
0153: return aStateSet;
0154: }
0155:
0156: @Override
0157: public Color getBackground() {
0158: return parent.getBackground();
0159: }
0160:
0161: @Override
0162: public Rectangle getBounds() {
0163: // return null
0164: return null;
0165: }
0166:
0167: @Override
0168: public Cursor getCursor() {
0169: return parent.getCursor();
0170: }
0171:
0172: @Override
0173: public Font getFont() {
0174: return parent.getFont();
0175: }
0176:
0177: @Override
0178: public FontMetrics getFontMetrics(Font f) {
0179: return parent.getFontMetrics(f);
0180: }
0181:
0182: @Override
0183: public Color getForeground() {
0184: return parent.getForeground();
0185: }
0186:
0187: @Override
0188: public Locale getLocale()
0189: throws IllegalComponentStateException {
0190: return parent.getLocale();
0191: }
0192:
0193: @Override
0194: public Point getLocation() {
0195: // just return null
0196: return null;
0197: }
0198:
0199: @Override
0200: public Point getLocationOnScreen() {
0201: // just return null
0202: return null;
0203: }
0204:
0205: @Override
0206: public Dimension getSize() {
0207: // just return null
0208: return null;
0209: }
0210:
0211: @Override
0212: public boolean isEnabled() {
0213: return parent.isEnabled();
0214: }
0215:
0216: @Override
0217: public boolean isFocusTraversable() {
0218: return false;
0219: }
0220:
0221: @Override
0222: public boolean isShowing() {
0223: // always invisible
0224: return false;
0225: }
0226:
0227: @Override
0228: public boolean isVisible() {
0229: // always invisible
0230: return false;
0231: }
0232:
0233: @Override
0234: public void removeFocusListener(FocusListener l) {
0235: // do nothing
0236: }
0237:
0238: @Override
0239: public void requestFocus() {
0240: // do nothing
0241: }
0242:
0243: @Override
0244: public void setBackground(Color color) {
0245: parent.setBackground(color);
0246: }
0247:
0248: @Override
0249: public void setBounds(Rectangle r) {
0250: // do nothing
0251: }
0252:
0253: @Override
0254: public void setCursor(Cursor cursor) {
0255: parent.setCursor(cursor);
0256: }
0257:
0258: @Override
0259: public void setEnabled(boolean enabled) {
0260: parent.setEnabled(enabled);
0261: }
0262:
0263: @Override
0264: public void setFont(Font f) {
0265: parent.setFont(f);
0266: }
0267:
0268: @Override
0269: public void setForeground(Color color) {
0270: parent.setForeground(color);
0271: }
0272:
0273: @Override
0274: public void setLocation(Point p) {
0275: // do nothing
0276: }
0277:
0278: @Override
0279: public void setSize(Dimension size) {
0280: // do nothing
0281: }
0282:
0283: @Override
0284: public void setVisible(boolean visible) {
0285: parent.setVisible(visible);
0286: }
0287: }
0288:
0289: public AccessibleAWTList() {
0290: addActionListener(this );
0291: addItemListener(this );
0292: }
0293:
0294: public int getAccessibleSelectionCount() {
0295: return getSelectedIndexes().length;
0296: }
0297:
0298: public void clearAccessibleSelection() {
0299: toolkit.lockAWT();
0300: try {
0301: int[] selection = getSelectedIndexes();
0302: int count = selection.length;
0303: for (int i = 0; i < count; i++) {
0304: deselect(selection[i]);
0305: }
0306: } finally {
0307: toolkit.unlockAWT();
0308: }
0309: }
0310:
0311: public void selectAllAccessibleSelection() {
0312: toolkit.lockAWT();
0313: try {
0314: int count = getItemCount();
0315: if (!isMultipleMode()) {
0316: count = Math.min(1, count);
0317: }
0318: for (int i = 0; i < count; i++) {
0319: select(i);
0320: }
0321: } finally {
0322: toolkit.unlockAWT();
0323: }
0324: }
0325:
0326: public void addAccessibleSelection(int i) {
0327: select(i);
0328: }
0329:
0330: public void removeAccessibleSelection(int i) {
0331: deselect(i);
0332: }
0333:
0334: public boolean isAccessibleChildSelected(int i) {
0335: return isIndexSelected(i);
0336: }
0337:
0338: public Accessible getAccessibleSelection(int i) {
0339: toolkit.lockAWT();
0340: try {
0341: int[] selection = getSelectedIndexes();
0342: if ((i < 0) || (i >= selection.length)) {
0343: return null;
0344: }
0345: return new AccessibleAWTListChild(List.this ,
0346: selection[i]);
0347: } finally {
0348: toolkit.unlockAWT();
0349: }
0350: }
0351:
0352: @Override
0353: public AccessibleSelection getAccessibleSelection() {
0354: return this ;
0355: }
0356:
0357: public void itemStateChanged(ItemEvent e) {
0358: // TODO: find out why listen to ItemEvents
0359: }
0360:
0361: public void actionPerformed(ActionEvent e) {
0362: // TODO: find out why listen to ActionEvents
0363: }
0364:
0365: @Override
0366: public Accessible getAccessibleAt(Point p) {
0367: // no specific implementation yet
0368: return super .getAccessibleAt(p);
0369: }
0370:
0371: @Override
0372: public Accessible getAccessibleChild(int i) {
0373: toolkit.lockAWT();
0374: try {
0375: int idx = Math.max(0, i);
0376: if (!isIdxValid(idx)) {
0377: return null;
0378: }
0379: return new AccessibleAWTListChild(List.this , idx);
0380: } finally {
0381: toolkit.unlockAWT();
0382: }
0383: }
0384:
0385: @Override
0386: public int getAccessibleChildrenCount() {
0387: return getItemCount();
0388: }
0389:
0390: @Override
0391: public AccessibleRole getAccessibleRole() {
0392: return AccessibleRole.LIST;
0393: }
0394:
0395: @Override
0396: public AccessibleStateSet getAccessibleStateSet() {
0397: toolkit.lockAWT();
0398: try {
0399: AccessibleStateSet aStateSet = super
0400: .getAccessibleStateSet();
0401: if (isMultipleMode()) {
0402: aStateSet.add(AccessibleState.MULTISELECTABLE);
0403: }
0404: return aStateSet;
0405: } finally {
0406: toolkit.unlockAWT();
0407: }
0408: }
0409: }
0410:
0411: class ListStateController extends ScrollStateController implements
0412: MouseListener, KeyListener, FocusListener,
0413: MouseMotionListener {
0414: boolean scrollPressed;
0415:
0416: public ListStateController(Scrollable scrollable) {
0417: super (scrollable);
0418: }
0419:
0420: public void mouseClicked(MouseEvent e) {
0421: if (getClient().contains(e.getPoint())
0422: && e.getClickCount() == 2) {
0423: fireActionEvent(e.getWhen(), e.getModifiers());
0424: }
0425: }
0426:
0427: public void mouseEntered(MouseEvent e) {
0428: // nothing to do
0429: }
0430:
0431: public void mouseExited(MouseEvent e) {
0432: // nothing to do
0433: }
0434:
0435: public void mousePressed(MouseEvent e) {
0436: if (e.getButton() != MouseEvent.BUTTON1) {
0437: return;
0438: }
0439: Point pt = e.getPoint();
0440: if (getClient().contains(pt)) {
0441: if (e.getClickCount() > 1) {
0442: // don't select/deselect on
0443: // double-click
0444: return;
0445: }
0446: int idx = getItemIndex(e.getY());
0447: if (checkIdx(idx)) {
0448: requestFocus();
0449: boolean selected = isIndexSelected(idx);
0450: int sel = selected ? ItemEvent.DESELECTED
0451: : ItemEvent.SELECTED;
0452: if (!selected) {
0453: select(idx);
0454: } else {
0455: deselect(idx);
0456: }
0457: fireItemEvent(sel);
0458: }
0459: } else if (vAdjustable.getBounds().contains(pt)
0460: || hAdjustable.getBounds().contains(pt)) {
0461: scrollPressed = true;
0462: }
0463: }
0464:
0465: public void mouseReleased(MouseEvent e) {
0466: scrollPressed = false;
0467: }
0468:
0469: public void keyPressed(KeyEvent e) {
0470: // awt.72=Key event for unfocused component
0471: assert isFocusOwner() : Messages.getString("awt.72"); //$NON-NLS-1$
0472: int keyCode = e.getKeyCode();
0473: switch (keyCode) {
0474: case KeyEvent.VK_UP:
0475: scrollByUnit(vAdjustable, -1);
0476: break;
0477: case KeyEvent.VK_LEFT:
0478: scrollByUnit(hAdjustable, -1);
0479: break;
0480: case KeyEvent.VK_DOWN:
0481: scrollByUnit(vAdjustable, 1);
0482: break;
0483: case KeyEvent.VK_RIGHT:
0484: scrollByUnit(hAdjustable, 1);
0485: break;
0486: case KeyEvent.VK_PAGE_UP:
0487: scrollByBlock(-1);
0488: break;
0489: case KeyEvent.VK_PAGE_DOWN:
0490: scrollByBlock(1);
0491: break;
0492: case KeyEvent.VK_HOME:
0493: selectVisible(0);
0494: break;
0495: case KeyEvent.VK_END:
0496: int lastIdx = getItemCount() - 1;
0497: selectVisible(lastIdx);
0498: break;
0499: case KeyEvent.VK_ENTER:
0500: fireActionEvent(e.getWhen(), e.getModifiers());
0501: break;
0502: case KeyEvent.VK_SPACE:
0503: if (isMultipleMode()) {
0504: boolean deselect = isIndexSelected(currentIndex);
0505: if (deselect) {
0506: deselect(currentIndex);
0507: } else {
0508: select(currentIndex);
0509: }
0510: fireItemEvent(deselect ? ItemEvent.DESELECTED
0511: : ItemEvent.SELECTED);
0512: }
0513: break;
0514: }
0515: }
0516:
0517: private void selectVisible(int idx) {
0518: int count = getItemCount();
0519: if (count <= 0) {
0520: return;
0521: }
0522: idx = Math.max(0, Math.min(count - 1, idx));
0523: makeVisible(idx);
0524: if (!isMultipleMode()) {
0525: select(idx);
0526: fireItemEvent(ItemEvent.SELECTED);
0527: }
0528: }
0529:
0530: private void scrollByBlock(int val) {
0531: int itemsPerBlock = getClient().height
0532: / getItemSize().height;
0533: scrollByUnit(vAdjustable, val * itemsPerBlock);
0534: }
0535:
0536: private void scrollByUnit(Adjustable adj, int val) {
0537: if (adj == vAdjustable) {
0538: int visIdx = getCurrentIndex() + val;
0539: selectVisible(visIdx);
0540: } else if (adj == hAdjustable) {
0541: updateAdjValue(adj, val * adj.getUnitIncrement());
0542: }
0543: }
0544:
0545: private void updateAdjValue(Adjustable adj, final int increment) {
0546: int oldVal = adj.getValue();
0547: adj.setValue(oldVal + increment);
0548: }
0549:
0550: public void keyReleased(KeyEvent e) {
0551: // nothing to do
0552: }
0553:
0554: public void keyTyped(KeyEvent e) {
0555: // nothing to do
0556: }
0557:
0558: public void fireActionEvent(long when, int mod) {
0559: if (!checkIdx(currentIndex)) {
0560: return;
0561: }
0562: postEvent(new ActionEvent(List.this ,
0563: ActionEvent.ACTION_PERFORMED,
0564: getItem(currentIndex), when, mod));
0565: }
0566:
0567: public void fireItemEvent(int sel) {
0568: postEvent(new ItemEvent(List.this ,
0569: ItemEvent.ITEM_STATE_CHANGED,
0570: getItem(currentIndex), sel));
0571: }
0572:
0573: public void focusGained(FocusEvent e) {
0574: doRepaint(getMinRect(currentIndex, currentIndex));
0575: }
0576:
0577: public void focusLost(FocusEvent e) {
0578: doRepaint(getMinRect(currentIndex, currentIndex));
0579: }
0580:
0581: public void mouseDragged(MouseEvent e) {
0582: if (scrollPressed) {
0583: return;
0584: }
0585: int y = e.getY();
0586: int idx = getItemIndex(y);
0587: if (checkIdx(idx)) {
0588: selectVisible(idx);
0589: }
0590: }
0591:
0592: private boolean checkIdx(int idx) {
0593: return (idx >= 0) && (idx < getItemCount());
0594: }
0595:
0596: public void mouseMoved(MouseEvent e) {
0597: // nothing to do
0598: }
0599: }
0600:
0601: class ListScrollable implements Scrollable {
0602: public Adjustable getVAdjustable() {
0603: return vAdjustable;
0604: }
0605:
0606: public Adjustable getHAdjustable() {
0607: return hAdjustable;
0608: }
0609:
0610: public Insets getInsets() {
0611: return List.this .getInsets();
0612: }
0613:
0614: public Point getLocation() {
0615: return new Point(scrollLocation);
0616: }
0617:
0618: public void setLocation(Point p) {
0619: if (scrollLocation == null) {
0620: scrollLocation = new Point();
0621: }
0622: scrollLocation.setLocation(p);
0623: }
0624:
0625: public Component getComponent() {
0626: return List.this ;
0627: }
0628:
0629: public void doRepaint() {
0630: List.this .doRepaint();
0631: }
0632:
0633: public int getAdjustableWidth() {
0634: return vAdjustable.getBounds().width;
0635: }
0636:
0637: public int getAdjustableHeight() {
0638: return hAdjustable.getBounds().height;
0639: }
0640:
0641: public void setAdjustableSizes(Adjustable adj, int vis,
0642: int min, int max) {
0643: ((ScrollPaneAdjustable) adj).setSizes(vis, min, max);
0644: }
0645:
0646: public int getAdjustableMode(Adjustable adj) {
0647: return AS_NEEDED;
0648: }
0649:
0650: public void setAdjustableBounds(Adjustable adj, Rectangle r) {
0651: ((ScrollPaneAdjustable) adj).setBounds(r);
0652: }
0653:
0654: public Dimension getSize() {
0655: Dimension prefSize = getPreferredSize(getItemCount());
0656: // don't include borders:
0657: // (return pure content size)
0658: prefSize.width -= 2 * BORDER_SIZE;
0659: prefSize.height -= 2 * BORDER_SIZE;
0660: return prefSize;
0661: }
0662:
0663: public int getWidth() {
0664: return List.this .getWidth();
0665: }
0666:
0667: public int getHeight() {
0668: return List.this .getHeight();
0669: }
0670:
0671: public void doRepaint(Rectangle r) {
0672: List.this .doRepaint(r);
0673: }
0674: }
0675:
0676: class State extends ComponentState implements ListState {
0677: public Rectangle getItemBounds(int idx) {
0678: return List.this .getItemBounds(idx);
0679: }
0680:
0681: public Rectangle getClient() {
0682: return List.this .getClient();
0683: }
0684:
0685: public int getItemCount() {
0686: return List.this .getItemCount();
0687: }
0688:
0689: public boolean isSelected(int idx) {
0690: return List.this .isSelected(idx);
0691: }
0692:
0693: public String getItem(int idx) {
0694: return List.this .getItem(idx);
0695: }
0696:
0697: public int getCurrentIndex() {
0698: return List.this .getCurrentIndex();
0699: }
0700: }
0701:
0702: public List(int rows) throws HeadlessException {
0703: this (rows, false);
0704: toolkit.lockAWT();
0705: try {
0706: } finally {
0707: toolkit.unlockAWT();
0708: }
0709: }
0710:
0711: public List() throws HeadlessException {
0712: this (0, false);
0713: toolkit.lockAWT();
0714: try {
0715: } finally {
0716: toolkit.unlockAWT();
0717: }
0718: }
0719:
0720: public List(int rows, boolean multipleMode)
0721: throws HeadlessException {
0722: toolkit.lockAWT();
0723: try {
0724: Toolkit.checkHeadless();
0725: this .rows = ((rows != 0) ? rows : 4);
0726: this .multipleMode = multipleMode;
0727: scrollLocation = new Point();
0728: hAdjustable = new ScrollPaneAdjustable(this ,
0729: Adjustable.HORIZONTAL);
0730: vAdjustable = new ScrollPaneAdjustable(this ,
0731: Adjustable.VERTICAL);
0732: scrollable = new ListScrollable();
0733: stateController = new ListStateController(scrollable);
0734: state = new State();
0735: addAWTMouseListener(stateController);
0736: addAWTMouseMotionListener(stateController);
0737: addAWTKeyListener(stateController);
0738: addAWTFocusListener(stateController);
0739: addAWTComponentListener(stateController);
0740: addAWTMouseWheelListener(stateController);
0741: hAdjustable.addAdjustmentListener(stateController);
0742: vAdjustable.addAdjustmentListener(stateController);
0743: } finally {
0744: toolkit.unlockAWT();
0745: }
0746: }
0747:
0748: public void add(String item) {
0749: toolkit.lockAWT();
0750: try {
0751: add(item, -1);
0752: } finally {
0753: toolkit.unlockAWT();
0754: }
0755: }
0756:
0757: public void add(String item, int index) {
0758: toolkit.lockAWT();
0759: try {
0760: String str = (item != null ? item : ""); //$NON-NLS-1$
0761: int pos = index;
0762: int size = items.size();
0763: if ((pos < 0) || (pos > size)) {
0764: pos = size;
0765: }
0766: items.add(pos, str);
0767: updatePrefWidth();
0768: doRepaint();
0769: } finally {
0770: toolkit.unlockAWT();
0771: }
0772: }
0773:
0774: public void remove(String item) {
0775: toolkit.lockAWT();
0776: try {
0777: int index = items.indexOf(item);
0778: if (index < 0) {
0779: // awt.73=no such item
0780: throw new IllegalArgumentException(Messages
0781: .getString("awt.73")); //$NON-NLS-1$
0782: }
0783: remove(index);
0784: } finally {
0785: toolkit.unlockAWT();
0786: }
0787: }
0788:
0789: public void remove(int position) {
0790: toolkit.lockAWT();
0791: try {
0792: selection.remove(new Integer(position));
0793: items.remove(position);
0794: // decrease all selected indices greater than position
0795: // by 1, because items list is shifted to the left
0796: for (int i = 0; i < selection.size(); i++) {
0797: Integer idx = selection.get(i);
0798: int val = idx.intValue();
0799: if (val > position) {
0800: selection.set(i, new Integer(val - 1));
0801: }
0802: }
0803: updatePrefWidth();
0804: doRepaint();
0805: } catch (IndexOutOfBoundsException e) {
0806: throw new ArrayIndexOutOfBoundsException(e.getMessage());
0807: } finally {
0808: toolkit.unlockAWT();
0809: }
0810: }
0811:
0812: /**
0813: * @deprecated
0814: */
0815: @Deprecated
0816: public void clear() {
0817: toolkit.lockAWT();
0818: try {
0819: removeAll();
0820: } finally {
0821: toolkit.unlockAWT();
0822: }
0823: return;
0824: }
0825:
0826: public void removeAll() {
0827: toolkit.lockAWT();
0828: try {
0829: items.clear();
0830: selection.clear();
0831: currentIndex = 0;
0832: scrollable.setLocation(new Point());
0833: doRepaint();
0834: } finally {
0835: toolkit.unlockAWT();
0836: }
0837: }
0838:
0839: @Override
0840: protected String paramString() {
0841: toolkit.lockAWT();
0842: try {
0843: return (super .paramString() + ",selected=" + getSelectedItem()); //$NON-NLS-1$
0844: } finally {
0845: toolkit.unlockAWT();
0846: }
0847: }
0848:
0849: public String getItem(int index) {
0850: toolkit.lockAWT();
0851: try {
0852: return items.get(index);
0853: } finally {
0854: toolkit.unlockAWT();
0855: }
0856: }
0857:
0858: @Override
0859: public void addNotify() {
0860: toolkit.lockAWT();
0861: try {
0862: super .addNotify();
0863: updatePrefWidth();
0864: updateIncrements();
0865: } finally {
0866: toolkit.unlockAWT();
0867: }
0868: }
0869:
0870: @Override
0871: public AccessibleContext getAccessibleContext() {
0872: toolkit.lockAWT();
0873: try {
0874: return super .getAccessibleContext();
0875: } finally {
0876: toolkit.unlockAWT();
0877: }
0878: }
0879:
0880: @Override
0881: public Dimension getMinimumSize() {
0882: toolkit.lockAWT();
0883: try {
0884: return minimumSize();
0885: } finally {
0886: toolkit.unlockAWT();
0887: }
0888: }
0889:
0890: public Dimension getMinimumSize(int rows) {
0891: toolkit.lockAWT();
0892: try {
0893: if (!isDisplayable()) {
0894: return new Dimension();
0895: }
0896: Graphics gr = getGraphics();
0897: Dimension charSize = getMaxCharSize(gr);
0898: int minRowHeight = charSize.height + 1;
0899: final int MIN_CHARS_IN_ROW = 12;
0900: int hGap = 2 * BORDER_SIZE;
0901: int vGap = hGap;
0902: int minWidth = charSize.width * MIN_CHARS_IN_ROW + hGap;
0903: gr.dispose();
0904: return new Dimension(minWidth, rows * minRowHeight + vGap);
0905: } finally {
0906: toolkit.unlockAWT();
0907: }
0908: }
0909:
0910: public Dimension getPreferredSize(int rows) {
0911: toolkit.lockAWT();
0912: try {
0913: Dimension minSize = getMinimumSize(rows);
0914: if (items.isEmpty()) {
0915: return minSize;
0916: }
0917: if (!isDisplayable()) {
0918: return new Dimension();
0919: }
0920: int maxItemWidth = minSize.width;
0921: Graphics2D gr = (Graphics2D) getGraphics();
0922: FontRenderContext frc = gr.getFontRenderContext();
0923: Font font = getFont();
0924: for (int i = 0; i < items.size(); i++) {
0925: String item = getItem(i);
0926: int itemWidth = font.getStringBounds(item, frc)
0927: .getBounds().width;
0928: if (itemWidth > maxItemWidth) {
0929: maxItemWidth = itemWidth;
0930: }
0931: }
0932: gr.dispose();
0933: return new Dimension(maxItemWidth, minSize.height);
0934: } finally {
0935: toolkit.unlockAWT();
0936: }
0937: }
0938:
0939: @Override
0940: public Dimension getPreferredSize() {
0941: toolkit.lockAWT();
0942: try {
0943: return preferredSize();
0944: } finally {
0945: toolkit.unlockAWT();
0946: }
0947: }
0948:
0949: /**
0950: * @deprecated
0951: */
0952: @SuppressWarnings("deprecation")
0953: @Deprecated
0954: @Override
0955: public Dimension minimumSize() {
0956: toolkit.lockAWT();
0957: try {
0958: if (isMinimumSizeSet()) {
0959: return super .minimumSize();
0960: }
0961: return getMinimumSize(getRows());
0962: } finally {
0963: toolkit.unlockAWT();
0964: }
0965: }
0966:
0967: /**
0968: * @deprecated
0969: */
0970: @Deprecated
0971: public Dimension minimumSize(int rows) {
0972: toolkit.lockAWT();
0973: try {
0974: return getMinimumSize(rows);
0975: } finally {
0976: toolkit.unlockAWT();
0977: }
0978: }
0979:
0980: /**
0981: * @deprecated
0982: */
0983: @Deprecated
0984: public Dimension preferredSize(int rows) {
0985: toolkit.lockAWT();
0986: try {
0987: return getPreferredSize(getRows());
0988: } finally {
0989: toolkit.unlockAWT();
0990: }
0991: }
0992:
0993: /**
0994: * @deprecated
0995: */
0996: @SuppressWarnings("deprecation")
0997: @Deprecated
0998: @Override
0999: public Dimension preferredSize() {
1000: toolkit.lockAWT();
1001: try {
1002: if (isPreferredSizeSet()) {
1003: return super .preferredSize();
1004: }
1005: return getPreferredSize(getRows());
1006: } finally {
1007: toolkit.unlockAWT();
1008: }
1009: }
1010:
1011: @Override
1012: public void removeNotify() {
1013: toolkit.lockAWT();
1014: try {
1015: super .removeNotify();
1016: updatePrefWidth();
1017: } finally {
1018: toolkit.unlockAWT();
1019: }
1020: }
1021:
1022: /**
1023: * @deprecated
1024: */
1025: @Deprecated
1026: public void addItem(String item) {
1027: toolkit.lockAWT();
1028: try {
1029: add(item);
1030: } finally {
1031: toolkit.unlockAWT();
1032: }
1033: return;
1034: }
1035:
1036: /**
1037: * @deprecated
1038: */
1039: @Deprecated
1040: public void addItem(String item, int index) {
1041: toolkit.lockAWT();
1042: try {
1043: add(item, index);
1044: } finally {
1045: toolkit.unlockAWT();
1046: }
1047: return;
1048: }
1049:
1050: /**
1051: * @deprecated
1052: */
1053: @Deprecated
1054: public boolean allowsMultipleSelections() {
1055: toolkit.lockAWT();
1056: try {
1057: return isMultipleMode();
1058: } finally {
1059: toolkit.unlockAWT();
1060: }
1061: }
1062:
1063: /**
1064: * @deprecated
1065: */
1066: @Deprecated
1067: public int countItems() {
1068: toolkit.lockAWT();
1069: try {
1070: return getItemCount();
1071: } finally {
1072: toolkit.unlockAWT();
1073: }
1074: }
1075:
1076: /**
1077: * @deprecated
1078: */
1079: @Deprecated
1080: public void delItem(int position) {
1081: toolkit.lockAWT();
1082: try {
1083: remove(position);
1084: } finally {
1085: toolkit.unlockAWT();
1086: }
1087: }
1088:
1089: /**
1090: * @deprecated
1091: */
1092: @Deprecated
1093: public void delItems(int start, int end) {
1094: toolkit.lockAWT();
1095: try {
1096: for (int i = start; i <= end; i++) {
1097: remove(start);
1098: }
1099: } finally {
1100: toolkit.unlockAWT();
1101: }
1102: }
1103:
1104: public void deselect(int index) {
1105: toolkit.lockAWT();
1106: try {
1107: int oldFocusedIdx = currentIndex;
1108: currentIndex = index;
1109: selection.remove(new Integer(index));
1110: // repaint only deselected item's Rectangle &
1111: // previously "focused" item's Rectangle
1112: doRepaint(getMinRect(index, oldFocusedIdx));
1113: } finally {
1114: toolkit.unlockAWT();
1115: }
1116: }
1117:
1118: public int getItemCount() {
1119: toolkit.lockAWT();
1120: try {
1121: return items.size();
1122: } finally {
1123: toolkit.unlockAWT();
1124: }
1125: }
1126:
1127: public String[] getItems() {
1128: toolkit.lockAWT();
1129: try {
1130: String[] itemsArr = new String[items.size()];
1131: items.toArray(itemsArr);
1132: return itemsArr;
1133: } finally {
1134: toolkit.unlockAWT();
1135: }
1136: }
1137:
1138: public int getRows() {
1139: toolkit.lockAWT();
1140: try {
1141: return rows;
1142: } finally {
1143: toolkit.unlockAWT();
1144: }
1145: }
1146:
1147: public int getSelectedIndex() {
1148: toolkit.lockAWT();
1149: try {
1150: int selectedIndex = -1;
1151: if (selection.size() == 1) {
1152: selectedIndex = selection.get(0).intValue();
1153: }
1154: return selectedIndex;
1155: } finally {
1156: toolkit.unlockAWT();
1157: }
1158: }
1159:
1160: public int[] getSelectedIndexes() {
1161: toolkit.lockAWT();
1162: try {
1163: Integer[] selArr = new Integer[selection.size()];
1164: selection.toArray(selArr);
1165: int[] intArr = new int[selArr.length];
1166: for (int i = 0; i < selArr.length; i++) {
1167: intArr[i] = selArr[i].intValue();
1168: }
1169: return intArr;
1170: } finally {
1171: toolkit.unlockAWT();
1172: }
1173: }
1174:
1175: public String getSelectedItem() {
1176: toolkit.lockAWT();
1177: try {
1178: int selectedIndex = getSelectedIndex();
1179: if (selectedIndex < 0) {
1180: return null;
1181: }
1182: return items.get(selectedIndex);
1183: } finally {
1184: toolkit.unlockAWT();
1185: }
1186: }
1187:
1188: public String[] getSelectedItems() {
1189: toolkit.lockAWT();
1190: try {
1191: int size = selection.size();
1192: String[] selItemsArr = new String[size];
1193: Integer[] selArr = new Integer[size];
1194: selection.toArray(selArr);
1195: for (int i = 0; i < selItemsArr.length; i++) {
1196: selItemsArr[i] = items.get(selArr[i].intValue());
1197: }
1198: return selItemsArr;
1199: } finally {
1200: toolkit.unlockAWT();
1201: }
1202: }
1203:
1204: public Object[] getSelectedObjects() {
1205: toolkit.lockAWT();
1206: try {
1207: return getSelectedItems();
1208: } finally {
1209: toolkit.unlockAWT();
1210: }
1211: }
1212:
1213: public int getVisibleIndex() {
1214: toolkit.lockAWT();
1215: try {
1216: return visibleIndex;
1217: } finally {
1218: toolkit.unlockAWT();
1219: }
1220: }
1221:
1222: public boolean isIndexSelected(int position) {
1223: toolkit.lockAWT();
1224: try {
1225: return selection.contains(new Integer(position));
1226: } finally {
1227: toolkit.unlockAWT();
1228: }
1229: }
1230:
1231: public boolean isMultipleMode() {
1232: toolkit.lockAWT();
1233: try {
1234: return multipleMode;
1235: } finally {
1236: toolkit.unlockAWT();
1237: }
1238: }
1239:
1240: /**
1241: * @deprecated
1242: */
1243: @Deprecated
1244: public boolean isSelected(int pos) {
1245: toolkit.lockAWT();
1246: try {
1247: return isIndexSelected(pos);
1248: } finally {
1249: toolkit.unlockAWT();
1250: }
1251: }
1252:
1253: public void makeVisible(int index) {
1254: toolkit.lockAWT();
1255: try {
1256: visibleIndex = index;
1257: if (!isDisplayable() || !isIdxValid(index)) {
1258: return;
1259: }
1260: // scroll if necessary
1261: Rectangle itemRect = getItemBounds(index);
1262: Rectangle clientRect = getClient();
1263: int dy = itemRect.y - clientRect.y;
1264: if (dy < 0) {
1265: stateController.updateAdjValue(vAdjustable, dy);
1266: }
1267: dy = itemRect.y + itemRect.height
1268: - (clientRect.y + clientRect.height);
1269: if (dy > 0) {
1270: stateController.updateAdjValue(vAdjustable, dy);
1271: }
1272: doRepaint(getMinRect(currentIndex, visibleIndex));
1273: currentIndex = visibleIndex;
1274: } finally {
1275: toolkit.unlockAWT();
1276: }
1277: }
1278:
1279: public void replaceItem(String newValue, int index) {
1280: toolkit.lockAWT();
1281: try {
1282: items.set(index, newValue);
1283: updatePrefWidth();
1284: doRepaint();
1285: } catch (IndexOutOfBoundsException e) {
1286: throw new ArrayIndexOutOfBoundsException(e.getMessage());
1287: } finally {
1288: toolkit.unlockAWT();
1289: }
1290: }
1291:
1292: public void select(int index) {
1293: toolkit.lockAWT();
1294: try {
1295: // if an item was already selected -
1296: // do nothing
1297: if (isIndexSelected(index)) {
1298: return;
1299: }
1300: if (!multipleMode && (selection.size() == 1)) {
1301: deselect(getSelectedIndex());
1302: }
1303: selection.add(new Integer(index));
1304: // repaint only item's rectangle & old "focused" item's rect
1305: doRepaint(getMinRect(index, currentIndex));
1306: currentIndex = index;
1307: } finally {
1308: toolkit.unlockAWT();
1309: }
1310: }
1311:
1312: public void setMultipleMode(boolean multipleMode) {
1313: toolkit.lockAWT();
1314: try {
1315: if (!multipleMode && (this .multipleMode != multipleMode)) {
1316: selection.clear();
1317: int curIdx = getCurrentIndex();
1318: if (curIdx >= 0) {
1319: selection.add(new Integer(curIdx));
1320: }
1321: }
1322: this .multipleMode = multipleMode;
1323: doRepaint();
1324: } finally {
1325: toolkit.unlockAWT();
1326: }
1327: }
1328:
1329: /**
1330: * @deprecated
1331: */
1332: @Deprecated
1333: public void setMultipleSelections(boolean mm) {
1334: toolkit.lockAWT();
1335: try {
1336: setMultipleMode(mm);
1337: } finally {
1338: toolkit.unlockAWT();
1339: }
1340: }
1341:
1342: @SuppressWarnings("unchecked")
1343: @Override
1344: public <T extends EventListener> T[] getListeners(
1345: Class<T> listenerType) {
1346: if (ActionListener.class.isAssignableFrom(listenerType)) {
1347: return (T[]) getActionListeners();
1348: } else if (ItemListener.class.isAssignableFrom(listenerType)) {
1349: return (T[]) getItemListeners();
1350: } else {
1351: return super .getListeners(listenerType);
1352: }
1353: }
1354:
1355: public void addActionListener(ActionListener l) {
1356: actionListeners.addUserListener(l);
1357: }
1358:
1359: public void removeActionListener(ActionListener l) {
1360: actionListeners.removeUserListener(l);
1361: }
1362:
1363: public ActionListener[] getActionListeners() {
1364: return actionListeners.getUserListeners(new ActionListener[0]);
1365: }
1366:
1367: public void addItemListener(ItemListener l) {
1368: itemListeners.addUserListener(l);
1369: }
1370:
1371: public void removeItemListener(ItemListener l) {
1372: itemListeners.removeUserListener(l);
1373: }
1374:
1375: public ItemListener[] getItemListeners() {
1376: return itemListeners.getUserListeners(new ItemListener[0]);
1377: }
1378:
1379: @Override
1380: protected void processEvent(AWTEvent e) {
1381: long eventMask = toolkit.eventTypeLookup.getEventMask(e);
1382: if (eventMask == AWTEvent.ACTION_EVENT_MASK) {
1383: processActionEvent((ActionEvent) e);
1384: } else if (eventMask == AWTEvent.ITEM_EVENT_MASK) {
1385: processItemEvent((ItemEvent) e);
1386: } else {
1387: super .processEvent(e);
1388: }
1389: }
1390:
1391: protected void processItemEvent(ItemEvent e) {
1392: for (Iterator<?> i = itemListeners.getUserIterator(); i
1393: .hasNext();) {
1394: ItemListener listener = (ItemListener) i.next();
1395: switch (e.getID()) {
1396: case ItemEvent.ITEM_STATE_CHANGED:
1397: listener.itemStateChanged(e);
1398: break;
1399: }
1400: }
1401: }
1402:
1403: protected void processActionEvent(ActionEvent e) {
1404: for (Iterator<?> i = actionListeners.getUserIterator(); i
1405: .hasNext();) {
1406: ActionListener listener = (ActionListener) i.next();
1407: switch (e.getID()) {
1408: case ActionEvent.ACTION_PERFORMED:
1409: listener.actionPerformed(e);
1410: break;
1411: }
1412: }
1413: }
1414:
1415: @Override
1416: String autoName() {
1417: return ("list" + toolkit.autoNumber.nextList++); //$NON-NLS-1$
1418: }
1419:
1420: Dimension getMinimumSizeImpl() {
1421: return getMinimumSize(getRows());
1422: }
1423:
1424: @Override
1425: ComponentBehavior createBehavior() {
1426: return new HWBehavior(this );
1427: }
1428:
1429: @Override
1430: boolean isPrepainter() {
1431: return true;
1432: }
1433:
1434: @Override
1435: void prepaint(Graphics g) {
1436: toolkit.theme.drawList(g, state, false);
1437: vAdjustable.prepaint(g);
1438: hAdjustable.prepaint(g);
1439: }
1440:
1441: private Dimension getMaxCharSize(Graphics g) {
1442: final FontRenderContext frc = ((Graphics2D) g)
1443: .getFontRenderContext();
1444: return getListFont()
1445: .getStringBounds("W", frc).getBounds().getSize(); //$NON-NLS-1$
1446: }
1447:
1448: private Font getListFont() {
1449: final Font f = getFont();
1450: return f == null ? DEFAULT_FONT : f;
1451: }
1452:
1453: private void doRepaint(Rectangle r) {
1454: if (isDisplayable()) {
1455: invalidate();
1456: if (isShowing() && (r != null)) {
1457: repaint(r.x, r.y, r.width, r.height);
1458: }
1459: }
1460: }
1461:
1462: private void doRepaint() {
1463: stateController.layoutScrollbars();
1464: doRepaint(new Rectangle(new Point(), getSize()));
1465: }
1466:
1467: @Override
1468: void setFontImpl(Font f) {
1469: super .setFontImpl(f);
1470: if (isDisplayable()) {
1471: invalidate();
1472: updateIncrements();
1473: }
1474: }
1475:
1476: private Rectangle getItemBounds(int pos) {
1477: Dimension itemSize = getItemSize();
1478: Point p = new Point(BORDER_SIZE, pos * itemSize.height
1479: + BORDER_SIZE);
1480: Rectangle itemRect = new Rectangle(p, itemSize);
1481: itemRect.translate(scrollLocation.x, scrollLocation.y);
1482: return itemRect;
1483: }
1484:
1485: @SuppressWarnings("deprecation")
1486: private Dimension getItemSize() {
1487: FontMetrics fm = toolkit.getFontMetrics(getListFont());
1488: int itemHeight = fm.getHeight() + 2;
1489: return new Dimension(prefWidth - 2 * BORDER_SIZE, itemHeight);
1490: }
1491:
1492: private int getItemIndex(int y) {
1493: return (y - BORDER_SIZE - scrollLocation.y)
1494: / getItemSize().height;
1495: }
1496:
1497: private int getCurrentIndex() {
1498: return (isDisplayable() ? currentIndex : -1);
1499: }
1500:
1501: private Rectangle getClient() {
1502: Insets ins = getNativeInsets();
1503: return new Rectangle(ins.left, ins.top, getWidth()
1504: - (ins.left + ins.right), getHeight()
1505: - (ins.top + ins.bottom));
1506: }
1507:
1508: @Override
1509: Insets getInsets() {
1510: if (!isDisplayable()) {
1511: return super .getInsets();
1512: }
1513: Insets insets = new Insets(BORDER_SIZE, BORDER_SIZE,
1514: BORDER_SIZE, BORDER_SIZE);
1515: return insets;
1516: }
1517:
1518: @Override
1519: Insets getNativeInsets() {
1520: Insets insets = getInsets();
1521: insets.bottom += hAdjustable.getBounds().height;
1522: insets.right += vAdjustable.getBounds().width;
1523: return insets;
1524: }
1525:
1526: private void updatePrefWidth() {
1527: Dimension prefSize = getPreferredSize(1);
1528: prefWidth = prefSize.width;
1529: }
1530:
1531: private void updateIncrements() {
1532: Dimension itemSize = getItemSize();
1533: Dimension clientSize = getClient().getSize();
1534: vAdjustable.setUnitIncrement(itemSize.height);
1535: vAdjustable.setBlockIncrement(clientSize.height);
1536: Graphics gr = getGraphics();
1537: hAdjustable.setUnitIncrement(getMaxCharSize(gr).width);
1538: hAdjustable.setBlockIncrement(clientSize.width);
1539: gr.dispose();
1540: }
1541:
1542: private boolean isIdxValid(int index) {
1543: return ((index >= 0) && (index < getItemCount()));
1544: }
1545:
1546: private Rectangle getMinRect(int idx1, int idx2) {
1547: if (!isDisplayable()) {
1548: return null;
1549: }
1550: Rectangle r1 = getItemBounds(idx1);
1551: Rectangle r2 = getItemBounds(idx2);
1552: Rectangle minRect = r1.union(r2);
1553: minRect.width = getClient().width - minRect.x + 1;
1554: minRect.grow(1, 1);
1555: return minRect;
1556: }
1557:
1558: @Override
1559: AccessibleContext createAccessibleContext() {
1560: return new AccessibleAWTList();
1561: }
1562: }
|