1 /* |
1 /* |
2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
38 * Class to paint a list of items, possibly with scrollbars |
38 * Class to paint a list of items, possibly with scrollbars |
39 * This class paints all items with the same font |
39 * This class paints all items with the same font |
40 * For now, this class manages the list of items and painting thereof, but not |
40 * For now, this class manages the list of items and painting thereof, but not |
41 * posting of Item or ActionEvents |
41 * posting of Item or ActionEvents |
42 */ |
42 */ |
43 public class ListHelper implements XScrollbarClient { |
43 final class ListHelper implements XScrollbarClient { |
44 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.ListHelper"); |
44 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.ListHelper"); |
45 |
45 |
46 private final int FOCUS_INSET = 1; |
46 private final int FOCUS_INSET = 1; |
47 |
47 |
48 private final int BORDER_WIDTH; // Width of border drawn around the list |
48 private final int BORDER_WIDTH; // Width of border drawn around the list |
77 private Color[] colors; // Passed in for painting on notifyValue() |
77 private Color[] colors; // Passed in for painting on notifyValue() |
78 |
78 |
79 // Holds the true if mouse is dragging outside of the area of the list |
79 // Holds the true if mouse is dragging outside of the area of the list |
80 // The flag is used at the moment of the dragging and releasing mouse |
80 // The flag is used at the moment of the dragging and releasing mouse |
81 // See 6243382 for more information |
81 // See 6243382 for more information |
82 boolean mouseDraggedOutVertically = false; |
82 private boolean mouseDraggedOutVertically = false; |
83 private volatile boolean vsbVisibilityChanged = false; |
83 private volatile boolean vsbVisibilityChanged = false; |
84 |
84 |
85 /* |
85 /* |
86 * Comment |
86 * Comment |
87 */ |
87 */ |
88 public ListHelper(XWindow peer, |
88 ListHelper(XWindow peer, Color[] colors, int initialSize, |
89 Color[] colors, |
89 boolean multiSelect, boolean scrollVert, boolean scrollHoriz, |
90 int initialSize, |
90 Font font, int maxVisItems, int SPACE, int MARGIN, int BORDER, |
91 boolean multiSelect, |
91 int SCROLLBAR) { |
92 boolean scrollVert, |
|
93 boolean scrollHoriz, |
|
94 Font font, |
|
95 int maxVisItems, |
|
96 int SPACE, |
|
97 int MARGIN, |
|
98 int BORDER, |
|
99 int SCROLLBAR) { |
|
100 this.peer = peer; |
92 this.peer = peer; |
101 this.colors = colors; |
93 this.colors = colors; |
102 this.multiSelect = multiSelect; |
94 this.multiSelect = multiSelect; |
103 items = new ArrayList<>(initialSize); |
95 items = new ArrayList<>(initialSize); |
104 selected = new ArrayList<>(1); |
96 selected = new ArrayList<>(1); |
119 ITEM_MARGIN = MARGIN; |
111 ITEM_MARGIN = MARGIN; |
120 BORDER_WIDTH = BORDER; |
112 BORDER_WIDTH = BORDER; |
121 SCROLLBAR_WIDTH = SCROLLBAR; |
113 SCROLLBAR_WIDTH = SCROLLBAR; |
122 } |
114 } |
123 |
115 |
|
116 @Override |
124 public Component getEventSource() { |
117 public Component getEventSource() { |
125 return peer.getEventSource(); |
118 return peer.getEventSource(); |
126 } |
119 } |
127 |
120 |
128 /**********************************************************************/ |
121 /**********************************************************************/ |
129 /* List management methods */ |
122 /* List management methods */ |
130 /**********************************************************************/ |
123 /**********************************************************************/ |
131 |
124 |
132 public void add(String item) { |
125 void add(String item) { |
133 items.add(item); |
126 items.add(item); |
134 updateScrollbars(); |
127 updateScrollbars(); |
135 } |
128 } |
136 |
129 |
137 public void add(String item, int index) { |
130 void add(String item, int index) { |
138 items.add(index, item); |
131 items.add(index, item); |
139 updateScrollbars(); |
132 updateScrollbars(); |
140 } |
133 } |
141 |
134 |
142 public void remove(String item) { |
135 void remove(String item) { |
143 // FIXME: need to clean up select list, too? |
136 // FIXME: need to clean up select list, too? |
144 items.remove(item); |
137 items.remove(item); |
145 updateScrollbars(); |
138 updateScrollbars(); |
146 // Is vsb visible now? |
139 // Is vsb visible now? |
147 } |
140 } |
148 |
141 |
149 public void remove(int index) { |
142 void remove(int index) { |
150 // FIXME: need to clean up select list, too? |
143 // FIXME: need to clean up select list, too? |
151 items.remove(index); |
144 items.remove(index); |
152 updateScrollbars(); |
145 updateScrollbars(); |
153 // Is vsb visible now? |
146 // Is vsb visible now? |
154 } |
147 } |
155 |
148 |
156 public void removeAll() { |
149 void removeAll() { |
157 items.removeAll(items); |
150 items.removeAll(items); |
158 updateScrollbars(); |
151 updateScrollbars(); |
159 } |
152 } |
160 |
153 |
161 public void setMultiSelect(boolean ms) { |
154 void setMultiSelect(boolean ms) { |
162 multiSelect = ms; |
155 multiSelect = ms; |
163 } |
156 } |
164 |
157 |
165 /* |
158 /* |
166 * docs.....definitely docs |
159 * docs.....definitely docs |
167 * merely keeps internal track of which items are selected for painting |
160 * merely keeps internal track of which items are selected for painting |
168 * dealing with target Components happens elsewhere |
161 * dealing with target Components happens elsewhere |
169 */ |
162 */ |
170 public void select(int index) { |
163 void select(int index) { |
171 if (index > getItemCount() - 1) { |
164 if (index > getItemCount() - 1) { |
172 index = (isEmpty() ? -1 : 0); |
165 index = (isEmpty() ? -1 : 0); |
173 } |
166 } |
174 if (multiSelect) { |
167 if (multiSelect) { |
175 assert false : "Implement ListHelper.select() for multiselect"; |
168 assert false : "Implement ListHelper.select() for multiselect"; |
200 |
193 |
201 /* |
194 /* |
202 * A getter method for XChoicePeer. |
195 * A getter method for XChoicePeer. |
203 * Returns vsbVisiblityChanged value and sets it to false. |
196 * Returns vsbVisiblityChanged value and sets it to false. |
204 */ |
197 */ |
205 public boolean checkVsbVisibilityChangedAndReset(){ |
198 boolean checkVsbVisibilityChangedAndReset(){ |
206 boolean returnVal = vsbVisibilityChanged; |
199 boolean returnVal = vsbVisibilityChanged; |
207 vsbVisibilityChanged = false; |
200 vsbVisibilityChanged = false; |
208 return returnVal; |
201 return returnVal; |
209 } |
202 } |
210 |
203 |
211 public boolean isEmpty() { |
204 boolean isEmpty() { |
212 return items.isEmpty(); |
205 return items.isEmpty(); |
213 } |
206 } |
214 |
207 |
215 public int getItemCount() { |
208 int getItemCount() { |
216 return items.size(); |
209 return items.size(); |
217 } |
210 } |
218 |
211 |
219 public String getItem(int index) { |
212 String getItem(int index) { |
220 return items.get(index); |
213 return items.get(index); |
221 } |
214 } |
222 |
215 |
223 /**********************************************************************/ |
216 /**********************************************************************/ |
224 /* GUI-related methods */ |
217 /* GUI-related methods */ |
225 /**********************************************************************/ |
218 /**********************************************************************/ |
226 |
219 |
227 public void setFocusedIndex(int index) { |
220 void setFocusedIndex(int index) { |
228 focusedIndex = index; |
221 focusedIndex = index; |
229 } |
222 } |
230 |
223 |
231 public boolean isFocusedIndex(int index) { |
224 private boolean isFocusedIndex(int index) { |
232 return index == focusedIndex; |
225 return index == focusedIndex; |
233 } |
226 } |
234 |
227 |
235 public void setFont(Font newFont) { |
228 void setFont(Font newFont) { |
236 if (newFont != font) { |
229 if (newFont != font) { |
237 font = newFont; |
230 font = newFont; |
238 fm = Toolkit.getDefaultToolkit().getFontMetrics(font); |
231 fm = Toolkit.getDefaultToolkit().getFontMetrics(font); |
239 // Also cache stuff like fontHeight? |
232 // Also cache stuff like fontHeight? |
240 } |
233 } |
241 } |
234 } |
242 |
235 |
243 /* |
236 /* |
244 * Returns width of the text of the longest item |
237 * Returns width of the text of the longest item |
245 */ |
238 */ |
246 public int getMaxItemWidth() { |
239 int getMaxItemWidth() { |
247 int m = 0; |
240 int m = 0; |
248 int end = getItemCount(); |
241 int end = getItemCount(); |
249 for(int i = 0 ; i < end ; i++) { |
242 for(int i = 0 ; i < end ; i++) { |
250 int l = fm.stringWidth(getItem(i)); |
243 int l = fm.stringWidth(getItem(i)); |
251 m = Math.max(m, l); |
244 m = Math.max(m, l); |
258 */ |
251 */ |
259 int getItemHeight() { |
252 int getItemHeight() { |
260 return fm.getHeight() + (2*TEXT_SPACE); |
253 return fm.getHeight() + (2*TEXT_SPACE); |
261 } |
254 } |
262 |
255 |
263 public int y2index(int y) { |
256 int y2index(int y) { |
264 if (log.isLoggable(PlatformLogger.Level.FINE)) { |
257 if (log.isLoggable(PlatformLogger.Level.FINE)) { |
265 log.fine("y=" + y +", firstIdx=" + firstDisplayedIndex() +", itemHeight=" + getItemHeight() |
258 log.fine("y=" + y +", firstIdx=" + firstDisplayedIndex() +", itemHeight=" + getItemHeight() |
266 + ",item_margin=" + ITEM_MARGIN); |
259 + ",item_margin=" + ITEM_MARGIN); |
267 } |
260 } |
268 // See 6243382 for more information |
261 // See 6243382 for more information |
273 /* write these |
266 /* write these |
274 int index2y(int); |
267 int index2y(int); |
275 public int numItemsDisplayed() {} |
268 public int numItemsDisplayed() {} |
276 */ |
269 */ |
277 |
270 |
278 public int firstDisplayedIndex() { |
271 int firstDisplayedIndex() { |
279 if (vsbVis) { |
272 if (vsbVis) { |
280 return vsb.getValue(); |
273 return vsb.getValue(); |
281 } |
274 } |
282 return 0; |
275 return 0; |
283 } |
276 } |
284 |
277 |
285 public int lastDisplayedIndex() { |
278 int lastDisplayedIndex() { |
286 // FIXME: need to account for horiz scroll bar |
279 // FIXME: need to account for horiz scroll bar |
287 if (hsbVis) { |
280 if (hsbVis) { |
288 assert false : "Implement for horiz scroll bar"; |
281 assert false : "Implement for horiz scroll bar"; |
289 } |
282 } |
290 |
283 |
355 vsb.setValue(newIdx); |
348 vsb.setValue(newIdx); |
356 select(firstDisplayedIndex() + selectionOffset); |
349 select(firstDisplayedIndex() + selectionOffset); |
357 } |
350 } |
358 } |
351 } |
359 } |
352 } |
360 public void home() {} |
353 void home() {} |
361 public void end() {} |
354 void end() {} |
362 |
355 |
363 |
356 |
364 public boolean isVSBVisible() { return vsbVis; } |
357 boolean isVSBVisible() { return vsbVis; } |
365 public boolean isHSBVisible() { return hsbVis; } |
358 boolean isHSBVisible() { return hsbVis; } |
366 |
359 |
367 public XVerticalScrollbar getVSB() { return vsb; } |
360 XVerticalScrollbar getVSB() { return vsb; } |
368 public XHorizontalScrollbar getHSB() { return hsb; } |
361 XHorizontalScrollbar getHSB() { return hsb; } |
369 |
362 |
370 public boolean isInVertSB(Rectangle bounds, int x, int y) { |
363 boolean isInVertSB(Rectangle bounds, int x, int y) { |
371 if (vsbVis) { |
364 if (vsbVis) { |
372 assert vsb != null : "Vert scrollbar is visible, yet is null?"; |
365 assert vsb != null : "Vert scrollbar is visible, yet is null?"; |
373 int sbHeight = hsbVis ? bounds.height - SCROLLBAR_WIDTH : bounds.height; |
366 int sbHeight = hsbVis ? bounds.height - SCROLLBAR_WIDTH : bounds.height; |
374 return (x <= bounds.width) && |
367 return (x <= bounds.width) && |
375 (x >= bounds.width - SCROLLBAR_WIDTH) && |
368 (x >= bounds.width - SCROLLBAR_WIDTH) && |
390 (y <= bounds.height); |
383 (y <= bounds.height); |
391 } |
384 } |
392 return false; |
385 return false; |
393 } |
386 } |
394 |
387 |
395 public void handleVSBEvent(MouseEvent e, Rectangle bounds, int x, int y) { |
388 void handleVSBEvent(MouseEvent e, Rectangle bounds, int x, int y) { |
396 int sbHeight = hsbVis ? bounds.height - SCROLLBAR_WIDTH : bounds.height; |
389 int sbHeight = hsbVis ? bounds.height - SCROLLBAR_WIDTH : bounds.height; |
397 |
390 |
398 vsb.handleMouseEvent(e.getID(), |
391 vsb.handleMouseEvent(e.getID(), |
399 e.getModifiers(), |
392 e.getModifiers(), |
400 x - (bounds.width - SCROLLBAR_WIDTH), |
393 x - (bounds.width - SCROLLBAR_WIDTH), |
403 |
396 |
404 /* |
397 /* |
405 * Called when items are added/removed. |
398 * Called when items are added/removed. |
406 * Update whether the scrollbar is visible or not, scrollbar values |
399 * Update whether the scrollbar is visible or not, scrollbar values |
407 */ |
400 */ |
408 void updateScrollbars() { |
401 private void updateScrollbars() { |
409 boolean oldVsbVis = vsbVis; |
402 boolean oldVsbVis = vsbVis; |
410 vsbVis = vsb != null && items.size() > maxVisItems; |
403 vsbVis = vsb != null && items.size() > maxVisItems; |
411 if (vsbVis) { |
404 if (vsbVis) { |
412 vsb.setValues(vsb.getValue(), getNumItemsDisplayed(), |
405 vsb.setValues(vsb.getValue(), getNumItemsDisplayed(), |
413 vsb.getMinimum(), items.size()); |
406 vsb.getMinimum(), items.size()); |
418 // but draw3DRect doesn't clear the area inside. Instead it just paints lines as borders. |
411 // but draw3DRect doesn't clear the area inside. Instead it just paints lines as borders. |
419 vsbVisibilityChanged = (vsbVis != oldVsbVis); |
412 vsbVisibilityChanged = (vsbVis != oldVsbVis); |
420 // FIXME: check if added item makes a hsb necessary (if supported, that of course) |
413 // FIXME: check if added item makes a hsb necessary (if supported, that of course) |
421 } |
414 } |
422 |
415 |
423 public int getNumItemsDisplayed() { |
416 private int getNumItemsDisplayed() { |
424 return items.size() > maxVisItems ? maxVisItems : items.size(); |
417 return items.size() > maxVisItems ? maxVisItems : items.size(); |
425 } |
418 } |
426 |
419 |
|
420 @Override |
427 public void repaintScrollbarRequest(XScrollbar sb) { |
421 public void repaintScrollbarRequest(XScrollbar sb) { |
428 Graphics g = peer.getGraphics(); |
422 Graphics g = peer.getGraphics(); |
429 Rectangle bounds = peer.getBounds(); |
423 Rectangle bounds = peer.getBounds(); |
430 if ((sb == vsb) && vsbVis) { |
424 if ((sb == vsb) && vsbVis) { |
431 paintVSB(g, XComponentPeer.getSystemColors(), bounds); |
425 paintVSB(g, XComponentPeer.getSystemColors(), bounds); |
434 paintHSB(g, XComponentPeer.getSystemColors(), bounds); |
428 paintHSB(g, XComponentPeer.getSystemColors(), bounds); |
435 } |
429 } |
436 g.dispose(); |
430 g.dispose(); |
437 } |
431 } |
438 |
432 |
|
433 @Override |
439 public void notifyValue(XScrollbar obj, int type, int v, boolean isAdjusting) { |
434 public void notifyValue(XScrollbar obj, int type, int v, boolean isAdjusting) { |
440 if (obj == vsb) { |
435 if (obj == vsb) { |
441 int oldScrollValue = vsb.getValue(); |
436 int oldScrollValue = vsb.getValue(); |
442 vsb.setValue(v); |
437 vsb.setValue(v); |
443 boolean needRepaint = (oldScrollValue != vsb.getValue()); |
438 boolean needRepaint = (oldScrollValue != vsb.getValue()); |
479 int first, |
474 int first, |
480 int last, |
475 int last, |
481 XVerticalScrollbar vsb, |
476 XVerticalScrollbar vsb, |
482 XHorizontalScrollbar hsb) { |
477 XHorizontalScrollbar hsb) { |
483 */ |
478 */ |
484 public void paintItems(Graphics g, |
479 void paintItems(Graphics g, |
485 Color[] colors, |
480 Color[] colors, |
486 Rectangle bounds) { |
481 Rectangle bounds) { |
487 // paint border |
482 // paint border |
488 // paint items |
483 // paint items |
489 // paint scrollbars |
484 // paint scrollbars |
490 // paint focus? |
485 // paint focus? |
491 |
486 |
492 } |
487 } |
493 public void paintAllItems(Graphics g, |
488 void paintAllItems(Graphics g, |
494 Color[] colors, |
489 Color[] colors, |
495 Rectangle bounds) { |
490 Rectangle bounds) { |
496 paintItems(g, colors, bounds, |
491 paintItems(g, colors, bounds, |
497 firstDisplayedIndex(), lastDisplayedIndex()); |
492 firstDisplayedIndex(), lastDisplayedIndex()); |
498 } |
493 } |
499 public void paintItems(Graphics g, |
494 private void paintItems(Graphics g, Color[] colors, Rectangle bounds, |
500 Color[] colors, |
495 int first, int last) { |
501 Rectangle bounds, |
|
502 int first, |
|
503 int last) { |
|
504 peer.flush(); |
496 peer.flush(); |
505 int x = BORDER_WIDTH + ITEM_MARGIN; |
497 int x = BORDER_WIDTH + ITEM_MARGIN; |
506 int width = bounds.width - 2*ITEM_MARGIN - 2*BORDER_WIDTH - (vsbVis ? SCROLLBAR_WIDTH : 0); |
498 int width = bounds.width - 2*ITEM_MARGIN - 2*BORDER_WIDTH - (vsbVis ? SCROLLBAR_WIDTH : 0); |
507 int height = getItemHeight(); |
499 int height = getItemHeight(); |
508 int y = BORDER_WIDTH + ITEM_MARGIN; |
500 int y = BORDER_WIDTH + ITEM_MARGIN; |
527 } |
519 } |
528 |
520 |
529 /* |
521 /* |
530 * comment about what is painted (i.e. the focus rect |
522 * comment about what is painted (i.e. the focus rect |
531 */ |
523 */ |
532 public void paintItem(Graphics g, |
524 private void paintItem(Graphics g, Color[] colors, String string, int x, |
533 Color[] colors, |
525 int y, int width, int height, boolean selected, |
534 String string, |
526 boolean focused) { |
535 int x, int y, int width, int height, |
|
536 boolean selected, |
|
537 boolean focused) { |
|
538 //System.out.println("LP.pI(): x="+x+" y="+y+" w="+width+" h="+height); |
527 //System.out.println("LP.pI(): x="+x+" y="+y+" w="+width+" h="+height); |
539 //g.setColor(colors[BACKGROUND_COLOR]); |
528 //g.setColor(colors[BACKGROUND_COLOR]); |
540 |
529 |
541 // FIXME: items shouldn't draw into the scrollbar |
530 // FIXME: items shouldn't draw into the scrollbar |
542 |
531 |
573 |
562 |
574 g.drawString(string, x + TEXT_SPACE, y + (height + fm.getMaxAscent() - fm.getMaxDescent())/2); |
563 g.drawString(string, x + TEXT_SPACE, y + (height + fm.getMaxAscent() - fm.getMaxDescent())/2); |
575 //g.clipRect(clip.x, clip.y, clip.width, clip.height); |
564 //g.clipRect(clip.x, clip.y, clip.width, clip.height); |
576 } |
565 } |
577 |
566 |
578 boolean isItemSelected(int index) { |
567 private boolean isItemSelected(int index) { |
579 Iterator<Integer> itr = selected.iterator(); |
568 Iterator<Integer> itr = selected.iterator(); |
580 while (itr.hasNext()) { |
569 while (itr.hasNext()) { |
581 Integer val = itr.next(); |
570 Integer val = itr.next(); |
582 if (val.intValue() == index) { |
571 if (val.intValue() == index) { |
583 return true; |
572 return true; |
584 } |
573 } |
585 } |
574 } |
586 return false; |
575 return false; |
587 } |
576 } |
588 |
577 |
589 public void paintVSB(Graphics g, Color colors[], Rectangle bounds) { |
578 private void paintVSB(Graphics g, Color colors[], Rectangle bounds) { |
590 int height = bounds.height - 2*BORDER_WIDTH - (hsbVis ? (SCROLLBAR_WIDTH-2) : 0); |
579 int height = bounds.height - 2*BORDER_WIDTH - (hsbVis ? (SCROLLBAR_WIDTH-2) : 0); |
591 Graphics ng = g.create(); |
580 Graphics ng = g.create(); |
592 |
581 |
593 g.setColor(colors[XComponentPeer.BACKGROUND_COLOR]); |
582 g.setColor(colors[XComponentPeer.BACKGROUND_COLOR]); |
594 try { |
583 try { |