1 /* |
|
2 * Copyright 1995-2004 Sun Microsystems, Inc. All Rights Reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 package sun.awt.motif; |
|
26 |
|
27 import java.awt.*; |
|
28 import java.awt.peer.*; |
|
29 import java.awt.event.ActionEvent; |
|
30 import java.awt.event.ItemEvent; |
|
31 import java.awt.event.MouseEvent; |
|
32 import java.awt.event.MouseWheelEvent; |
|
33 |
|
34 class MListPeer extends MComponentPeer implements ListPeer { |
|
35 native void create(MComponentPeer parent); |
|
36 |
|
37 void initialize() { |
|
38 List li = (List)target; |
|
39 |
|
40 /* add any items that were already inserted in the target. */ |
|
41 int nitems = li.countItems(); |
|
42 for (int i = 0; i < nitems; i++) { |
|
43 addItem(li.getItem(i), -1); |
|
44 } |
|
45 |
|
46 /* set whether this list should allow multiple selections. */ |
|
47 setMultipleSelections(li.allowsMultipleSelections()); |
|
48 |
|
49 /* make the visible position visible. */ |
|
50 int index = li.getVisibleIndex(); |
|
51 if (index >= 0) { |
|
52 makeVisible(index); |
|
53 } |
|
54 |
|
55 /* select the item if necessary. */ |
|
56 int sel[] = li.getSelectedIndexes(); |
|
57 for (int i = 0 ; i < sel.length ; i++) { |
|
58 select(sel[i]); |
|
59 } |
|
60 |
|
61 /* BugID 4060345 to avoid showing scrollbar in empty List */ |
|
62 if (nitems == 0) { |
|
63 addItem(" ", 0); |
|
64 delItems(0, 0); |
|
65 } |
|
66 super.pSetScrollbarBackground(getParent_NoClientCode(li).getBackground()); |
|
67 |
|
68 if (!target.isBackgroundSet()) { |
|
69 target.setBackground(SystemColor.text); |
|
70 } |
|
71 if (!target.isForegroundSet()) { |
|
72 target.setForeground(SystemColor.textText); |
|
73 } |
|
74 |
|
75 super.initialize(); |
|
76 } |
|
77 |
|
78 MListPeer(List target) { |
|
79 super(target); |
|
80 } |
|
81 |
|
82 /* New method name for 1.1 */ |
|
83 public void add(String item, int index) { |
|
84 addItem(item, index); |
|
85 } |
|
86 |
|
87 /* New method name for 1.1 */ |
|
88 public void removeAll() { |
|
89 clear(); |
|
90 } |
|
91 |
|
92 /* New method name for 1.1 */ |
|
93 public void setMultipleMode (boolean b) { |
|
94 setMultipleSelections(b); |
|
95 } |
|
96 |
|
97 /* New method name for 1.1 */ |
|
98 public Dimension getPreferredSize(int rows) { |
|
99 return preferredSize(rows); |
|
100 } |
|
101 |
|
102 /* New method name for 1.1 */ |
|
103 public Dimension getMinimumSize(int rows) { |
|
104 return minimumSize(rows); |
|
105 } |
|
106 |
|
107 public void setForeground(Color c) { |
|
108 pSetInnerForeground(c); |
|
109 } |
|
110 |
|
111 public native void setBackground(Color c); |
|
112 public native void setMultipleSelections(boolean v); |
|
113 public native boolean isSelected(int index); |
|
114 public native void addItem(String item, int index); |
|
115 public native void delItems(int start, int end); |
|
116 public native void select(int index); |
|
117 public native void deselect(int index); |
|
118 public native void makeVisible(int index); |
|
119 |
|
120 public void clear() { |
|
121 List l = (List)target; |
|
122 int count = l.countItems(); |
|
123 if (count > 0) { |
|
124 delItems(0, count-1); |
|
125 } |
|
126 } |
|
127 |
|
128 public int[] getSelectedIndexes() { |
|
129 List l = (List)target; |
|
130 int len = l.countItems(); |
|
131 int sel[] = new int[len]; |
|
132 int nsel = 0; |
|
133 for (int i = 0 ; i < len ; i++) { |
|
134 if (isSelected(i)) { |
|
135 sel[nsel++] = i; |
|
136 } |
|
137 } |
|
138 int selected[] = new int[nsel]; |
|
139 System.arraycopy(sel, 0, selected, 0, nsel); |
|
140 return selected; |
|
141 } |
|
142 |
|
143 // NOTE: This method may be called by privileged threads. |
|
144 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! |
|
145 public void action(int index, final long when, final int modifiers) { |
|
146 final List list = (List)target; |
|
147 final int selectIndex = index; |
|
148 |
|
149 MToolkit.executeOnEventHandlerThread(list, new Runnable() { |
|
150 public void run() { |
|
151 list.select(selectIndex); |
|
152 postEvent(new ActionEvent(target, ActionEvent.ACTION_PERFORMED, |
|
153 list.getItem(selectIndex), when, |
|
154 modifiers)); |
|
155 } |
|
156 }); |
|
157 } // action() |
|
158 |
|
159 // NOTE: This method may be called by privileged threads. |
|
160 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! |
|
161 public void handleListChanged(int index) { |
|
162 final MListPeer listPeer = this; |
|
163 final List list = (List)target; |
|
164 final int listIndex = index; |
|
165 |
|
166 MToolkit.executeOnEventHandlerThread(list, new Runnable() { |
|
167 public void run() { |
|
168 int selected[] = listPeer.getSelectedIndexes(); |
|
169 boolean isSelected = false; |
|
170 |
|
171 for (int i=0; i < selected.length; i++) { |
|
172 if (listIndex == selected[i]) { |
|
173 isSelected = true; |
|
174 break; |
|
175 } |
|
176 } |
|
177 postEvent(new ItemEvent(list, ItemEvent.ITEM_STATE_CHANGED, |
|
178 Integer.valueOf(listIndex), |
|
179 isSelected? ItemEvent.SELECTED : ItemEvent.DESELECTED)); |
|
180 |
|
181 } |
|
182 }); |
|
183 } // handleListChanged() |
|
184 |
|
185 public Dimension minimumSize() { |
|
186 return minimumSize(4); |
|
187 } |
|
188 |
|
189 public Dimension preferredSize(int v) { |
|
190 return minimumSize(v); |
|
191 } |
|
192 |
|
193 public Dimension minimumSize(int v) { |
|
194 FontMetrics fm = getFontMetrics(((List)target).getFont()); |
|
195 return new Dimension(SCROLLBAR + 2*MARGIN + |
|
196 fm.stringWidth("0123456789abcde"), |
|
197 ((fm.getHeight()+2*SPACE) * v) + |
|
198 2*MARGIN); |
|
199 } |
|
200 |
|
201 public boolean isFocusable() { |
|
202 return true; |
|
203 } |
|
204 |
|
205 /* |
|
206 * Print the native component by rendering the Motif look ourselves. |
|
207 * ToDo(aim): needs to query native motif for more accurate size and |
|
208 * color information, selected items, and item offset. |
|
209 */ |
|
210 final static int MARGIN = 2; |
|
211 final static int SPACE = 1; |
|
212 final static int SCROLLBAR = 16; |
|
213 int fontHeight; |
|
214 int fontAscent; |
|
215 int fontLeading; |
|
216 int vval; |
|
217 int hval; |
|
218 int vmax; |
|
219 int hmax; |
|
220 |
|
221 public void print(Graphics g) { |
|
222 List l = (List)target; |
|
223 Dimension d = l.size(); |
|
224 Color bg = l.getBackground(); |
|
225 Color fg = l.getForeground(); |
|
226 int numItems = l.getItemCount(); |
|
227 FontMetrics fm = getFontMetrics(l.getFont()); |
|
228 int w, h; |
|
229 int vvis, hvis, vmin, hmin; |
|
230 int max = 0; |
|
231 |
|
232 for (int i = 0; i < numItems; i++) { |
|
233 int len = fm.stringWidth(l.getItem(i)); |
|
234 max = Math.max(max, len); |
|
235 } |
|
236 |
|
237 fontHeight = fm.getHeight(); |
|
238 fontAscent = fm.getAscent(); |
|
239 fontLeading = fm.getLeading(); |
|
240 |
|
241 hmin = vmin = 0; |
|
242 |
|
243 vvis = itemsInWindow(true); |
|
244 vmax = Math.max(numItems - vvis, 0); |
|
245 h = d.height - SCROLLBAR; |
|
246 |
|
247 if (vmax != 0) { |
|
248 w = d.width - SCROLLBAR; |
|
249 hvis = w - ((2 * SPACE) + (2 * MARGIN)); |
|
250 hmax = Math.max(max - hvis, 0); |
|
251 } else { |
|
252 w = d.width; |
|
253 hvis = w - ((2 * SPACE) + (2 * MARGIN)); |
|
254 hmax = Math.max(max - hvis, 0); |
|
255 } |
|
256 if (hmax == 0) { |
|
257 h = d.height; |
|
258 vvis = itemsInWindow(false); |
|
259 vmax = Math.max(numItems - vvis, 0); |
|
260 } |
|
261 if (vmax == 0) { |
|
262 w = d.width; |
|
263 hvis = w - ((2 * SPACE) + (2 * MARGIN)); |
|
264 hmax = Math.max(max - hvis, 0); |
|
265 } |
|
266 |
|
267 hval = 0; |
|
268 vval = 0; |
|
269 /* |
|
270 System.out.println("print List: "+d.width+"x"+d.height+" numItems="+numItems+ |
|
271 "max="+max+" vsb=("+vmin+".."+vmax+","+vval+","+vvis+ |
|
272 ") hsb=("+hmin+".."+hmax+","+hval+","+hvis+")"); |
|
273 */ |
|
274 |
|
275 g.setColor(bg); |
|
276 g.fillRect(0, 0, w, h); |
|
277 |
|
278 if (hmax != 0) { |
|
279 int sbw = d.width - ((vmax == 0) ? 0 : SCROLLBAR); |
|
280 g.fillRect(1, d.height - SCROLLBAR - 3, sbw - 1, SCROLLBAR - 3); |
|
281 Graphics ng = g.create(); |
|
282 try { |
|
283 ng.translate(0, d.height - (SCROLLBAR - 2)); |
|
284 drawScrollbar(ng, bg, SCROLLBAR - 2, sbw, |
|
285 hmin, hmax, hval, hvis, true); |
|
286 } finally { |
|
287 ng.dispose(); |
|
288 } |
|
289 } |
|
290 if (vmax != 0) { |
|
291 int sbh = d.height - ((hmax == 0) ? 0 : SCROLLBAR); |
|
292 g.fillRect(d.width - SCROLLBAR - 3, 1, SCROLLBAR - 3, sbh - 1); |
|
293 Graphics ng = g.create(); |
|
294 try { |
|
295 ng.translate(d.width - (SCROLLBAR - 2), 0); |
|
296 drawScrollbar(ng, bg, SCROLLBAR - 2, sbh, |
|
297 vmin, vmax, vval, vvis, false); |
|
298 } finally { |
|
299 ng.dispose(); |
|
300 } |
|
301 } |
|
302 |
|
303 draw3DRect(g, bg, 0, 0, w - 1, h - 1, false); |
|
304 |
|
305 if (numItems > 0) { |
|
306 int n = itemsInWindow(hmax != 0); |
|
307 int e = Math.min(numItems - 1, (vval + n) - 1); |
|
308 paintItems(g, bg, fg, vval, e); |
|
309 } |
|
310 |
|
311 target.print(g); |
|
312 } |
|
313 |
|
314 int itemsInWindow(boolean scrollbarVisible) { |
|
315 Dimension d = target.size(); |
|
316 int h; |
|
317 if (scrollbarVisible) { |
|
318 h = d.height - ((2 * MARGIN) + SCROLLBAR); |
|
319 } else { |
|
320 h = d.height - 2*MARGIN; |
|
321 } |
|
322 int i = fontHeight - fontLeading; |
|
323 return h / (i + (2 * SPACE)); |
|
324 } |
|
325 |
|
326 void paintItem(Graphics g, Color bg, Color fg, int index, boolean isSelected) { |
|
327 List l = (List)target; |
|
328 Dimension d = l.size(); |
|
329 int numItems = l.getItemCount(); |
|
330 Color shadow = bg.darker(); |
|
331 |
|
332 if ((index < vval) || (index >= (vval + itemsInWindow(hmax != 0)))) { |
|
333 return; |
|
334 } |
|
335 int w = d.width - ((2 * MARGIN) + ((vmax != 0)? SCROLLBAR : 0)); |
|
336 int h = (fontHeight - fontLeading); |
|
337 int htotal = h + (2 * SPACE); |
|
338 int index2y = MARGIN + (index * htotal) + SPACE; |
|
339 int y = index2y - (vval * htotal); |
|
340 int x = MARGIN + SPACE; |
|
341 Graphics ng = g.create(); |
|
342 try { |
|
343 if (index > numItems - 1) { |
|
344 ng.setColor(bg); |
|
345 ng.fillRect(x - 2, y - 2, w, h + 4); |
|
346 return; |
|
347 } |
|
348 if (isSelected) { |
|
349 ng.setColor(shadow); |
|
350 ng.fillRect(x - 1, y - 1, w - 2, h + 2); |
|
351 } else { |
|
352 ng.setColor(bg); |
|
353 ng.fillRect(x - 1, y - 1, w - 2, h + 2); |
|
354 } |
|
355 ng.setColor(bg); |
|
356 |
|
357 ng.drawRect(x - 2, y - 2, w - 1, h + 3); |
|
358 ng.setColor(fg); |
|
359 String str = (String)l.getItem(index); |
|
360 ng.clipRect(x, y, w - (2 * SPACE), h); |
|
361 ng.drawString(str, x - hval, y + fontAscent); |
|
362 } finally { |
|
363 ng.dispose(); |
|
364 } |
|
365 } |
|
366 |
|
367 void paintItems(Graphics g, Color bg, Color fg, int s, int e) { |
|
368 for (int i = s ; i <= e ; i++) { |
|
369 paintItem(g, bg, fg, i, false); |
|
370 } |
|
371 } |
|
372 |
|
373 public boolean handlesWheelScrolling() {return true;} |
|
374 |
|
375 public void handleEvent(AWTEvent e) { |
|
376 if (e.getID() == MouseEvent.MOUSE_WHEEL) { |
|
377 MouseWheelEvent mwe = (MouseWheelEvent)e; |
|
378 nativeHandleMouseWheel(mwe.getScrollType(), |
|
379 mwe.getScrollAmount(), |
|
380 mwe.getWheelRotation()); |
|
381 } |
|
382 else { |
|
383 super.handleEvent(e); |
|
384 } |
|
385 } |
|
386 |
|
387 native void nativeHandleMouseWheel(int scrollType, |
|
388 int scrollAmount, |
|
389 int wheelRotation); |
|
390 } |
|