001: /*
002: * Copyright 1995-2004 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025: package sun.awt.motif;
026:
027: import java.awt.*;
028: import java.awt.peer.*;
029: import java.awt.event.ActionEvent;
030: import java.awt.event.ItemEvent;
031: import java.awt.event.MouseEvent;
032: import java.awt.event.MouseWheelEvent;
033:
034: class MListPeer extends MComponentPeer implements ListPeer {
035: native void create(MComponentPeer parent);
036:
037: void initialize() {
038: List li = (List) target;
039:
040: /* add any items that were already inserted in the target. */
041: int nitems = li.countItems();
042: for (int i = 0; i < nitems; i++) {
043: addItem(li.getItem(i), -1);
044: }
045:
046: /* set whether this list should allow multiple selections. */
047: setMultipleSelections(li.allowsMultipleSelections());
048:
049: /* make the visible position visible. */
050: int index = li.getVisibleIndex();
051: if (index >= 0) {
052: makeVisible(index);
053: }
054:
055: /* select the item if necessary. */
056: int sel[] = li.getSelectedIndexes();
057: for (int i = 0; i < sel.length; i++) {
058: select(sel[i]);
059: }
060:
061: /* BugID 4060345 to avoid showing scrollbar in empty List */
062: if (nitems == 0) {
063: addItem(" ", 0);
064: delItems(0, 0);
065: }
066: super .pSetScrollbarBackground(getParent_NoClientCode(li)
067: .getBackground());
068:
069: if (!target.isBackgroundSet()) {
070: target.setBackground(SystemColor.text);
071: }
072: if (!target.isForegroundSet()) {
073: target.setForeground(SystemColor.textText);
074: }
075:
076: super .initialize();
077: }
078:
079: MListPeer(List target) {
080: super (target);
081: }
082:
083: /* New method name for 1.1 */
084: public void add(String item, int index) {
085: addItem(item, index);
086: }
087:
088: /* New method name for 1.1 */
089: public void removeAll() {
090: clear();
091: }
092:
093: /* New method name for 1.1 */
094: public void setMultipleMode(boolean b) {
095: setMultipleSelections(b);
096: }
097:
098: /* New method name for 1.1 */
099: public Dimension getPreferredSize(int rows) {
100: return preferredSize(rows);
101: }
102:
103: /* New method name for 1.1 */
104: public Dimension getMinimumSize(int rows) {
105: return minimumSize(rows);
106: }
107:
108: public void setForeground(Color c) {
109: pSetInnerForeground(c);
110: }
111:
112: public native void setBackground(Color c);
113:
114: public native void setMultipleSelections(boolean v);
115:
116: public native boolean isSelected(int index);
117:
118: public native void addItem(String item, int index);
119:
120: public native void delItems(int start, int end);
121:
122: public native void select(int index);
123:
124: public native void deselect(int index);
125:
126: public native void makeVisible(int index);
127:
128: public void clear() {
129: List l = (List) target;
130: int count = l.countItems();
131: if (count > 0) {
132: delItems(0, count - 1);
133: }
134: }
135:
136: public int[] getSelectedIndexes() {
137: List l = (List) target;
138: int len = l.countItems();
139: int sel[] = new int[len];
140: int nsel = 0;
141: for (int i = 0; i < len; i++) {
142: if (isSelected(i)) {
143: sel[nsel++] = i;
144: }
145: }
146: int selected[] = new int[nsel];
147: System.arraycopy(sel, 0, selected, 0, nsel);
148: return selected;
149: }
150:
151: // NOTE: This method may be called by privileged threads.
152: // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
153: public void action(int index, final long when, final int modifiers) {
154: final List list = (List) target;
155: final int selectIndex = index;
156:
157: MToolkit.executeOnEventHandlerThread(list, new Runnable() {
158: public void run() {
159: list.select(selectIndex);
160: postEvent(new ActionEvent(target,
161: ActionEvent.ACTION_PERFORMED, list
162: .getItem(selectIndex), when, modifiers));
163: }
164: });
165: } // action()
166:
167: // NOTE: This method may be called by privileged threads.
168: // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
169: public void handleListChanged(int index) {
170: final MListPeer listPeer = this ;
171: final List list = (List) target;
172: final int listIndex = index;
173:
174: MToolkit.executeOnEventHandlerThread(list, new Runnable() {
175: public void run() {
176: int selected[] = listPeer.getSelectedIndexes();
177: boolean isSelected = false;
178:
179: for (int i = 0; i < selected.length; i++) {
180: if (listIndex == selected[i]) {
181: isSelected = true;
182: break;
183: }
184: }
185: postEvent(new ItemEvent(list,
186: ItemEvent.ITEM_STATE_CHANGED, Integer
187: .valueOf(listIndex),
188: isSelected ? ItemEvent.SELECTED
189: : ItemEvent.DESELECTED));
190:
191: }
192: });
193: } // handleListChanged()
194:
195: public Dimension minimumSize() {
196: return minimumSize(4);
197: }
198:
199: public Dimension preferredSize(int v) {
200: return minimumSize(v);
201: }
202:
203: public Dimension minimumSize(int v) {
204: FontMetrics fm = getFontMetrics(((List) target).getFont());
205: return new Dimension(SCROLLBAR + 2 * MARGIN
206: + fm.stringWidth("0123456789abcde"),
207: ((fm.getHeight() + 2 * SPACE) * v) + 2 * MARGIN);
208: }
209:
210: public boolean isFocusable() {
211: return true;
212: }
213:
214: /*
215: * Print the native component by rendering the Motif look ourselves.
216: * ToDo(aim): needs to query native motif for more accurate size and
217: * color information, selected items, and item offset.
218: */
219: final static int MARGIN = 2;
220: final static int SPACE = 1;
221: final static int SCROLLBAR = 16;
222: int fontHeight;
223: int fontAscent;
224: int fontLeading;
225: int vval;
226: int hval;
227: int vmax;
228: int hmax;
229:
230: public void print(Graphics g) {
231: List l = (List) target;
232: Dimension d = l.size();
233: Color bg = l.getBackground();
234: Color fg = l.getForeground();
235: int numItems = l.getItemCount();
236: FontMetrics fm = getFontMetrics(l.getFont());
237: int w, h;
238: int vvis, hvis, vmin, hmin;
239: int max = 0;
240:
241: for (int i = 0; i < numItems; i++) {
242: int len = fm.stringWidth(l.getItem(i));
243: max = Math.max(max, len);
244: }
245:
246: fontHeight = fm.getHeight();
247: fontAscent = fm.getAscent();
248: fontLeading = fm.getLeading();
249:
250: hmin = vmin = 0;
251:
252: vvis = itemsInWindow(true);
253: vmax = Math.max(numItems - vvis, 0);
254: h = d.height - SCROLLBAR;
255:
256: if (vmax != 0) {
257: w = d.width - SCROLLBAR;
258: hvis = w - ((2 * SPACE) + (2 * MARGIN));
259: hmax = Math.max(max - hvis, 0);
260: } else {
261: w = d.width;
262: hvis = w - ((2 * SPACE) + (2 * MARGIN));
263: hmax = Math.max(max - hvis, 0);
264: }
265: if (hmax == 0) {
266: h = d.height;
267: vvis = itemsInWindow(false);
268: vmax = Math.max(numItems - vvis, 0);
269: }
270: if (vmax == 0) {
271: w = d.width;
272: hvis = w - ((2 * SPACE) + (2 * MARGIN));
273: hmax = Math.max(max - hvis, 0);
274: }
275:
276: hval = 0;
277: vval = 0;
278: /*
279: System.out.println("print List: "+d.width+"x"+d.height+" numItems="+numItems+
280: "max="+max+" vsb=("+vmin+".."+vmax+","+vval+","+vvis+
281: ") hsb=("+hmin+".."+hmax+","+hval+","+hvis+")");
282: */
283:
284: g.setColor(bg);
285: g.fillRect(0, 0, w, h);
286:
287: if (hmax != 0) {
288: int sbw = d.width - ((vmax == 0) ? 0 : SCROLLBAR);
289: g.fillRect(1, d.height - SCROLLBAR - 3, sbw - 1,
290: SCROLLBAR - 3);
291: Graphics ng = g.create();
292: try {
293: ng.translate(0, d.height - (SCROLLBAR - 2));
294: drawScrollbar(ng, bg, SCROLLBAR - 2, sbw, hmin, hmax,
295: hval, hvis, true);
296: } finally {
297: ng.dispose();
298: }
299: }
300: if (vmax != 0) {
301: int sbh = d.height - ((hmax == 0) ? 0 : SCROLLBAR);
302: g.fillRect(d.width - SCROLLBAR - 3, 1, SCROLLBAR - 3,
303: sbh - 1);
304: Graphics ng = g.create();
305: try {
306: ng.translate(d.width - (SCROLLBAR - 2), 0);
307: drawScrollbar(ng, bg, SCROLLBAR - 2, sbh, vmin, vmax,
308: vval, vvis, false);
309: } finally {
310: ng.dispose();
311: }
312: }
313:
314: draw3DRect(g, bg, 0, 0, w - 1, h - 1, false);
315:
316: if (numItems > 0) {
317: int n = itemsInWindow(hmax != 0);
318: int e = Math.min(numItems - 1, (vval + n) - 1);
319: paintItems(g, bg, fg, vval, e);
320: }
321:
322: target.print(g);
323: }
324:
325: int itemsInWindow(boolean scrollbarVisible) {
326: Dimension d = target.size();
327: int h;
328: if (scrollbarVisible) {
329: h = d.height - ((2 * MARGIN) + SCROLLBAR);
330: } else {
331: h = d.height - 2 * MARGIN;
332: }
333: int i = fontHeight - fontLeading;
334: return h / (i + (2 * SPACE));
335: }
336:
337: void paintItem(Graphics g, Color bg, Color fg, int index,
338: boolean isSelected) {
339: List l = (List) target;
340: Dimension d = l.size();
341: int numItems = l.getItemCount();
342: Color shadow = bg.darker();
343:
344: if ((index < vval)
345: || (index >= (vval + itemsInWindow(hmax != 0)))) {
346: return;
347: }
348: int w = d.width
349: - ((2 * MARGIN) + ((vmax != 0) ? SCROLLBAR : 0));
350: int h = (fontHeight - fontLeading);
351: int htotal = h + (2 * SPACE);
352: int index2y = MARGIN + (index * htotal) + SPACE;
353: int y = index2y - (vval * htotal);
354: int x = MARGIN + SPACE;
355: Graphics ng = g.create();
356: try {
357: if (index > numItems - 1) {
358: ng.setColor(bg);
359: ng.fillRect(x - 2, y - 2, w, h + 4);
360: return;
361: }
362: if (isSelected) {
363: ng.setColor(shadow);
364: ng.fillRect(x - 1, y - 1, w - 2, h + 2);
365: } else {
366: ng.setColor(bg);
367: ng.fillRect(x - 1, y - 1, w - 2, h + 2);
368: }
369: ng.setColor(bg);
370:
371: ng.drawRect(x - 2, y - 2, w - 1, h + 3);
372: ng.setColor(fg);
373: String str = (String) l.getItem(index);
374: ng.clipRect(x, y, w - (2 * SPACE), h);
375: ng.drawString(str, x - hval, y + fontAscent);
376: } finally {
377: ng.dispose();
378: }
379: }
380:
381: void paintItems(Graphics g, Color bg, Color fg, int s, int e) {
382: for (int i = s; i <= e; i++) {
383: paintItem(g, bg, fg, i, false);
384: }
385: }
386:
387: public boolean handlesWheelScrolling() {
388: return true;
389: }
390:
391: public void handleEvent(AWTEvent e) {
392: if (e.getID() == MouseEvent.MOUSE_WHEEL) {
393: MouseWheelEvent mwe = (MouseWheelEvent) e;
394: nativeHandleMouseWheel(mwe.getScrollType(), mwe
395: .getScrollAmount(), mwe.getWheelRotation());
396: } else {
397: super .handleEvent(e);
398: }
399: }
400:
401: native void nativeHandleMouseWheel(int scrollType,
402: int scrollAmount, int wheelRotation);
403: }
|