0001: /*
0002: * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: // Very much based on XListPeer from javaos
0027: package sun.awt.X11;
0028:
0029: import java.awt.*;
0030: import java.awt.event.*;
0031: import java.awt.peer.*;
0032: import java.util.Vector;
0033: import java.awt.geom.*;
0034: import java.awt.image.*;
0035: import java.util.logging.*;
0036:
0037: // TODO: some input actions should do nothing if Shift or Control are down
0038:
0039: class XListPeer extends XComponentPeer implements ListPeer,
0040: XScrollbarClient {
0041:
0042: private static final Logger log = Logger
0043: .getLogger("sun.awt.X11.XListPeer");
0044:
0045: public final static int MARGIN = 2;
0046: public final static int SPACE = 1;
0047: public final static int SCROLLBAR_AREA = 17; // Area reserved for the
0048: // scrollbar
0049: public final static int SCROLLBAR_WIDTH = 13; // Actual width of the
0050: // scrollbar
0051: public final static int NONE = -1;
0052: public final static int WINDOW = 0;
0053: public final static int VERSCROLLBAR = 1;
0054: public final static int HORSCROLLBAR = 2;
0055: public final static int DEFAULT_VISIBLE_ROWS = 4; // From java.awt.List,
0056: public final static int HORIZ_SCROLL_AMT = 10;
0057:
0058: final static int PAINT_VSCROLL = 2, PAINT_HSCROLL = 4,
0059: PAINT_ITEMS = 8, PAINT_FOCUS = 16, PAINT_BACKGROUND = 32,
0060: PAINT_HIDEFOCUS = 64, PAINT_ALL = PAINT_VSCROLL
0061: | PAINT_HSCROLL | PAINT_ITEMS | PAINT_FOCUS
0062: | PAINT_BACKGROUND;
0063:
0064: XVerticalScrollbar vsb;
0065: XHorizontalScrollbar hsb;
0066: ListPainter painter;
0067:
0068: // TODO: ick - Vector?
0069: Vector items;
0070: boolean multipleSelections;
0071: int active = NONE;
0072:
0073: // Holds the array of the indexes of the elements which is selected
0074: // This array should be kept sorted, low to high.
0075: int selected[];
0076: int fontHeight;
0077: int fontAscent;
0078: int fontLeading;
0079:
0080: // Holds the index of the item used in the previous operation (selectItem, deselectItem)
0081: // Adding of an item or clearing of the list sets this index to -1
0082: // The index is used at the moment of the post of ACTION_PERFORMED event after the mouse double click event.
0083: int currentIndex = -1;
0084:
0085: // Used for tracking selection/deselection between mousePress/Release
0086: // and for ItemEvents
0087: int eventIndex = -1;
0088: int eventType = NONE;
0089:
0090: // Holds the index of the item that receive focus
0091: // This variable is reasonable only for multiple list
0092: // since 'focusIndex' and 'selected[0]' are equal for single-selection list
0093: int focusIndex;
0094:
0095: int maxLength;
0096: boolean vsbVis; // visibility of scrollbars
0097: boolean hsbVis;
0098: int listWidth; // Width of list portion of List
0099: int listHeight; // Height of list portion of List
0100: // (i.e. without scrollbars)
0101:
0102: private int firstTimeVisibleIndex = 0;
0103:
0104: // Motif Lists don't seem to inherit the background color from their
0105: // parent when an app is first started up. So, we track if the colors have
0106: // been set. See getListBackground()/getListForeground().
0107: boolean bgColorSet;
0108: boolean fgColorSet;
0109:
0110: // Holds the true if mouse is dragging outside of the area of the list
0111: // The flag is used at the moment of the dragging and releasing mouse
0112: // See 6243382 for more information
0113: boolean mouseDraggedOutHorizontally = false;
0114: boolean mouseDraggedOutVertically = false;
0115:
0116: // Holds the true if a mouse event was originated on the scrollbar
0117: // See 6300527 for more information
0118: boolean isScrollBarOriginated = false;
0119:
0120: // This variable is set to true after the "mouse pressed" event and to false after the "mouse released" event
0121: // Fixed 6293432: Key events ('SPACE', 'UP', 'DOWN') aren't blocked if mouse is kept in 'PRESSED' state for List, XAWT
0122: boolean isMousePressed = false;
0123:
0124: /**
0125: * Create a list
0126: */
0127: XListPeer(List target) {
0128: super (target);
0129: }
0130:
0131: /**
0132: * Overridden from XWindow
0133: */
0134: public void preInit(XCreateWindowParams params) {
0135: super .preInit(params);
0136:
0137: // Stuff that must be initialized before layout() is called
0138: items = new Vector();
0139: createVerScrollbar();
0140: createHorScrollbar();
0141:
0142: painter = new ListPainter();
0143:
0144: // See 6246467 for more information
0145: bgColorSet = target.isBackgroundSet();
0146: fgColorSet = target.isForegroundSet();
0147: }
0148:
0149: public void postInit(XCreateWindowParams params) {
0150: super .postInit(params);
0151: initFontMetrics();
0152: // TODO: more efficient way?
0153: // do we really want/need a copy of all the items?
0154: // get all items from target
0155: List l = (List) target;
0156: int stop = l.getItemCount();
0157: for (int i = 0; i < stop; i++) {
0158: items.addElement(l.getItem(i));
0159: }
0160:
0161: /* make the visible position visible. */
0162: int index = l.getVisibleIndex();
0163: if (index >= 0) {
0164: // Can't call makeVisible since it check scroll bar,
0165: // initialize scroll bar instead
0166: vsb.setValues(index, 0, 0, items.size());
0167: }
0168:
0169: // NOTE: needs to have target set
0170: maxLength = maxLength();
0171:
0172: // get the index containing all indexes to selected items
0173: int sel[] = l.getSelectedIndexes();
0174: selected = new int[sel.length];
0175: // TODO: shouldn't this be arraycopy()?
0176: for (int i = 0; i < sel.length; i++) {
0177: selected[i] = sel[i];
0178: }
0179: // The select()ed item should become the focused item, but we don't
0180: // get the select() call because the peer generally hasn't yet been
0181: // created during app initialization.
0182: // TODO: For multi-select lists, it should be the highest selected index
0183: if (sel.length > 0) {
0184: setFocusIndex(sel[sel.length - 1]);
0185: } else {
0186: setFocusIndex(0);
0187: }
0188:
0189: multipleSelections = l.isMultipleMode();
0190: }
0191:
0192: /**
0193: * add Vertical Scrollbar
0194: */
0195: void createVerScrollbar() {
0196: vsb = new XVerticalScrollbar(this );
0197: vsb.setValues(0, 0, 0, 0, 1, 1);
0198: }
0199:
0200: /**
0201: * add Horizontal scrollbar
0202: */
0203: void createHorScrollbar() {
0204: hsb = new XHorizontalScrollbar(this );
0205: hsb.setValues(0, 0, 0, 0, HORIZ_SCROLL_AMT, HORIZ_SCROLL_AMT);
0206: }
0207:
0208: /* New method name for 1.1 */
0209: public void add(String item, int index) {
0210: addItem(item, index);
0211: }
0212:
0213: /* New method name for 1.1 */
0214: public void removeAll() {
0215: clear();
0216: maxLength = 0;
0217: }
0218:
0219: /* New method name for 1.1 */
0220: public void setMultipleMode(boolean b) {
0221: setMultipleSelections(b);
0222: }
0223:
0224: /* New method name for 1.1 */
0225: public Dimension getPreferredSize(int rows) {
0226: return preferredSize(rows);
0227: }
0228:
0229: /* New method name for 1.1 */
0230: public Dimension getMinimumSize(int rows) {
0231: return minimumSize(rows);
0232: }
0233:
0234: /**
0235: * Minimum size.
0236: */
0237: public Dimension minimumSize() {
0238: return minimumSize(DEFAULT_VISIBLE_ROWS);
0239: }
0240:
0241: /**
0242: * return the preferredSize
0243: */
0244: public Dimension preferredSize(int v) {
0245: return minimumSize(v);
0246: }
0247:
0248: /**
0249: * return the minimumsize
0250: */
0251: public Dimension minimumSize(int v) {
0252: FontMetrics fm = getFontMetrics(getFont());
0253: initFontMetrics();
0254: return new Dimension(20 + fm.stringWidth("0123456789abcde"),
0255: getItemHeight() * v + (2 * MARGIN));
0256: }
0257:
0258: /**
0259: * Calculate font metrics
0260: */
0261: void initFontMetrics() {
0262: FontMetrics fm = getFontMetrics(getFont());
0263: fontHeight = fm.getHeight();
0264: fontAscent = fm.getAscent();
0265: fontLeading = fm.getLeading();
0266: }
0267:
0268: /**
0269: * return the length of the largest item in the list
0270: */
0271: int maxLength() {
0272: FontMetrics fm = getFontMetrics(getFont());
0273: int m = 0;
0274: int end = items.size();
0275: for (int i = 0; i < end; i++) {
0276: int l = fm.stringWidth(((String) items.elementAt(i)));
0277: m = Math.max(m, l);
0278: }
0279: return m;
0280: }
0281:
0282: /**
0283: * Calculates the width of item's label
0284: */
0285: int getItemWidth(int i) {
0286: FontMetrics fm = getFontMetrics(getFont());
0287: return fm.stringWidth((String) items.elementAt(i));
0288: }
0289:
0290: /**
0291: * return the on-screen width of the given string "str"
0292: */
0293: int stringLength(String str) {
0294: FontMetrics fm = getFontMetrics(target.getFont());
0295: return fm.stringWidth(str);
0296: }
0297:
0298: public void setForeground(Color c) {
0299: fgColorSet = true;
0300: super .setForeground(c);
0301: }
0302:
0303: public void setBackground(Color c) {
0304: bgColorSet = true;
0305: super .setBackground(c);
0306: }
0307:
0308: /**
0309: * Returns the color that should be used to paint the background of
0310: * the list of items. Note that this is not the same as
0311: * target.getBackground() which is the color of the scrollbars, and the
0312: * lower-right corner of the Component when the scrollbars are displayed.
0313: */
0314: private Color getListBackground(Color[] colors) {
0315: if (bgColorSet) {
0316: return colors[BACKGROUND_COLOR];
0317: } else {
0318: return SystemColor.text;
0319: }
0320: }
0321:
0322: /**
0323: * Returns the color that should be used to paint the list item text.
0324: */
0325: private Color getListForeground(Color[] colors) {
0326: if (fgColorSet) {
0327: return colors[FOREGROUND_COLOR];
0328: } else {
0329: return SystemColor.textText;
0330: }
0331: }
0332:
0333: Rectangle getVScrollBarRec() {
0334: return new Rectangle(width - (SCROLLBAR_WIDTH), 0,
0335: SCROLLBAR_WIDTH + 1, height);
0336: }
0337:
0338: Rectangle getHScrollBarRec() {
0339: return new Rectangle(0, height - SCROLLBAR_WIDTH, width,
0340: SCROLLBAR_WIDTH);
0341: }
0342:
0343: int getFirstVisibleItem() {
0344: if (vsbVis) {
0345: return vsb.getValue();
0346: } else {
0347: return 0;
0348: }
0349: }
0350:
0351: int getLastVisibleItem() {
0352: if (vsbVis) {
0353: return Math.min(items.size() - 1, vsb.getValue()
0354: + itemsInWindow() - 1);
0355: } else {
0356: return Math.min(items.size() - 1, itemsInWindow() - 1);
0357: }
0358: }
0359:
0360: Area getItemsArea(int firstItem, int lastItem) {
0361: firstItem = Math.max(getFirstVisibleItem(), firstItem);
0362: lastItem = Math.min(lastItem, getLastVisibleItem());
0363: if (lastItem < getFirstVisibleItem()) {
0364: return new Area();
0365: }
0366: if (firstItem <= lastItem) {
0367: int startY = getItemY(firstItem);
0368: int endY = getItemY(lastItem) + getItemHeight();
0369: // Account for focus rectangle, instead should be called twice - before change
0370: // of focusIndex and after
0371: startY -= 2;
0372: endY += 2;
0373: // x is 0 since we need to account for focus rectangle,
0374: // the same with width
0375: return new Area(new Rectangle(0, startY,
0376: getItemWidth() + 3, endY - startY + 1));
0377: } else {
0378: return new Area();
0379: }
0380: }
0381:
0382: Rectangle getItemRect(int item) {
0383: return new Rectangle(MARGIN, getItemY(item), getItemWidth(),
0384: getItemHeight());
0385: }
0386:
0387: Area getItemArea(int item) {
0388: return new Area(getItemRect(item));
0389: }
0390:
0391: public void repaintScrollbarRequest(XScrollbar scrollbar) {
0392: Graphics g = getGraphics();
0393: if (scrollbar == hsb) {
0394: repaint(PAINT_HSCROLL);
0395: } else if (scrollbar == vsb) {
0396: repaint(PAINT_VSCROLL);
0397: }
0398: }
0399:
0400: /**
0401: * Overridden for performance
0402: */
0403: public void repaint() {
0404: repaint(getFirstVisibleItem(), getLastVisibleItem(), PAINT_ALL);
0405: }
0406:
0407: public void repaint(int options) {
0408: repaint(getFirstVisibleItem(), getLastVisibleItem(), options);
0409: }
0410:
0411: public void repaint(int firstItem, int lastItem, int options) {
0412: Graphics g = getGraphics();
0413: try {
0414: painter.paint(g, firstItem, lastItem, options);
0415: } finally {
0416: g.dispose();
0417: }
0418: }
0419:
0420: public void paint(Graphics g) {
0421: painter.paint(g, getFirstVisibleItem(), getLastVisibleItem(),
0422: PAINT_ALL);
0423: }
0424:
0425: public boolean isFocusable() {
0426: return true;
0427: }
0428:
0429: // TODO: share/promote the Focus methods?
0430: public void focusGained(FocusEvent e) {
0431: super .focusGained(e);
0432: repaint(PAINT_FOCUS);
0433: }
0434:
0435: public void focusLost(FocusEvent e) {
0436: super .focusLost(e);
0437: repaint(PAINT_FOCUS);
0438: }
0439:
0440: /**
0441: * Layout the sub-components of the List - that is, the scrollbars and the
0442: * list of items.
0443: */
0444: public void layout() {
0445: int vis, maximum;
0446: boolean vsbWasVisible;
0447: int origVSBVal;
0448: assert (target != null);
0449:
0450: // Start with assumption there is not a horizontal scrollbar,
0451: // see if we need a vertical scrollbar
0452:
0453: // Bug: If the list DOES have a horiz scrollbar and the value is set to
0454: // the very bottom value, value is reset in setValues() because it isn't
0455: // a valid value for cases when the list DOESN'T have a horiz scrollbar.
0456: // This is currently worked-around with origVSGVal.
0457: origVSBVal = vsb.getValue();
0458: vis = itemsInWindow(false);
0459: maximum = items.size() < vis ? vis : items.size();
0460: vsb.setValues(vsb.getValue(), vis, vsb.getMinimum(), maximum);
0461: vsbVis = vsbWasVisible = vsbIsVisible(false);
0462: listHeight = height;
0463:
0464: // now see if we need a horizontal scrollbar
0465: listWidth = getListWidth();
0466: vis = listWidth - ((2 * SPACE) + (2 * MARGIN));
0467: maximum = maxLength < vis ? vis : maxLength;
0468: hsb.setValues(hsb.getValue(), vis, hsb.getMinimum(), maximum);
0469: hsbVis = hsbIsVisible(vsbVis);
0470:
0471: if (hsbVis) {
0472: // do need a horizontal scrollbar, so recalculate height of
0473: // vertical s crollbar
0474: listHeight = height - SCROLLBAR_AREA;
0475: vis = itemsInWindow(true);
0476: maximum = items.size() < vis ? vis : items.size();
0477: vsb.setValues(origVSBVal, vis, vsb.getMinimum(), maximum);
0478: vsbVis = vsbIsVisible(true);
0479: }
0480:
0481: // now check to make sure we haven't changed need for vertical
0482: // scrollbar - if we have, we need to
0483: // recalculate horizontal scrollbar width - then we're done...
0484: if (vsbWasVisible != vsbVis) {
0485: listWidth = getListWidth();
0486: vis = listWidth - ((2 * SPACE) + (2 * MARGIN));
0487: maximum = maxLength < vis ? 0 : maxLength;
0488: hsb.setValues(hsb.getValue(), vis, hsb.getMinimum(),
0489: maximum);
0490: hsbVis = hsbIsVisible(vsbVis);
0491: }
0492:
0493: vsb.setSize(SCROLLBAR_WIDTH, listHeight);
0494: hsb.setSize(listWidth, SCROLLBAR_WIDTH);
0495:
0496: vsb.setBlockIncrement(itemsInWindow());
0497: hsb
0498: .setBlockIncrement(width
0499: - ((2 * SPACE) + (2 * MARGIN) + (vsbVis ? SCROLLBAR_AREA
0500: : 0)));
0501: }
0502:
0503: int getItemWidth() {
0504: return width - ((2 * MARGIN) + (vsbVis ? SCROLLBAR_AREA : 0));
0505: }
0506:
0507: /* Returns height of an item in the list */
0508: int getItemHeight() {
0509: return (fontHeight - fontLeading) + (2 * SPACE);
0510: }
0511:
0512: int getItemX() {
0513: return MARGIN + SPACE;
0514: }
0515:
0516: int getItemY(int item) {
0517: return index2y(item);
0518: }
0519:
0520: int getFocusIndex() {
0521: return focusIndex;
0522: }
0523:
0524: void setFocusIndex(int value) {
0525: focusIndex = value;
0526: }
0527:
0528: /**
0529: * Update and return the focus rectangle.
0530: * Focus is around the focused item, if it is visible, or
0531: * around the border of the list if the focused item is scrolled off the top
0532: * or bottom of the list.
0533: */
0534: Rectangle getFocusRect() {
0535: Rectangle focusRect = new Rectangle();
0536: // width is always only based on presence of vert sb
0537: focusRect.x = 1;
0538: focusRect.width = getListWidth() - 3;
0539: // if focused item is not currently displayed in the list, paint
0540: // focus around entire list (not including scrollbars)
0541: if (isIndexDisplayed(getFocusIndex())) {
0542: // focus rect is around the item
0543: focusRect.y = index2y(getFocusIndex()) - 2;
0544: focusRect.height = getItemHeight() + 1;
0545: } else {
0546: // focus rect is around the list
0547: focusRect.y = 1;
0548: focusRect.height = hsbVis ? height - SCROLLBAR_AREA
0549: : height;
0550: focusRect.height -= 3;
0551: }
0552: return focusRect;
0553: }
0554:
0555: public void handleConfigureNotifyEvent(XEvent xev) {
0556: super .handleConfigureNotifyEvent(xev);
0557:
0558: // Update buffer
0559: painter.invalidate();
0560: }
0561:
0562: public boolean handlesWheelScrolling() {
0563: return true;
0564: }
0565:
0566: // FIXME: need to support MouseWheel scrolling, too
0567: void handleJavaMouseEvent(MouseEvent e) {
0568: super .handleJavaMouseEvent(e);
0569: int i = e.getID();
0570: switch (i) {
0571: case MouseEvent.MOUSE_PRESSED:
0572: mousePressed(e);
0573: break;
0574: case MouseEvent.MOUSE_RELEASED:
0575: mouseReleased(e);
0576: break;
0577: case MouseEvent.MOUSE_DRAGGED:
0578: mouseDragged(e);
0579: break;
0580: }
0581: }
0582:
0583: void handleJavaMouseWheelEvent(MouseWheelEvent e) {
0584: if (ListHelper.doWheelScroll(vsbVis ? vsb : null, hsbVis ? hsb
0585: : null, e)) {
0586: repaint();
0587: }
0588: }
0589:
0590: void mousePressed(MouseEvent mouseEvent) {
0591: if (log.isLoggable(Level.FINER))
0592: log.finer(mouseEvent.toString() + ", hsb " + hsbVis
0593: + ", vsb " + vsbVis);
0594: if (isEnabled() && mouseEvent.getButton() == MouseEvent.BUTTON1) {
0595: if (inWindow(mouseEvent.getX(), mouseEvent.getY())) {
0596: if (log.isLoggable(Level.FINE))
0597: log.fine("Mouse press in items area");
0598: active = WINDOW;
0599: int i = y2index(mouseEvent.getY());
0600: if (i >= 0) {
0601: if (multipleSelections) {
0602: if (isSelected(i)) {
0603: // See 6243382 for more information
0604: deselectItem(i);
0605: eventIndex = i;
0606: eventType = ItemEvent.DESELECTED;
0607: } else {
0608: selectItem(i);
0609: eventIndex = i;
0610: eventType = ItemEvent.SELECTED;
0611: }
0612: }
0613: // Backward-compatible bug: even if a single-select
0614: // item is already selected, we send an ITEM_STATE_CHANGED/
0615: // SELECTED event. Engineer's Toolbox appears to rely on
0616: // this.
0617: //else if (!isSelected(i)) {
0618: else {
0619: selectItem(i);
0620: eventIndex = i;
0621: eventType = ItemEvent.SELECTED;
0622: }
0623: // Restoring Windows behaviour
0624: // We should update focus index after "mouse pressed" event
0625: setFocusIndex(i);
0626: repaint(PAINT_FOCUS);
0627: } else {
0628: // 6426186: reset variable to prevent action event
0629: // if user clicks on unoccupied area of list
0630: currentIndex = -1;
0631: }
0632: } else if (inVerticalScrollbar(mouseEvent.getX(),
0633: mouseEvent.getY())) {
0634: if (log.isLoggable(Level.FINE))
0635: log.fine("Mouse press in vertical scrollbar");
0636: active = VERSCROLLBAR;
0637: vsb.handleMouseEvent(mouseEvent.getID(), mouseEvent
0638: .getModifiers(), mouseEvent.getX()
0639: - (width - SCROLLBAR_WIDTH), mouseEvent.getY());
0640: } else if (inHorizontalScrollbar(mouseEvent.getX(),
0641: mouseEvent.getY())) {
0642: if (log.isLoggable(Level.FINE))
0643: log.fine("Mouse press in horizontal scrollbar");
0644: active = HORSCROLLBAR;
0645: hsb.handleMouseEvent(mouseEvent.getID(), mouseEvent
0646: .getModifiers(), mouseEvent.getX(), mouseEvent
0647: .getY()
0648: - (height - SCROLLBAR_WIDTH));
0649:
0650: }
0651: isMousePressed = true;
0652: }
0653: }
0654:
0655: void mouseReleased(MouseEvent mouseEvent) {
0656: if (isEnabled() && mouseEvent.getButton() == MouseEvent.BUTTON1) {
0657: //winReleaseCursorFocus();
0658: int clickCount = mouseEvent.getClickCount();
0659: if (active == VERSCROLLBAR) {
0660: vsb.handleMouseEvent(mouseEvent.getID(), mouseEvent
0661: .getModifiers(), mouseEvent.getX()
0662: - (width - SCROLLBAR_WIDTH), mouseEvent.getY());
0663: } else if (active == HORSCROLLBAR) {
0664: hsb.handleMouseEvent(mouseEvent.getID(), mouseEvent
0665: .getModifiers(), mouseEvent.getX(), mouseEvent
0666: .getY()
0667: - (height - SCROLLBAR_WIDTH));
0668: } else if ((currentIndex >= 0) && (clickCount >= 2)
0669: && (clickCount % 2 == 0)) {
0670: postEvent(new ActionEvent(target,
0671: ActionEvent.ACTION_PERFORMED, (String) items
0672: .elementAt(currentIndex), mouseEvent
0673: .getWhen(), mouseEvent.getModifiers())); // No ext mods
0674: } else if (active == WINDOW) {
0675: // See 6243382 for more information
0676: trackMouseReleasedScroll();
0677:
0678: if (eventType == ItemEvent.DESELECTED) {
0679: assert multipleSelections : "Shouldn't get a deselect for a single-select List";
0680: // Paint deselection the release
0681: deselectItem(eventIndex);
0682: }
0683: if (eventType != NONE) {
0684: postEvent(new ItemEvent((List) target,
0685: ItemEvent.ITEM_STATE_CHANGED, Integer
0686: .valueOf(eventIndex), eventType));
0687: }
0688: }
0689: active = NONE;
0690: eventIndex = -1;
0691: eventType = NONE;
0692: isMousePressed = false;
0693: }
0694: }
0695:
0696: void mouseDragged(MouseEvent mouseEvent) {
0697: // TODO: can you drag w/ any other buttons? what about multiple buttons?
0698: if (isEnabled()
0699: && (mouseEvent.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0) {
0700: if ((active == VERSCROLLBAR)) {
0701: vsb.handleMouseEvent(mouseEvent.getID(), mouseEvent
0702: .getModifiers(), mouseEvent.getX()
0703: - (width - SCROLLBAR_WIDTH), mouseEvent.getY());
0704: } else if ((active == HORSCROLLBAR)) {
0705: hsb.handleMouseEvent(mouseEvent.getID(), mouseEvent
0706: .getModifiers(), mouseEvent.getX(), mouseEvent
0707: .getY()
0708: - (height - SCROLLBAR_WIDTH));
0709: } else if (active == WINDOW) {
0710: int i = y2index(mouseEvent.getY());
0711: if (multipleSelections) {
0712: // Multi-select only:
0713: // If a selected item was pressed on and then dragged off
0714: // of, cancel the pending deselect.
0715: if (eventType == ItemEvent.DESELECTED) {
0716: if (i != eventIndex) {
0717: eventType = NONE;
0718: eventIndex = -1;
0719: }
0720: }
0721: } else if (eventType == ItemEvent.SELECTED) {
0722: // Single-select only:
0723: // If an unselected item was pressed on, track the drag
0724: // and select the item under the mouse
0725:
0726: // See 6243382 for more information
0727: trackMouseDraggedScroll(mouseEvent);
0728:
0729: if (i >= 0 && !isSelected(i)) {
0730: int oldSel = eventIndex;
0731: selectItem(i);
0732: eventIndex = i;
0733: repaint(oldSel, eventIndex, PAINT_ITEMS);
0734: }
0735: }
0736: // Restoring Windows behaviour
0737: // We should update focus index after "mouse dragged" event
0738: if (i >= 0) {
0739: setFocusIndex(i);
0740: repaint(PAINT_FOCUS);
0741: }
0742: }
0743: }
0744: }
0745:
0746: /*
0747: * Helper method for XListPeer with integrated vertical scrollbar.
0748: * Start or stop vertical scrolling when mouse dragged in / out the area of the list if it's required
0749: * Restoring Motif behavior
0750: * See 6243382 for more information
0751: */
0752: void trackMouseDraggedScroll(MouseEvent mouseEvent) {
0753:
0754: if (vsb.beforeThumb(mouseEvent.getX(), mouseEvent.getY())) {
0755: vsb.setMode(AdjustmentEvent.UNIT_DECREMENT);
0756: } else {
0757: vsb.setMode(AdjustmentEvent.UNIT_INCREMENT);
0758: }
0759:
0760: if (mouseEvent.getY() < 0 || mouseEvent.getY() >= listHeight) {
0761: if (!mouseDraggedOutVertically) {
0762: mouseDraggedOutVertically = true;
0763: vsb.startScrollingInstance();
0764: }
0765: } else {
0766: if (mouseDraggedOutVertically) {
0767: mouseDraggedOutVertically = false;
0768: vsb.stopScrollingInstance();
0769: }
0770: }
0771:
0772: if (hsb.beforeThumb(mouseEvent.getX(), mouseEvent.getY())) {
0773: hsb.setMode(AdjustmentEvent.UNIT_DECREMENT);
0774: } else {
0775: hsb.setMode(AdjustmentEvent.UNIT_INCREMENT);
0776: }
0777:
0778: if (mouseEvent.getX() < 0 || mouseEvent.getX() >= listWidth) {
0779: if (!mouseDraggedOutHorizontally) {
0780: mouseDraggedOutHorizontally = true;
0781: hsb.startScrollingInstance();
0782: }
0783: } else {
0784: if (mouseDraggedOutHorizontally) {
0785: mouseDraggedOutHorizontally = false;
0786: hsb.stopScrollingInstance();
0787: }
0788: }
0789: }
0790:
0791: /*
0792: * Helper method for XListPeer with integrated vertical scrollbar.
0793: * Stop vertical scrolling when mouse released in / out the area of the list if it's required
0794: * Restoring Motif behavior
0795: * see 6243382 for more information
0796: */
0797: void trackMouseReleasedScroll() {
0798:
0799: if (mouseDraggedOutVertically) {
0800: mouseDraggedOutVertically = false;
0801: vsb.stopScrollingInstance();
0802: }
0803:
0804: if (mouseDraggedOutHorizontally) {
0805: mouseDraggedOutHorizontally = false;
0806: hsb.stopScrollingInstance();
0807: }
0808: }
0809:
0810: void handleJavaKeyEvent(KeyEvent e) {
0811: switch (e.getID()) {
0812: case KeyEvent.KEY_PRESSED:
0813: if (!isMousePressed) {
0814: keyPressed(e);
0815: }
0816: break;
0817: }
0818: }
0819:
0820: void keyPressed(KeyEvent e) {
0821: int keyCode = e.getKeyCode();
0822: if (log.isLoggable(Level.FINE))
0823: log.fine(e.toString());
0824: switch (keyCode) {
0825: case KeyEvent.VK_UP:
0826: case KeyEvent.VK_KP_UP: // TODO: I assume we also want this, too
0827: if (getFocusIndex() > 0) {
0828: setFocusIndex(getFocusIndex() - 1);
0829: repaint(PAINT_HIDEFOCUS);
0830: // If single-select, select the item
0831: if (!multipleSelections) {
0832: selectItem(getFocusIndex());
0833: postEvent(new ItemEvent((List) target,
0834: ItemEvent.ITEM_STATE_CHANGED, Integer
0835: .valueOf(getFocusIndex()),
0836: ItemEvent.SELECTED));
0837: }
0838: if (isItemHidden(getFocusIndex())) {
0839: makeVisible(getFocusIndex());
0840: } else {
0841: repaint(PAINT_FOCUS);
0842: }
0843: }
0844: break;
0845: case KeyEvent.VK_DOWN:
0846: case KeyEvent.VK_KP_DOWN: // TODO: I assume we also want this, too
0847: if (getFocusIndex() < items.size() - 1) {
0848: setFocusIndex(getFocusIndex() + 1);
0849: repaint(PAINT_HIDEFOCUS);
0850: // If single-select, select the item
0851: if (!multipleSelections) {
0852: selectItem(getFocusIndex());
0853: postEvent(new ItemEvent((List) target,
0854: ItemEvent.ITEM_STATE_CHANGED, Integer
0855: .valueOf(getFocusIndex()),
0856: ItemEvent.SELECTED));
0857: }
0858: if (isItemHidden(getFocusIndex())) {
0859: makeVisible(getFocusIndex());
0860: } else {
0861: repaint(PAINT_FOCUS);
0862: }
0863: }
0864: break;
0865: case KeyEvent.VK_PAGE_UP: {
0866: // Assumes that scrollbar does its own bounds-checking
0867: int previousValue = vsb.getValue();
0868: vsb.setValue(vsb.getValue() - vsb.getBlockIncrement());
0869: int currentValue = vsb.getValue();
0870: // 6190768 pressing pg-up on AWT multiple selection lists the items but no item event is triggered, on XToolkit
0871: // Restoring Motif behavior
0872: if (previousValue != currentValue) {
0873: setFocusIndex(Math.max(getFocusIndex()
0874: - itemsInWindow(), 0));
0875: if (!multipleSelections) {
0876: selectItem(getFocusIndex());
0877: postEvent(new ItemEvent((List) target,
0878: ItemEvent.ITEM_STATE_CHANGED, Integer
0879: .valueOf(getFocusIndex()),
0880: ItemEvent.SELECTED));
0881: }
0882: }
0883: repaint();
0884: break;
0885: }
0886: case KeyEvent.VK_PAGE_DOWN: {
0887: // Assumes that scrollbar does its own bounds-checking
0888: int previousValue = vsb.getValue();
0889: vsb.setValue(vsb.getValue() + vsb.getBlockIncrement());
0890: int currentValue = vsb.getValue();
0891: // 6190768 pressing pg-down on AWT multiple selection list selects the items but no item event is triggered, on XToolkit
0892: // Restoring Motif behavior
0893: if (previousValue != currentValue) {
0894: setFocusIndex(Math.min(getFocusIndex()
0895: + itemsInWindow(), items.size() - 1));
0896: if (!multipleSelections) {
0897: selectItem(getFocusIndex());
0898: postEvent(new ItemEvent((List) target,
0899: ItemEvent.ITEM_STATE_CHANGED, Integer
0900: .valueOf(getFocusIndex()),
0901: ItemEvent.SELECTED));
0902: }
0903: }
0904: repaint();
0905: break;
0906: }
0907: case KeyEvent.VK_LEFT:
0908: case KeyEvent.VK_KP_LEFT:
0909: if (hsbVis & hsb.getValue() > 0) {
0910: hsb.setValue(hsb.getValue() - HORIZ_SCROLL_AMT);
0911: repaint();
0912: }
0913: break;
0914: case KeyEvent.VK_RIGHT:
0915: case KeyEvent.VK_KP_RIGHT:
0916: if (hsbVis) { // Should check if already at end
0917: hsb.setValue(hsb.getValue() + HORIZ_SCROLL_AMT);
0918: repaint();
0919: }
0920: break;
0921: // 6190778 CTRL + HOME, CTRL + END keys do not work properly for list on XToolkit
0922: // Restoring Motif behavior
0923: case KeyEvent.VK_HOME:
0924: if (!e.isControlDown()
0925: || ((List) target).getItemCount() <= 0)
0926: break;
0927: if (vsbVis) {
0928: vsb.setValue(vsb.getMinimum());
0929: }
0930: setFocusIndex(0);
0931: if (!multipleSelections) {
0932: selectItem(getFocusIndex());
0933: postEvent(new ItemEvent((List) target,
0934: ItemEvent.ITEM_STATE_CHANGED, Integer
0935: .valueOf(getFocusIndex()),
0936: ItemEvent.SELECTED));
0937: }
0938: repaint();
0939: break;
0940: case KeyEvent.VK_END:
0941: if (!e.isControlDown()
0942: || ((List) target).getItemCount() <= 0)
0943: break;
0944: if (vsbVis) {
0945: vsb.setValue(vsb.getMaximum());
0946: }
0947: setFocusIndex(items.size() - 1);
0948: if (!multipleSelections) {
0949: selectItem(getFocusIndex());
0950: postEvent(new ItemEvent((List) target,
0951: ItemEvent.ITEM_STATE_CHANGED, Integer
0952: .valueOf(getFocusIndex()),
0953: ItemEvent.SELECTED));
0954: }
0955: repaint();
0956: break;
0957: case KeyEvent.VK_SPACE:
0958: // Fixed 6299853: XToolkit: Pressing space triggers ItemStateChanged event after List.removeAll called
0959: // If getFocusIndex() is less than 0, the event will not be triggered when space pressed
0960: if (getFocusIndex() < 0
0961: || ((List) target).getItemCount() <= 0) {
0962: break;
0963: }
0964:
0965: boolean isSelected = isSelected(getFocusIndex());
0966:
0967: // Spacebar only deselects for multi-select Lists
0968: if (multipleSelections && isSelected) {
0969: deselectItem(getFocusIndex());
0970: postEvent(new ItemEvent((List) target,
0971: ItemEvent.ITEM_STATE_CHANGED, Integer
0972: .valueOf(getFocusIndex()),
0973: ItemEvent.DESELECTED));
0974: } else if (!isSelected) { // Note: this changes the Solaris/Linux
0975: // behavior to match that of win32.
0976: // That is, pressing space bar on a
0977: // single-select list when the focused
0978: // item is already selected does NOT
0979: // send an ItemEvent.SELECTED event.
0980: selectItem(getFocusIndex());
0981: postEvent(new ItemEvent((List) target,
0982: ItemEvent.ITEM_STATE_CHANGED, Integer
0983: .valueOf(getFocusIndex()),
0984: ItemEvent.SELECTED));
0985: }
0986: break;
0987: case KeyEvent.VK_ENTER:
0988: // It looks to me like there are bugs as well as inconsistencies
0989: // in the way the Enter key is handled by both Solaris and Windows.
0990: // So for now in XAWT, I'm going to simply go by what the List docs
0991: // say: "AWT also generates an action event when the user presses
0992: // the return key while an item in the list is selected."
0993: if (selected.length > 0) {
0994: postEvent(new ActionEvent((List) target,
0995: ActionEvent.ACTION_PERFORMED, (String) items
0996: .elementAt(getFocusIndex()), e
0997: .getWhen(), e.getModifiers())); // ActionEvent doesn't have
0998: // extended modifiers.
0999: }
1000: break;
1001: }
1002: }
1003:
1004: /**
1005: * return value from the scrollbar
1006: */
1007: public void notifyValue(XScrollbar obj, int type, int v,
1008: boolean isAdjusting) {
1009:
1010: if (log.isLoggable(Level.FINE))
1011: log.fine("Notify value changed on " + obj + " to " + v);
1012: int value = obj.getValue();
1013: if (obj == vsb) {
1014: scrollVertical(v - value);
1015:
1016: // See 6243382 for more information
1017: int oldSel = eventIndex;
1018: int newSel = eventIndex + v - value;
1019: if (mouseDraggedOutVertically && !isSelected(newSel)) {
1020: selectItem(newSel);
1021: eventIndex = newSel;
1022: repaint(oldSel, eventIndex, PAINT_ITEMS);
1023: // Scrolling select() should also set the focus index
1024: // Otherwise, the updating of the 'focusIndex' variable will be incorrect
1025: // if user drag mouse out of the area of the list
1026: setFocusIndex(newSel);
1027: repaint(PAINT_FOCUS);
1028: }
1029:
1030: } else if ((XHorizontalScrollbar) obj == hsb) {
1031: scrollHorizontal(v - value);
1032: }
1033:
1034: }
1035:
1036: /**
1037: * deselect all items in List
1038: */
1039: private void deselectAllItems() {
1040: selected = new int[0];
1041: repaint(PAINT_ITEMS);
1042: }
1043:
1044: /**
1045: * set multiple selections
1046: */
1047: public void setMultipleSelections(boolean v) {
1048: if (multipleSelections != v) {
1049: if (!v) {
1050: int selPos = (isSelected(focusIndex)) ? focusIndex : -1;
1051: deselectAllItems();
1052: if (selPos != -1) {
1053: selectItem(selPos);
1054: }
1055: }
1056: multipleSelections = v;
1057: }
1058: }
1059:
1060: /**
1061: * add an item
1062: * if the index of the item is < 0 or >= than items.size()
1063: * then add the item to the end of the list
1064: */
1065: public void addItem(String item, int i) {
1066: int oldMaxLength = maxLength;
1067: boolean hsbWasVis = hsbVis;
1068: boolean vsbWasVis = vsbVis;
1069:
1070: int addedIndex = 0; // Index where the new item ended up
1071: if (i < 0 || i >= items.size()) {
1072: i = -1;
1073: }
1074:
1075: // Why we set this variable to -1 in spite of the fact that selected[] is changed in other way?
1076: // It's not clear how to reproduce incorrect behaviour based on this assignment
1077: // since before using this variable (mouseReleased) we certainly update it to correct value
1078: // So we don't modify this behaviour now
1079: currentIndex = -1;
1080:
1081: if (i == -1) {
1082: items.addElement(item);
1083: i = 0; // fix the math for the paintItems test
1084: addedIndex = items.size() - 1;
1085: } else {
1086: items.insertElementAt(item, i);
1087: addedIndex = i;
1088: for (int j = 0; j < selected.length; j++) {
1089: if (selected[j] >= i) {
1090: selected[j] += 1;
1091: }
1092: }
1093: }
1094: if (log.isLoggable(Level.FINER))
1095: log.finer("Adding item '" + item + "' to " + addedIndex);
1096:
1097: // Update maxLength
1098: boolean repaintItems = !isItemHidden(addedIndex);
1099: maxLength = Math.max(maxLength, getItemWidth(addedIndex));
1100: layout();
1101:
1102: int options = 0;
1103: if (vsbVis != vsbWasVis || hsbVis != hsbWasVis) {
1104: // Scrollbars are being added or removed, so we must repaint all
1105: options = PAINT_ALL;
1106: } else {
1107: options = (repaintItems ? (PAINT_ITEMS) : 0)
1108: | ((maxLength != oldMaxLength || (hsbWasVis ^ hsbVis)) ? (PAINT_HSCROLL)
1109: : 0)
1110: | ((vsb.needsRepaint()) ? (PAINT_VSCROLL) : 0);
1111:
1112: }
1113: if (log.isLoggable(Level.FINEST))
1114: log.finest("Last visible: " + getLastVisibleItem()
1115: + ", hsb changed : " + (hsbWasVis ^ hsbVis)
1116: + ", items changed " + repaintItems);
1117: repaint(addedIndex, getLastVisibleItem(), options);
1118: }
1119:
1120: /**
1121: * delete items starting with s (start position) to e (end position) including s and e
1122: * if s < 0 then s = 0
1123: * if e >= items.size() then e = items.size() - 1
1124: */
1125: public void delItems(int s, int e) {
1126: // save the current state of the scrollbars
1127: boolean hsbWasVisible = hsbVis;
1128: boolean vsbWasVisible = vsbVis;
1129: int oldLastDisplayed = lastItemDisplayed();
1130:
1131: if (log.isLoggable(Level.FINE))
1132: log.fine("Deleting from " + s + " to " + e);
1133:
1134: if (log.isLoggable(Level.FINEST))
1135: log.finest("Last displayed item: " + oldLastDisplayed
1136: + ", items in window " + itemsInWindow()
1137: + ", size " + items.size());
1138:
1139: if (items.size() == 0) {
1140: return;
1141: }
1142:
1143: // if user passed in flipped args, reverse them
1144: if (s > e) {
1145: int tmp = s;
1146: s = e;
1147: e = tmp;
1148: }
1149:
1150: // check for starting point less than zero
1151: if (s < 0) {
1152: s = 0;
1153: }
1154:
1155: // check for end point greater than the size of the list
1156: if (e >= items.size()) {
1157: e = items.size() - 1;
1158: }
1159:
1160: // determine whether we're going to delete any visible elements
1161: // repaint must also be done if scrollbars appear/disappear, which
1162: // can happen from removing a non-showing list item
1163: /*
1164: boolean repaintNeeded =
1165: ((s <= lastItemDisplayed()) && (e >= vsb.getValue()));
1166: */
1167: boolean repaintNeeded = (s >= getFirstVisibleItem() && s <= getLastVisibleItem());
1168:
1169: // delete the items out of the items list and out of the selected list
1170: for (int i = s; i <= e; i++) {
1171: items.removeElementAt(s);
1172: int j = posInSel(i);
1173: if (j != -1) {
1174: int newsel[] = new int[selected.length - 1];
1175: System.arraycopy(selected, 0, newsel, 0, j);
1176: System.arraycopy(selected, j + 1, newsel, j,
1177: selected.length - (j + 1));
1178: selected = newsel;
1179: }
1180:
1181: }
1182:
1183: // update the indexes in the selected array
1184: int diff = (e - s) + 1;
1185: for (int i = 0; i < selected.length; i++) {
1186: if (selected[i] > e) {
1187: selected[i] -= diff;
1188: }
1189: }
1190:
1191: int options = PAINT_VSCROLL;
1192: // focusedIndex updating according to native (Window, Motif) behaviour
1193: if (getFocusIndex() > e) {
1194: setFocusIndex(getFocusIndex() - (e - s + 1));
1195: options |= PAINT_FOCUS;
1196: } else if (getFocusIndex() >= s && getFocusIndex() <= e) {
1197: // Fixed 6299858: PIT. Focused border not shown on List if selected item is removed, XToolkit
1198: // We should set focus to new first item if the current first item was removed
1199: // except if the list is empty
1200: int focusBound = (items.size() > 0) ? 0 : -1;
1201: setFocusIndex(Math.max(s - 1, focusBound));
1202: options |= PAINT_FOCUS;
1203: }
1204:
1205: if (log.isLoggable(Level.FINEST))
1206: log.finest("Multiple selections: " + multipleSelections);
1207:
1208: // update vsb.val
1209: if (vsb.getValue() >= s) {
1210: if (vsb.getValue() <= e) {
1211: vsb.setValue(e + 1 - diff);
1212: } else {
1213: vsb.setValue(vsb.getValue() - diff);
1214: }
1215: }
1216:
1217: int oldMaxLength = maxLength;
1218: maxLength = maxLength();
1219: if (maxLength != oldMaxLength) {
1220: // Width of the items changed affecting the range of
1221: // horizontal scrollbar
1222: options |= PAINT_HSCROLL;
1223: }
1224: layout();
1225: repaintNeeded |= (vsbWasVisible ^ vsbVis)
1226: || (hsbWasVisible ^ hsbVis); // If scrollbars visibility changed
1227: if (repaintNeeded) {
1228: options |= PAINT_ALL;
1229: }
1230: repaint(s, oldLastDisplayed, options);
1231: }
1232:
1233: /**
1234: * ListPeer method
1235: */
1236: public void select(int index) {
1237: // Programmatic select() should also set the focus index
1238: setFocusIndex(index);
1239: repaint(PAINT_FOCUS);
1240: selectItem(index);
1241: }
1242:
1243: /**
1244: * select the index
1245: * redraw the list to the screen
1246: */
1247: void selectItem(int index) {
1248: // NOTE: instead of recalculating and the calling repaint(), painting
1249: // is done immediately
1250:
1251: // 6190746 List does not trigger ActionEvent when double clicking a programmatically selected item, XToolkit
1252: // If we invoke select(int) before setVisible(boolean), then variable currentIndex will equals -1. At the same time isSelected may be true.
1253: // Restoring Motif behavior
1254: currentIndex = index;
1255:
1256: if (isSelected(index)) {
1257: return;
1258: }
1259: if (!multipleSelections) {
1260: if (selected.length == 0) { // No current selection
1261: selected = new int[1];
1262: selected[0] = index;
1263: } else {
1264: int oldSel = selected[0];
1265: selected[0] = index;
1266: if (!isItemHidden(oldSel)) {
1267: // Only bother painting if item is visible (4895367)
1268: repaint(oldSel, oldSel, PAINT_ITEMS);
1269: }
1270: }
1271: } else {
1272: // insert "index" into the selection array
1273: int newsel[] = new int[selected.length + 1];
1274: int i = 0;
1275: while (i < selected.length && index > selected[i]) {
1276: newsel[i] = selected[i];
1277: i++;
1278: }
1279: newsel[i] = index;
1280: System.arraycopy(selected, i, newsel, i + 1,
1281: selected.length - i);
1282: selected = newsel;
1283: }
1284: if (!isItemHidden(index)) {
1285: // Only bother painting if item is visible (4895367)
1286: repaint(index, index, PAINT_ITEMS);
1287: }
1288: }
1289:
1290: /**
1291: * ListPeer method
1292: * focusedIndex isn't updated according to native (Window, Motif) behaviour
1293: */
1294: public void deselect(int index) {
1295: deselectItem(index);
1296: }
1297:
1298: /**
1299: * deselect the index
1300: * redraw the list to the screen
1301: */
1302: void deselectItem(int index) {
1303: if (!isSelected(index)) {
1304: return;
1305: }
1306: if (!multipleSelections) {
1307: // TODO: keep an int[0] and int[1] around and just use them instead
1308: // creating new ones all the time
1309: selected = new int[0];
1310: } else {
1311: int i = posInSel(index);
1312: int newsel[] = new int[selected.length - 1];
1313: System.arraycopy(selected, 0, newsel, 0, i);
1314: System.arraycopy(selected, i + 1, newsel, i,
1315: selected.length - (i + 1));
1316: selected = newsel;
1317: }
1318: currentIndex = index;
1319: if (!isItemHidden(index)) {
1320: // Only bother repainting if item is visible
1321: repaint(index, index, PAINT_ITEMS);
1322: }
1323: }
1324:
1325: /**
1326: * ensure that the given index is visible, scrolling the List
1327: * if necessary, or doing nothing if the item is already visible.
1328: * The List must be repainted for changes to be visible.
1329: */
1330: public void makeVisible(int index) {
1331: if (index < 0 || index >= items.size()) {
1332: return;
1333: }
1334: if (isItemHidden(index)) { // Do I really need to call this?
1335: // If index is above the top, scroll up
1336: if (index < vsb.getValue()) {
1337: scrollVertical(index - vsb.getValue());
1338: }
1339: // If index is below the bottom, scroll down
1340: else if (index > lastItemDisplayed()) {
1341: int val = index - lastItemDisplayed();
1342: scrollVertical(val);
1343: }
1344: }
1345: }
1346:
1347: /**
1348: * clear
1349: */
1350: public void clear() {
1351: selected = new int[0];
1352: items = new Vector();
1353: currentIndex = -1;
1354: // Fixed 6291736: ITEM_STATE_CHANGED triggered after List.removeAll(), XToolkit
1355: // We should update 'focusIndex' variable more carefully
1356: setFocusIndex(-1);
1357: vsb.setValue(0);
1358: maxLength = 0;
1359: layout();
1360: repaint();
1361: }
1362:
1363: /**
1364: * return the selected indexes
1365: */
1366: public int[] getSelectedIndexes() {
1367: return selected;
1368: }
1369:
1370: /**
1371: * return the y value of the given index "i".
1372: * the y value represents the top of the text
1373: * NOTE: index can be larger than items.size as long
1374: * as it can fit the window
1375: */
1376: int index2y(int index) {
1377: int h = getItemHeight();
1378:
1379: //if (index < vsb.getValue() || index > vsb.getValue() + itemsInWindow()) {
1380: return MARGIN + ((index - vsb.getValue()) * h) + SPACE;
1381: }
1382:
1383: /* return true if the y is a valid y coordinate for
1384: * a VISIBLE list item, otherwise returns false
1385: */
1386: boolean validY(int y) {
1387:
1388: int shown = itemsDisplayed();
1389: int lastY = shown * getItemHeight() + MARGIN;
1390:
1391: if (shown == itemsInWindow()) {
1392: lastY += MARGIN;
1393: }
1394:
1395: if (y < 0 || y >= lastY) {
1396: return false;
1397: }
1398:
1399: return true;
1400: }
1401:
1402: /**
1403: * return the position of the index in the selected array
1404: * if the index isn't in the array selected return -1;
1405: */
1406: int posInSel(int index) {
1407: for (int i = 0; i < selected.length; i++) {
1408: if (index == selected[i]) {
1409: return i;
1410: }
1411: }
1412: return -1;
1413: }
1414:
1415: boolean isIndexDisplayed(int idx) {
1416: int lastDisplayed = lastItemDisplayed();
1417:
1418: return idx <= lastDisplayed
1419: && idx >= Math.max(0, lastDisplayed - itemsInWindow()
1420: + 1);
1421: }
1422:
1423: /**
1424: * returns index of last item displayed in the List
1425: */
1426: int lastItemDisplayed() {
1427: int n = itemsInWindow();
1428: return (Math.min(items.size() - 1, (vsb.getValue() + n) - 1));
1429: }
1430:
1431: /**
1432: * returns whether the given index is currently scrolled off the top or
1433: * bottom of the List.
1434: */
1435: boolean isItemHidden(int index) {
1436: return index < vsb.getValue()
1437: || index >= vsb.getValue() + itemsInWindow();
1438: }
1439:
1440: /**
1441: * returns the width of the list portion of the component (accounts for
1442: * presence of vertical scrollbar)
1443: */
1444: int getListWidth() {
1445: return vsbVis ? width - SCROLLBAR_AREA : width;
1446: }
1447:
1448: /**
1449: * returns number of items actually displayed in the List
1450: */
1451: int itemsDisplayed() {
1452:
1453: return (Math
1454: .min(items.size() - vsb.getValue(), itemsInWindow()));
1455:
1456: }
1457:
1458: /**
1459: * scrollVertical
1460: * y is the number of items to scroll
1461: */
1462: void scrollVertical(int y) {
1463: if (log.isLoggable(Level.FINE))
1464: log.fine("Scrolling vertically by " + y);
1465: int itemsInWin = itemsInWindow();
1466: int h = getItemHeight();
1467: int pixelsToScroll = y * h;
1468:
1469: if (vsb.getValue() < -y) {
1470: y = -vsb.getValue();
1471: }
1472: vsb.setValue(vsb.getValue() + y);
1473:
1474: if (y > 0) {
1475: // Fixed 6308295: XAWTduplicate list item is displayed
1476: // Window resizing leads to the buffer flushing
1477: // That's why the repainting with the PAINT_HIDEFOCUS option is the repainting with PAINT_ALL option
1478: // So we should do only the repainting instead of the copy area
1479: if (y < itemsInWin && painter.isBuffer()) {
1480: if (log.isLoggable(Level.FINEST)) {
1481: log.finest("Copying " + "" + MARGIN + ","
1482: + (MARGIN + pixelsToScroll) + ","
1483: + (width - SCROLLBAR_AREA) + ","
1484: + (h * (itemsInWin - y) - 1) + "," + 0
1485: + "," + (-pixelsToScroll));
1486: }
1487: // Unpaint focus before copying
1488: repaint(PAINT_HIDEFOCUS);
1489: painter.copyArea(MARGIN, MARGIN + pixelsToScroll, width
1490: - SCROLLBAR_AREA, h * (itemsInWin - y - 1) - 1,
1491: 0, -pixelsToScroll);
1492: }
1493: repaint(vsb.getValue() + (itemsInWin - y) - 1, (vsb
1494: .getValue() + itemsInWin) - 1, PAINT_ITEMS
1495: | PAINT_VSCROLL | PAINT_FOCUS);
1496: } else if (y < 0 && painter.isBuffer()) {
1497: if (y + itemsInWindow() > 0) {
1498: if (log.isLoggable(Level.FINEST)) {
1499: log.finest("Copying " + MARGIN + "," + MARGIN + ","
1500: + (width - SCROLLBAR_AREA) + ","
1501: + (h * (itemsInWin + y)) + "," + "0" + ","
1502: + (-pixelsToScroll));
1503: }
1504: repaint(PAINT_HIDEFOCUS);
1505: painter.copyArea(MARGIN, MARGIN,
1506: width - SCROLLBAR_AREA, h * (itemsInWin + y),
1507: 0, -pixelsToScroll);
1508: }
1509: int e = Math.min(getLastVisibleItem(), vsb.getValue() + -y);
1510: repaint(vsb.getValue(), e, PAINT_ITEMS | PAINT_VSCROLL
1511: | PAINT_FOCUS);
1512: }
1513: }
1514:
1515: /**
1516: * scrollHorizontal
1517: * x is the number of pixels to scroll
1518: */
1519: void scrollHorizontal(int x) {
1520: if (log.isLoggable(Level.FINE))
1521: log.fine("Scrolling horizontally by " + y);
1522: int w = getListWidth();
1523: w -= ((2 * SPACE) + (2 * MARGIN));
1524: int h = height - (SCROLLBAR_AREA + (2 * MARGIN));
1525: hsb.setValue(hsb.getValue() + x);
1526:
1527: if (x < 0 && painter.isBuffer()) {
1528: painter.copyArea(MARGIN + SPACE, MARGIN, w + x, h, -x, 0);
1529: } else if (x > 0 && painter.isBuffer()) {
1530: painter.copyArea(MARGIN + SPACE + x, MARGIN, w - x, h, -x,
1531: 0);
1532: }
1533: repaint(vsb.getValue(), lastItemDisplayed(), PAINT_ITEMS
1534: | PAINT_HSCROLL);
1535: }
1536:
1537: /**
1538: * return the index
1539: */
1540: int y2index(int y) {
1541: if (!validY(y)) {
1542: return -1;
1543: }
1544:
1545: int i = (y - MARGIN) / getItemHeight() + vsb.getValue();
1546: int last = lastItemDisplayed();
1547:
1548: if (i > last) {
1549: i = last;
1550: }
1551:
1552: return i;
1553:
1554: }
1555:
1556: /**
1557: * is the index "index" selected
1558: */
1559: boolean isSelected(int index) {
1560: if (eventType == ItemEvent.SELECTED && index == eventIndex) {
1561: return true;
1562: }
1563: for (int i = 0; i < selected.length; i++) {
1564: if (selected[i] == index) {
1565: return true;
1566: }
1567: }
1568: return false;
1569: }
1570:
1571: /**
1572: * return the number of items that can fit
1573: * in the current window
1574: */
1575: int itemsInWindow(boolean scrollbarVisible) {
1576: int h;
1577: if (scrollbarVisible) {
1578: h = height - ((2 * MARGIN) + SCROLLBAR_AREA);
1579: } else {
1580: h = height - 2 * MARGIN;
1581: }
1582: return (h / getItemHeight());
1583: }
1584:
1585: int itemsInWindow() {
1586: return itemsInWindow(hsbVis);
1587: }
1588:
1589: /**
1590: * return true if the x and y position is in the horizontal scrollbar
1591: */
1592: boolean inHorizontalScrollbar(int x, int y) {
1593: int w = getListWidth();
1594: int h = height - SCROLLBAR_WIDTH;
1595: return (hsbVis && (x >= 0) && (x <= w) && (y > h));
1596: }
1597:
1598: /**
1599: * return true if the x and y position is in the verticalscrollbar
1600: */
1601: boolean inVerticalScrollbar(int x, int y) {
1602: int w = width - SCROLLBAR_WIDTH;
1603: int h = hsbVis ? height - SCROLLBAR_AREA : height;
1604: return (vsbVis && (x > w) && (y >= 0) && (y <= h));
1605: }
1606:
1607: /**
1608: * return true if the x and y position is in the window
1609: */
1610: boolean inWindow(int x, int y) {
1611: int w = getListWidth();
1612: int h = hsbVis ? height - SCROLLBAR_AREA : height;
1613: return ((x >= 0) && (x <= w)) && ((y >= 0) && (y <= h));
1614: }
1615:
1616: /**
1617: * return true if vertical scrollbar is visible and false otherwise;
1618: * hsbVisible is the visibility of the horizontal scrollbar
1619: */
1620: boolean vsbIsVisible(boolean hsbVisible) {
1621: return (items.size() > itemsInWindow(hsbVisible));
1622: }
1623:
1624: /**
1625: * return true if horizontal scrollbar is visible and false otherwise;
1626: * vsbVisible is the visibility of the vertical scrollbar
1627: */
1628: boolean hsbIsVisible(boolean vsbVisible) {
1629: int w = width
1630: - ((2 * SPACE) + (2 * MARGIN) + (vsbVisible ? SCROLLBAR_AREA
1631: : 0));
1632: return (maxLength > w);
1633: }
1634:
1635: /*
1636: * Returns true if the event has been handled and should not be
1637: * posted to Java
1638: */
1639: boolean prePostEvent(final AWTEvent e) {
1640: if (e instanceof MouseEvent) {
1641: return prePostMouseEvent((MouseEvent) e);
1642: }
1643: return super .prePostEvent(e);
1644: }
1645:
1646: /*
1647: * Fixed 6240151: XToolkit: Dragging the List scrollbar initiates DnD
1648: * To be compatible with Motif, MouseEvent originated on the scrollbar
1649: * should be sent into Java in this way:
1650: * - post: MOUSE_ENTERED, MOUSE_EXITED, MOUSE_MOVED
1651: * - don't post: MOUSE_PRESSED, MOUSE_RELEASED, MOUSE_CLICKED, MOUSE_DRAGGED
1652: */
1653: boolean prePostMouseEvent(final MouseEvent me) {
1654: if (getToplevelXWindow().isModalBlocked()) {
1655: return false;
1656: }
1657:
1658: int eventId = me.getID();
1659:
1660: if (eventId == MouseEvent.MOUSE_MOVED) {
1661: // only for performance improvement
1662: } else if ((eventId == MouseEvent.MOUSE_DRAGGED || eventId == MouseEvent.MOUSE_RELEASED)
1663: && isScrollBarOriginated) {
1664: if (eventId == MouseEvent.MOUSE_RELEASED) {
1665: isScrollBarOriginated = false;
1666: }
1667: handleJavaMouseEventOnEDT(me);
1668: return true;
1669: } else if ((eventId == MouseEvent.MOUSE_PRESSED || eventId == MouseEvent.MOUSE_CLICKED)
1670: && (inVerticalScrollbar(me.getX(), me.getY()) || inHorizontalScrollbar(
1671: me.getX(), me.getY()))) {
1672: if (eventId == MouseEvent.MOUSE_PRESSED) {
1673: isScrollBarOriginated = true;
1674: }
1675: handleJavaMouseEventOnEDT(me);
1676: return true;
1677: }
1678: return false;
1679: }
1680:
1681: /*
1682: * Do handleJavaMouseEvent on EDT
1683: */
1684: void handleJavaMouseEventOnEDT(final MouseEvent me) {
1685: EventQueue.invokeLater(new Runnable() {
1686: public void run() {
1687: handleJavaMouseEvent(me);
1688: }
1689: });
1690: }
1691:
1692: /*
1693: * Fixed 5010944: List's rows overlap one another
1694: * The bug is due to incorrent caching of the list item size
1695: * So we should recalculate font metrics on setFont
1696: */
1697: public void setFont(Font f) {
1698: super .setFont(f);
1699: initFontMetrics();
1700: layout();
1701: repaint();
1702: }
1703:
1704: /**
1705: * Sometimes painter is called on Toolkit thread, so the lock sequence is:
1706: * awtLock -> Painter -> awtLock
1707: * Sometimes it is called on other threads:
1708: * Painter -> awtLock
1709: * Since we can't guarantee the sequence, use awtLock.
1710: */
1711: class ListPainter {
1712: // TODO: use VolatileImage
1713: VolatileImage buffer;
1714: Color[] colors;
1715:
1716: private Color getListForeground() {
1717: if (fgColorSet) {
1718: return colors[FOREGROUND_COLOR];
1719: } else {
1720: return SystemColor.textText;
1721: }
1722: }
1723:
1724: private Color getListBackground() {
1725: if (bgColorSet) {
1726: return colors[BACKGROUND_COLOR];
1727: } else {
1728: return SystemColor.text;
1729: }
1730: }
1731:
1732: private Color getDisabledColor() {
1733: Color backgroundColor = getListBackground();
1734: Color foregroundColor = getListForeground();
1735: return (backgroundColor.equals(Color.BLACK)) ? foregroundColor
1736: .darker()
1737: : backgroundColor.darker();
1738: }
1739:
1740: private boolean createBuffer() {
1741: VolatileImage localBuffer = null;
1742: XToolkit.awtLock();
1743: try {
1744: localBuffer = buffer;
1745: } finally {
1746: XToolkit.awtUnlock();
1747: }
1748:
1749: if (localBuffer == null) {
1750: if (log.isLoggable(Level.FINE))
1751: log.fine("Creating buffer " + width + "x" + height);
1752: // use GraphicsConfig.cCVI() instead of Component.cVI(),
1753: // because the latter may cause a deadlock with the tree lock
1754: localBuffer = graphicsConfig
1755: .createCompatibleVolatileImage(width + 1,
1756: height + 1);
1757: }
1758: XToolkit.awtLock();
1759: try {
1760: if (buffer == null) {
1761: buffer = localBuffer;
1762: return true;
1763: }
1764: } finally {
1765: XToolkit.awtUnlock();
1766: }
1767: return false;
1768: }
1769:
1770: public void invalidate() {
1771: XToolkit.awtLock();
1772: try {
1773: if (buffer != null) {
1774: buffer.flush();
1775: }
1776: buffer = null;
1777: } finally {
1778: XToolkit.awtUnlock();
1779: }
1780: }
1781:
1782: private void paint(Graphics listG, int firstItem, int lastItem,
1783: int options) {
1784: if (log.isLoggable(Level.FINER))
1785: log.finer("Repaint from " + firstItem + " to "
1786: + lastItem + " options " + options);
1787: if (firstItem > lastItem) {
1788: int t = lastItem;
1789: lastItem = firstItem;
1790: firstItem = t;
1791: }
1792: if (firstItem < 0) {
1793: firstItem = 0;
1794: }
1795: colors = getGUIcolors();
1796: VolatileImage localBuffer = null;
1797: do {
1798: XToolkit.awtLock();
1799: try {
1800: if (createBuffer()) {
1801: // First time created buffer should be painted over at full.
1802: options = PAINT_ALL;
1803: }
1804: localBuffer = buffer;
1805: } finally {
1806: XToolkit.awtUnlock();
1807: }
1808: switch (localBuffer
1809: .validate(getGraphicsConfiguration())) {
1810: case VolatileImage.IMAGE_INCOMPATIBLE:
1811: invalidate();
1812: options = PAINT_ALL;
1813: continue;
1814: }
1815: Graphics g = localBuffer.createGraphics();
1816:
1817: try {
1818: g.setFont(getFont());
1819: if ((options & PAINT_BACKGROUND) != 0) {
1820: g.setColor(SystemColor.window);
1821: g.fillRect(0, 0, width, height);
1822: g.setColor(getListBackground());
1823: g.fillRect(0, 0, listWidth, listHeight);
1824: draw3DRect(g, getSystemColors(), 0, 0,
1825: listWidth - 1, listHeight - 1, false);
1826: // Since we made full erase update items
1827: firstItem = getFirstVisibleItem();
1828: lastItem = getLastVisibleItem();
1829: }
1830: if ((options & PAINT_ITEMS) != 0) {
1831: paintItems(g, firstItem, lastItem, options);
1832: }
1833: if ((options & PAINT_VSCROLL) != 0 && vsbVis) {
1834: g.setClip(getVScrollBarRec());
1835: paintVerScrollbar(g, true);
1836: }
1837: if ((options & PAINT_HSCROLL) != 0 && hsbVis) {
1838: g.setClip(getHScrollBarRec());
1839: paintHorScrollbar(g, true);
1840: }
1841: if ((options & (PAINT_FOCUS | PAINT_HIDEFOCUS)) != 0) {
1842: paintFocus(g, options);
1843: }
1844: } finally {
1845: g.dispose();
1846: }
1847: } while (localBuffer.contentsLost());
1848: listG.drawImage(localBuffer, 0, 0, null);
1849: }
1850:
1851: private void paintItems(Graphics g, int firstItem,
1852: int lastItem, int options) {
1853: if (log.isLoggable(Level.FINER))
1854: log.finer("Painting items from " + firstItem + " to "
1855: + lastItem + ", focused " + focusIndex
1856: + ", first " + getFirstVisibleItem()
1857: + ", last " + getLastVisibleItem());
1858:
1859: firstItem = Math.max(getFirstVisibleItem(), firstItem);
1860: if (firstItem > lastItem) {
1861: int t = lastItem;
1862: lastItem = firstItem;
1863: firstItem = t;
1864: }
1865: firstItem = Math.max(getFirstVisibleItem(), firstItem);
1866: lastItem = Math.min(lastItem, items.size() - 1);
1867:
1868: if (log.isLoggable(Level.FINER))
1869: log.finer("Actually painting items from " + firstItem
1870: + " to " + lastItem + ", items in window "
1871: + itemsInWindow());
1872: for (int i = firstItem; i <= lastItem; i++) {
1873: paintItem(g, i);
1874: }
1875: }
1876:
1877: private void paintItem(Graphics g, int index) {
1878: if (log.isLoggable(Level.FINEST))
1879: log.finest("Painting item " + index);
1880: // 4895367 - only paint items which are visible
1881: if (!isItemHidden(index)) {
1882: Shape clip = g.getClip();
1883: int w = getItemWidth();
1884: int h = getItemHeight();
1885: int y = getItemY(index);
1886: int x = getItemX();
1887: if (log.isLoggable(Level.FINEST))
1888: log.finest("Setting clip "
1889: + new Rectangle(x, y, w - (SPACE * 2), h
1890: - (SPACE * 2)));
1891: g.setClip(x, y, w - (SPACE * 2), h - (SPACE * 2));
1892:
1893: // Always paint the background so that focus is unpainted in
1894: // multiselect mode
1895: if (isSelected(index)) {
1896: if (log.isLoggable(Level.FINEST))
1897: log.finest("Painted item is selected");
1898: g.setColor(getListForeground());
1899: } else {
1900: g.setColor(getListBackground());
1901: }
1902: if (log.isLoggable(Level.FINEST))
1903: log.finest("Filling " + new Rectangle(x, y, w, h));
1904: g.fillRect(x, y, w, h);
1905:
1906: if (index <= getLastVisibleItem()
1907: && index < items.size()) {
1908: if (!isEnabled()) {
1909: g.setColor(getDisabledColor());
1910: } else if (isSelected(index)) {
1911: g.setColor(getListBackground());
1912: } else {
1913: g.setColor(getListForeground());
1914: }
1915: String str = (String) items.elementAt(index);
1916: g.drawString(str, x - hsb.getValue(), y
1917: + fontAscent);
1918: } else {
1919: // Clear the remaining area around the item - focus area and the rest of border
1920: g.setClip(x, y, listWidth, h);
1921: g.setColor(getListBackground());
1922: g.fillRect(x, y, listWidth, h);
1923: }
1924: g.setClip(clip);
1925: }
1926: }
1927:
1928: void paintScrollBar(XScrollbar scr, Graphics g, int x, int y,
1929: int width, int height, boolean paintAll) {
1930: if (log.isLoggable(Level.FINEST))
1931: log.finest("Painting scrollbar " + scr + " width "
1932: + width + " height " + height + ", paintAll "
1933: + paintAll);
1934: g.translate(x, y);
1935: scr.paint(g, getSystemColors(), paintAll);
1936: g.translate(-x, -y);
1937: }
1938:
1939: /**
1940: * Paint the horizontal scrollbar to the screen
1941: *
1942: * @param g the graphics context to draw into
1943: * @param colors the colors used to draw the scrollbar
1944: * @param paintAll paint the whole scrollbar if true, just the thumb if false
1945: */
1946: void paintHorScrollbar(Graphics g, boolean paintAll) {
1947: int w = getListWidth();
1948: paintScrollBar(hsb, g, 0, height - (SCROLLBAR_WIDTH), w,
1949: SCROLLBAR_WIDTH, paintAll);
1950: }
1951:
1952: /**
1953: * Paint the vertical scrollbar to the screen
1954: *
1955: * @param g the graphics context to draw into
1956: * @param colors the colors used to draw the scrollbar
1957: * @param paintAll paint the whole scrollbar if true, just the thumb if false
1958: */
1959: void paintVerScrollbar(Graphics g, boolean paintAll) {
1960: int h = height - (hsbVis ? (SCROLLBAR_AREA - 2) : 0);
1961: paintScrollBar(vsb, g, width - SCROLLBAR_WIDTH, 0,
1962: SCROLLBAR_WIDTH - 2, h, paintAll);
1963: }
1964:
1965: private Rectangle prevFocusRect;
1966:
1967: private void paintFocus(Graphics g, int options) {
1968: boolean paintFocus = (options & PAINT_FOCUS) != 0;
1969: if (paintFocus && !hasFocus()) {
1970: paintFocus = false;
1971: }
1972: if (log.isLoggable(Level.FINE))
1973: log
1974: .fine("Painting focus, focus index "
1975: + getFocusIndex()
1976: + ", focus is "
1977: + (isItemHidden(getFocusIndex()) ? ("invisible")
1978: : ("visible"))
1979: + ", paint focus is " + paintFocus);
1980: Shape clip = g.getClip();
1981: g.setClip(0, 0, listWidth, listHeight);
1982: if (log.isLoggable(Level.FINEST))
1983: log.finest("Setting focus clip "
1984: + new Rectangle(0, 0, listWidth, listHeight));
1985: Rectangle rect = getFocusRect();
1986: if (prevFocusRect != null) {
1987: // Erase focus rect
1988: if (log.isLoggable(Level.FINEST))
1989: log.finest("Erasing previous focus rect "
1990: + prevFocusRect);
1991: g.setColor(getListBackground());
1992: g.drawRect(prevFocusRect.x, prevFocusRect.y,
1993: prevFocusRect.width, prevFocusRect.height);
1994: prevFocusRect = null;
1995: }
1996: if (paintFocus) {
1997: // Paint new
1998: if (log.isLoggable(Level.FINEST))
1999: log.finest("Painting focus rect " + rect);
2000: g.setColor(getListForeground()); // Focus color is always black on Linux
2001: g.drawRect(rect.x, rect.y, rect.width, rect.height);
2002: prevFocusRect = rect;
2003: }
2004: g.setClip(clip);
2005: }
2006:
2007: public void copyArea(int x, int y, int width, int height,
2008: int dx, int dy) {
2009: if (log.isLoggable(Level.FINER))
2010: log.finer("Copying area " + x + ", " + y + " " + width
2011: + "x" + height + ", (" + dx + "," + dy + ")");
2012: VolatileImage localBuffer = null;
2013: do {
2014: XToolkit.awtLock();
2015: try {
2016: if (createBuffer()) {
2017: // Newly created buffer should be painted over at full
2018: repaint(PAINT_ALL);
2019: return;
2020: }
2021: localBuffer = buffer;
2022: } finally {
2023: XToolkit.awtUnlock();
2024: }
2025: switch (localBuffer
2026: .validate(getGraphicsConfiguration())) {
2027: case VolatileImage.IMAGE_INCOMPATIBLE:
2028: invalidate();
2029: case VolatileImage.IMAGE_RESTORED:
2030: // Since we've lost the content we can't just scroll - we should paint again
2031: repaint(PAINT_ALL);
2032: return;
2033: }
2034: Graphics g = localBuffer.createGraphics();
2035: try {
2036: g.copyArea(x, y, width, height, dx, dy);
2037: } finally {
2038: g.dispose();
2039: }
2040: } while (localBuffer.contentsLost());
2041: Graphics listG = getGraphics();
2042: listG.setClip(x, y, width, height);
2043: listG.drawImage(localBuffer, 0, 0, null);
2044: listG.dispose();
2045: }
2046:
2047: public boolean isBuffer() {
2048: boolean isBuffer;
2049: XToolkit.awtLock();
2050: try {
2051: isBuffer = (buffer != null);
2052: } finally {
2053: XToolkit.awtUnlock();
2054: }
2055: return isBuffer;
2056: }
2057: }
2058: }
|