44 |
import java.awt.Graphics; |
import java.awt.Graphics; |
45 |
import java.awt.Point; |
import java.awt.Point; |
46 |
import java.awt.Rectangle; |
import java.awt.Rectangle; |
47 |
|
import java.awt.event.ActionEvent; |
48 |
|
import java.awt.event.ActionListener; |
49 |
import java.awt.event.ComponentAdapter; |
import java.awt.event.ComponentAdapter; |
50 |
import java.awt.event.ComponentEvent; |
import java.awt.event.ComponentEvent; |
51 |
import java.awt.event.ComponentListener; |
import java.awt.event.ComponentListener; |
52 |
import java.awt.event.FocusEvent; |
import java.awt.event.FocusEvent; |
53 |
import java.awt.event.FocusListener; |
import java.awt.event.FocusListener; |
|
import java.awt.event.InputEvent; |
|
|
import java.awt.event.KeyAdapter; |
|
54 |
import java.awt.event.KeyEvent; |
import java.awt.event.KeyEvent; |
55 |
import java.awt.event.MouseEvent; |
import java.awt.event.MouseEvent; |
56 |
import java.beans.PropertyChangeEvent; |
import java.beans.PropertyChangeEvent; |
57 |
import java.beans.PropertyChangeListener; |
import java.beans.PropertyChangeListener; |
58 |
|
|
59 |
|
import javax.swing.AbstractAction; |
60 |
|
import javax.swing.ActionMap; |
61 |
import javax.swing.CellRendererPane; |
import javax.swing.CellRendererPane; |
62 |
|
import javax.swing.DefaultListSelectionModel; |
63 |
|
import javax.swing.InputMap; |
64 |
import javax.swing.JComponent; |
import javax.swing.JComponent; |
65 |
import javax.swing.JList; |
import javax.swing.JList; |
66 |
import javax.swing.JViewport; |
import javax.swing.JViewport; |
67 |
|
import javax.swing.KeyStroke; |
68 |
import javax.swing.ListCellRenderer; |
import javax.swing.ListCellRenderer; |
69 |
import javax.swing.ListModel; |
import javax.swing.ListModel; |
70 |
import javax.swing.ListSelectionModel; |
import javax.swing.ListSelectionModel; |
71 |
|
import javax.swing.LookAndFeel; |
72 |
import javax.swing.UIDefaults; |
import javax.swing.UIDefaults; |
73 |
import javax.swing.UIManager; |
import javax.swing.UIManager; |
74 |
import javax.swing.event.ListDataEvent; |
import javax.swing.event.ListDataEvent; |
77 |
import javax.swing.event.ListSelectionListener; |
import javax.swing.event.ListSelectionListener; |
78 |
import javax.swing.event.MouseInputListener; |
import javax.swing.event.MouseInputListener; |
79 |
import javax.swing.plaf.ComponentUI; |
import javax.swing.plaf.ComponentUI; |
80 |
|
import javax.swing.plaf.InputMapUIResource; |
81 |
import javax.swing.plaf.ListUI; |
import javax.swing.plaf.ListUI; |
82 |
|
|
83 |
/** |
/** |
132 |
* Helper method to repaint the focused cell's |
* Helper method to repaint the focused cell's |
133 |
* lost or acquired focus state. |
* lost or acquired focus state. |
134 |
*/ |
*/ |
135 |
void repaintCellFocus() |
protected void repaintCellFocus() |
136 |
{ |
{ |
137 |
|
// TODO: Implement this properly. |
138 |
} |
} |
139 |
} |
} |
140 |
|
|
191 |
*/ |
*/ |
192 |
public void valueChanged(ListSelectionEvent e) |
public void valueChanged(ListSelectionEvent e) |
193 |
{ |
{ |
194 |
|
// TODO: Implement this properly. |
195 |
} |
} |
196 |
} |
} |
197 |
|
|
198 |
/** |
/** |
199 |
* A helper class which listens for {@link KeyEvents}s |
* This class is used to mimmic the behaviour of the JDK when registering |
200 |
* from the {@link JList}. |
* keyboard actions. It is the same as the private class used in JComponent |
201 |
|
* for the same reason. This class receives an action event and dispatches |
202 |
|
* it to the true receiver after altering the actionCommand property of the |
203 |
|
* event. |
204 |
*/ |
*/ |
205 |
private class KeyHandler extends KeyAdapter |
private static class ActionListenerProxy |
206 |
|
extends AbstractAction |
207 |
{ |
{ |
208 |
public KeyHandler() |
ActionListener target; |
209 |
|
String bindingCommandName; |
210 |
|
|
211 |
|
public ActionListenerProxy(ActionListener li, |
212 |
|
String cmd) |
213 |
|
{ |
214 |
|
target = li; |
215 |
|
bindingCommandName = cmd; |
216 |
|
} |
217 |
|
|
218 |
|
public void actionPerformed(ActionEvent e) |
219 |
{ |
{ |
220 |
|
ActionEvent derivedEvent = new ActionEvent(e.getSource(), |
221 |
|
e.getID(), |
222 |
|
bindingCommandName, |
223 |
|
e.getModifiers()); |
224 |
|
target.actionPerformed(derivedEvent); |
225 |
} |
} |
226 |
|
} |
227 |
public void keyPressed( KeyEvent evt ) |
|
228 |
|
class ListAction extends AbstractAction |
229 |
|
{ |
230 |
|
public void actionPerformed (ActionEvent e) |
231 |
{ |
{ |
232 |
int lead = BasicListUI.this.list.getLeadSelectionIndex(); |
int lead = list.getLeadSelectionIndex(); |
233 |
int max = BasicListUI.this.list.getModel().getSize() - 1; |
int max = list.getModel().getSize() - 1; |
234 |
|
DefaultListSelectionModel selModel = (DefaultListSelectionModel)list.getSelectionModel(); |
235 |
|
String command = e.getActionCommand(); |
236 |
// Do nothing if list is empty |
// Do nothing if list is empty |
237 |
if (max == -1) |
if (max == -1) |
238 |
return; |
return; |
239 |
|
|
240 |
// Process the key event. Bindings can be found in |
if (command.equals("selectNextRow")) |
|
// javax.swing.plaf.basic.BasicLookAndFeel.java |
|
|
if ((evt.getKeyCode() == KeyEvent.VK_DOWN) |
|
|
|| (evt.getKeyCode() == KeyEvent.VK_KP_DOWN)) |
|
241 |
{ |
{ |
242 |
if (evt.getModifiers() == 0) |
selectNextIndex(); |
243 |
{ |
} |
244 |
BasicListUI.this.list.clearSelection(); |
else if (command.equals("selectPreviousRow")) |
245 |
BasicListUI.this.list.setSelectedIndex(Math.min(lead+1,max)); |
{ |
246 |
} |
selectPreviousIndex(); |
247 |
else if (evt.getModifiers() == InputEvent.SHIFT_MASK) |
} |
248 |
|
else if (command.equals("clearSelection")) |
249 |
|
{ |
250 |
|
list.clearSelection(); |
251 |
|
} |
252 |
|
else if (command.equals("selectAll")) |
253 |
|
{ |
254 |
|
list.setSelectionInterval(0, max); |
255 |
|
// this next line is to restore the lead selection index to the old |
256 |
|
// position, because select-all should not change the lead index |
257 |
|
list.addSelectionInterval(lead, lead); |
258 |
|
} |
259 |
|
else if (command.equals("selectLastRow")) |
260 |
|
{ |
261 |
|
list.setSelectedIndex(list.getModel().getSize() - 1); |
262 |
|
} |
263 |
|
else if (command.equals("selectLastRowChangeLead")) |
264 |
|
{ |
265 |
|
selModel.moveLeadSelectionIndex(list.getModel().getSize() - 1); |
266 |
|
} |
267 |
|
else if (command.equals("scrollDownExtendSelection")) |
268 |
|
{ |
269 |
|
int target; |
270 |
|
if (lead == list.getLastVisibleIndex()) |
271 |
{ |
{ |
272 |
BasicListUI.this.list.getSelectionModel(). |
target = Math.min |
273 |
setLeadSelectionIndex(Math.min(lead+1,max)); |
(max, lead + (list.getLastVisibleIndex() - |
274 |
|
list.getFirstVisibleIndex() + 1)); |
275 |
} |
} |
276 |
|
else |
277 |
|
target = list.getLastVisibleIndex(); |
278 |
|
selModel.setLeadSelectionIndex(target); |
279 |
} |
} |
280 |
else if ((evt.getKeyCode() == KeyEvent.VK_UP) |
else if (command.equals("scrollDownChangeLead")) |
|
|| (evt.getKeyCode() == KeyEvent.VK_KP_UP)) |
|
281 |
{ |
{ |
282 |
if (evt.getModifiers() == 0) |
int target; |
283 |
|
if (lead == list.getLastVisibleIndex()) |
284 |
{ |
{ |
285 |
BasicListUI.this.list.clearSelection(); |
target = Math.min |
286 |
BasicListUI.this.list.setSelectedIndex(Math.max(lead-1,0)); |
(max, lead + (list.getLastVisibleIndex() - |
287 |
|
list.getFirstVisibleIndex() + 1)); |
288 |
} |
} |
289 |
else if (evt.getModifiers() == InputEvent.SHIFT_MASK) |
else |
290 |
|
target = list.getLastVisibleIndex(); |
291 |
|
selModel.moveLeadSelectionIndex(target); |
292 |
|
} |
293 |
|
else if (command.equals("scrollUpExtendSelection")) |
294 |
|
{ |
295 |
|
int target; |
296 |
|
if (lead == list.getFirstVisibleIndex()) |
297 |
{ |
{ |
298 |
BasicListUI.this.list.getSelectionModel(). |
target = Math.max |
299 |
setLeadSelectionIndex(Math.max(lead-1,0)); |
(0, lead - (list.getLastVisibleIndex() - |
300 |
|
list.getFirstVisibleIndex() + 1)); |
301 |
} |
} |
302 |
|
else |
303 |
|
target = list.getFirstVisibleIndex(); |
304 |
|
selModel.setLeadSelectionIndex(target); |
305 |
} |
} |
306 |
else if (evt.getKeyCode() == KeyEvent.VK_PAGE_UP) |
else if (command.equals("scrollUpChangeLead")) |
307 |
{ |
{ |
308 |
int target; |
int target; |
309 |
if (lead == BasicListUI.this.list.getFirstVisibleIndex()) |
if (lead == list.getFirstVisibleIndex()) |
310 |
{ |
{ |
311 |
target = Math.max |
target = Math.max |
312 |
(0, lead - (BasicListUI.this.list.getLastVisibleIndex() - |
(0, lead - (list.getLastVisibleIndex() - |
313 |
BasicListUI.this.list.getFirstVisibleIndex() + 1)); |
list.getFirstVisibleIndex() + 1)); |
314 |
} |
} |
315 |
else |
else |
316 |
|
target = list.getFirstVisibleIndex(); |
317 |
|
selModel.moveLeadSelectionIndex(target); |
318 |
|
} |
319 |
|
else if (command.equals("selectNextRowExtendSelection")) |
320 |
|
{ |
321 |
|
selModel.setLeadSelectionIndex(Math.min(lead + 1,max)); |
322 |
|
} |
323 |
|
else if (command.equals("selectFirstRow")) |
324 |
|
{ |
325 |
|
list.setSelectedIndex(0); |
326 |
|
} |
327 |
|
else if (command.equals("selectFirstRowChangeLead")) |
328 |
|
{ |
329 |
|
selModel.moveLeadSelectionIndex(0); |
330 |
|
} |
331 |
|
else if (command.equals("selectFirstRowExtendSelection")) |
332 |
|
{ |
333 |
|
selModel.setLeadSelectionIndex(0); |
334 |
|
} |
335 |
|
else if (command.equals("selectPreviousRowExtendSelection")) |
336 |
|
{ |
337 |
|
selModel.setLeadSelectionIndex(Math.max(0,lead - 1)); |
338 |
|
} |
339 |
|
else if (command.equals("scrollUp")) |
340 |
|
{ |
341 |
|
int target; |
342 |
|
if (lead == list.getFirstVisibleIndex()) |
343 |
{ |
{ |
344 |
target = BasicListUI.this.list.getFirstVisibleIndex(); |
target = Math.max |
345 |
|
(0, lead - (list.getLastVisibleIndex() - |
346 |
|
list.getFirstVisibleIndex() + 1)); |
347 |
} |
} |
348 |
if (evt.getModifiers() == 0) |
else |
349 |
BasicListUI.this.list.setSelectedIndex(target); |
target = list.getFirstVisibleIndex(); |
350 |
else if (evt.getModifiers() == InputEvent.SHIFT_MASK) |
list.setSelectedIndex(target); |
351 |
BasicListUI.this.list.getSelectionModel(). |
} |
352 |
setLeadSelectionIndex(target); |
else if (command.equals("selectLastRowExtendSelection")) |
353 |
|
{ |
354 |
|
selModel.setLeadSelectionIndex(list.getModel().getSize() - 1); |
355 |
} |
} |
356 |
else if (evt.getKeyCode() == KeyEvent.VK_PAGE_DOWN) |
else if (command.equals("scrollDown")) |
357 |
{ |
{ |
358 |
int target; |
int target; |
359 |
if (lead == BasicListUI.this.list.getLastVisibleIndex()) |
if (lead == list.getLastVisibleIndex()) |
360 |
{ |
{ |
361 |
target = Math.min |
target = Math.min |
362 |
(max, lead + (BasicListUI.this.list.getLastVisibleIndex() - |
(max, lead + (list.getLastVisibleIndex() - |
363 |
BasicListUI.this.list.getFirstVisibleIndex() + 1)); |
list.getFirstVisibleIndex() + 1)); |
364 |
} |
} |
365 |
else |
else |
366 |
|
target = list.getLastVisibleIndex(); |
367 |
|
list.setSelectedIndex(target); |
368 |
|
} |
369 |
|
else if (command.equals("selectNextRowChangeLead")) |
370 |
|
{ |
371 |
|
if (selModel.getSelectionMode() != ListSelectionModel.MULTIPLE_INTERVAL_SELECTION) |
372 |
|
selectNextIndex(); |
373 |
|
else |
374 |
|
{ |
375 |
|
selModel.moveLeadSelectionIndex(Math.min(max, lead + 1)); |
376 |
|
} |
377 |
|
} |
378 |
|
else if (command.equals("selectPreviousRowChangeLead")) |
379 |
|
{ |
380 |
|
if (selModel.getSelectionMode() != ListSelectionModel.MULTIPLE_INTERVAL_SELECTION) |
381 |
|
selectPreviousIndex(); |
382 |
|
else |
383 |
{ |
{ |
384 |
target = BasicListUI.this.list.getLastVisibleIndex(); |
selModel.moveLeadSelectionIndex(Math.max(0, lead - 1)); |
385 |
} |
} |
386 |
if (evt.getModifiers() == 0) |
} |
387 |
BasicListUI.this.list.setSelectedIndex(target); |
else if (command.equals("addToSelection")) |
388 |
else if (evt.getModifiers() == InputEvent.SHIFT_MASK) |
{ |
389 |
BasicListUI.this.list.getSelectionModel(). |
list.addSelectionInterval(lead, lead); |
|
setLeadSelectionIndex(target); |
|
|
} |
|
|
else if (evt.getKeyCode() == KeyEvent.VK_BACK_SLASH |
|
|
&& (evt.getModifiers() == InputEvent.CTRL_MASK)) |
|
|
{ |
|
|
BasicListUI.this.list.clearSelection(); |
|
|
} |
|
|
else if ((evt.getKeyCode() == KeyEvent.VK_HOME) |
|
|
|| evt.getKeyCode() == KeyEvent.VK_END) |
|
|
{ |
|
|
if (evt.getModifiers() != 0 && |
|
|
evt.getModifiers() != InputEvent.SHIFT_MASK) |
|
|
return; |
|
|
// index is either 0 for HOME, or last cell for END |
|
|
int index = (evt.getKeyCode() == KeyEvent.VK_HOME) ? 0 : max; |
|
|
|
|
|
if (!evt.isShiftDown() ||(BasicListUI.this.list.getSelectionMode() |
|
|
== ListSelectionModel.SINGLE_SELECTION)) |
|
|
BasicListUI.this.list.setSelectedIndex(index); |
|
|
else if (BasicListUI.this.list.getSelectionMode() == |
|
|
ListSelectionModel.SINGLE_INTERVAL_SELECTION) |
|
|
BasicListUI.this.list.setSelectionInterval |
|
|
(BasicListUI.this.list.getAnchorSelectionIndex(), index); |
|
|
else |
|
|
BasicListUI.this.list.getSelectionModel(). |
|
|
setLeadSelectionIndex(index); |
|
390 |
} |
} |
391 |
else if ((evt.getKeyCode() == KeyEvent.VK_A || evt.getKeyCode() |
else if (command.equals("extendTo")) |
|
== KeyEvent.VK_SLASH) && (evt.getModifiers() == |
|
|
InputEvent.CTRL_MASK)) |
|
392 |
{ |
{ |
393 |
BasicListUI.this.list.setSelectionInterval(0, max); |
selModel.setSelectionInterval(selModel.getAnchorSelectionIndex(), |
394 |
// this next line is to restore the lead selection index to the old |
lead); |
|
// position, because select-all should not change the lead index |
|
|
BasicListUI.this.list.addSelectionInterval(lead, lead); |
|
395 |
} |
} |
396 |
else if (evt.getKeyCode() == KeyEvent.VK_SPACE && |
else if (command.equals("toggleAndAnchor")) |
|
(evt.getModifiers() == InputEvent.CTRL_MASK)) |
|
397 |
{ |
{ |
398 |
BasicListUI.this.list.getSelectionModel(). |
if (!list.isSelectedIndex(lead)) |
399 |
setLeadSelectionIndex(Math.min(lead+1,max)); |
list.addSelectionInterval(lead, lead); |
400 |
|
else |
401 |
|
list.removeSelectionInterval(lead, lead); |
402 |
|
selModel.setAnchorSelectionIndex(lead); |
403 |
} |
} |
404 |
|
else |
405 |
BasicListUI.this.list.ensureIndexIsVisible |
{ |
406 |
(BasicListUI.this.list.getLeadSelectionIndex()); |
// DEBUG: uncomment the following line to print out |
407 |
|
// key bindings that aren't implemented yet |
408 |
|
|
409 |
|
// System.out.println ("not implemented: "+e.getActionCommand()); |
410 |
|
} |
411 |
|
|
412 |
|
list.ensureIndexIsVisible(list.getLeadSelectionIndex()); |
413 |
} |
} |
414 |
} |
} |
415 |
|
|
416 |
/** |
/** |
417 |
* A helper class which listens for {@link MouseEvent}s |
* A helper class which listens for {@link MouseEvent}s |
418 |
* from the {@link JList}. |
* from the {@link JList}. |
428 |
public void mouseClicked(MouseEvent event) |
public void mouseClicked(MouseEvent event) |
429 |
{ |
{ |
430 |
Point click = event.getPoint(); |
Point click = event.getPoint(); |
431 |
int index = BasicListUI.this.locationToIndex(list, click); |
int index = locationToIndex(list, click); |
432 |
if (index == -1) |
if (index == -1) |
433 |
return; |
return; |
434 |
if (event.isShiftDown()) |
if (event.isShiftDown()) |
435 |
{ |
{ |
436 |
if (BasicListUI.this.list.getSelectionMode() == |
if (list.getSelectionMode() == ListSelectionModel.SINGLE_SELECTION) |
437 |
ListSelectionModel.SINGLE_SELECTION) |
list.setSelectedIndex(index); |
438 |
BasicListUI.this.list.setSelectedIndex(index); |
else if (list.getSelectionMode() == |
|
else if (BasicListUI.this.list.getSelectionMode() == |
|
439 |
ListSelectionModel.SINGLE_INTERVAL_SELECTION) |
ListSelectionModel.SINGLE_INTERVAL_SELECTION) |
440 |
// COMPAT: the IBM VM is compatible with the following line of code. |
// COMPAT: the IBM VM is compatible with the following line of code. |
441 |
// However, compliance with Sun's VM would correspond to replacing |
// However, compliance with Sun's VM would correspond to replacing |
442 |
// getAnchorSelectionIndex() with getLeadSelectionIndex().This is |
// getAnchorSelectionIndex() with getLeadSelectionIndex().This is |
443 |
// both unnatural and contradictory to the way they handle other |
// both unnatural and contradictory to the way they handle other |
444 |
// similar UI interactions. |
// similar UI interactions. |
445 |
BasicListUI.this.list.setSelectionInterval |
list.setSelectionInterval(list.getAnchorSelectionIndex(), index); |
|
(BasicListUI.this.list.getAnchorSelectionIndex(), index); |
|
446 |
else |
else |
447 |
// COMPAT: both Sun and IBM are compatible instead with: |
// COMPAT: both Sun and IBM are compatible instead with: |
448 |
// BasicListUI.this.list.setSelectionInterval |
// list.setSelectionInterval |
449 |
// (BasicListUI.this.list.getLeadSelectionIndex(),index); |
// (list.getLeadSelectionIndex(),index); |
450 |
// Note that for IBM this is contradictory to what they did in |
// Note that for IBM this is contradictory to what they did in |
451 |
// the above situation for SINGLE_INTERVAL_SELECTION. |
// the above situation for SINGLE_INTERVAL_SELECTION. |
452 |
// The most natural thing to do is the following: |
// The most natural thing to do is the following: |
453 |
BasicListUI.this.list.getSelectionModel(). |
if (list.isSelectedIndex(list.getAnchorSelectionIndex())) |
454 |
setLeadSelectionIndex(index); |
list.getSelectionModel().setLeadSelectionIndex(index); |
455 |
|
else |
456 |
|
list.addSelectionInterval(list.getAnchorSelectionIndex(), index); |
457 |
} |
} |
458 |
else if (event.isControlDown()) |
else if (event.isControlDown()) |
459 |
{ |
{ |
460 |
if (BasicListUI.this.list.getSelectionMode() == |
if (list.getSelectionMode() == ListSelectionModel.SINGLE_SELECTION) |
461 |
ListSelectionModel.SINGLE_SELECTION) |
list.setSelectedIndex(index); |
462 |
BasicListUI.this.list.setSelectedIndex(index); |
else if (list.isSelectedIndex(index)) |
463 |
else if (BasicListUI.this.list.isSelectedIndex(index)) |
list.removeSelectionInterval(index,index); |
|
BasicListUI.this.list.removeSelectionInterval(index,index); |
|
464 |
else |
else |
465 |
BasicListUI.this.list.addSelectionInterval(index,index); |
list.addSelectionInterval(index,index); |
466 |
} |
} |
467 |
else |
else |
468 |
BasicListUI.this.list.setSelectedIndex(index); |
list.setSelectedIndex(index); |
469 |
|
|
470 |
BasicListUI.this.list.ensureIndexIsVisible |
list.ensureIndexIsVisible(list.getLeadSelectionIndex()); |
|
(BasicListUI.this.list.getLeadSelectionIndex()); |
|
471 |
} |
} |
472 |
|
|
473 |
/** |
/** |
478 |
*/ |
*/ |
479 |
public void mousePressed(MouseEvent event) |
public void mousePressed(MouseEvent event) |
480 |
{ |
{ |
481 |
|
// TODO: What should be done here, if anything? |
482 |
} |
} |
483 |
|
|
484 |
/** |
/** |
489 |
*/ |
*/ |
490 |
public void mouseReleased(MouseEvent event) |
public void mouseReleased(MouseEvent event) |
491 |
{ |
{ |
492 |
|
// TODO: What should be done here, if anything? |
493 |
} |
} |
494 |
|
|
495 |
/** |
/** |
500 |
*/ |
*/ |
501 |
public void mouseEntered(MouseEvent event) |
public void mouseEntered(MouseEvent event) |
502 |
{ |
{ |
503 |
|
// TODO: What should be done here, if anything? |
504 |
} |
} |
505 |
|
|
506 |
/** |
/** |
511 |
*/ |
*/ |
512 |
public void mouseExited(MouseEvent event) |
public void mouseExited(MouseEvent event) |
513 |
{ |
{ |
514 |
|
// TODO: What should be done here, if anything? |
515 |
} |
} |
516 |
|
|
517 |
/** |
/** |
522 |
*/ |
*/ |
523 |
public void mouseDragged(MouseEvent event) |
public void mouseDragged(MouseEvent event) |
524 |
{ |
{ |
525 |
|
// TODO: What should be done here, if anything? |
526 |
} |
} |
527 |
|
|
528 |
/** |
/** |
533 |
*/ |
*/ |
534 |
public void mouseMoved(MouseEvent event) |
public void mouseMoved(MouseEvent event) |
535 |
{ |
{ |
536 |
|
// TODO: What should be done here, if anything? |
537 |
} |
} |
538 |
} |
} |
539 |
|
|
558 |
if (e.getNewValue() != null && e.getNewValue() instanceof ListModel) |
if (e.getNewValue() != null && e.getNewValue() instanceof ListModel) |
559 |
((ListModel) e.getNewValue()).addListDataListener(BasicListUI.this.listDataListener); |
((ListModel) e.getNewValue()).addListDataListener(BasicListUI.this.listDataListener); |
560 |
} |
} |
561 |
|
// Update the updateLayoutStateNeeded flag. |
562 |
|
if (e.getPropertyName().equals("model")) |
563 |
|
updateLayoutStateNeeded += modelChanged; |
564 |
|
else if (e.getPropertyName().equals("selectionModel")) |
565 |
|
updateLayoutStateNeeded += selectionModelChanged; |
566 |
|
else if (e.getPropertyName().equals("font")) |
567 |
|
updateLayoutStateNeeded += fontChanged; |
568 |
|
else if (e.getPropertyName().equals("fixedCellWidth")) |
569 |
|
updateLayoutStateNeeded += fixedCellWidthChanged; |
570 |
|
else if (e.getPropertyName().equals("fixedCellHeight")) |
571 |
|
updateLayoutStateNeeded += fixedCellHeightChanged; |
572 |
|
else if (e.getPropertyName().equals("prototypeCellValue")) |
573 |
|
updateLayoutStateNeeded += prototypeCellValueChanged; |
574 |
|
else if (e.getPropertyName().equals("cellRenderer")) |
575 |
|
updateLayoutStateNeeded += cellRendererChanged; |
576 |
|
|
577 |
BasicListUI.this.damageLayout(); |
BasicListUI.this.damageLayout(); |
578 |
} |
} |
579 |
} |
} |
580 |
|
|
581 |
/** |
/** |
582 |
|
* A constant to indicate that the model has changed. |
583 |
|
*/ |
584 |
|
protected static final int modelChanged = 1; |
585 |
|
|
586 |
|
/** |
587 |
|
* A constant to indicate that the selection model has changed. |
588 |
|
*/ |
589 |
|
protected static final int selectionModelChanged = 2; |
590 |
|
|
591 |
|
/** |
592 |
|
* A constant to indicate that the font has changed. |
593 |
|
*/ |
594 |
|
protected static final int fontChanged = 4; |
595 |
|
|
596 |
|
/** |
597 |
|
* A constant to indicate that the fixedCellWidth has changed. |
598 |
|
*/ |
599 |
|
protected static final int fixedCellWidthChanged = 8; |
600 |
|
|
601 |
|
/** |
602 |
|
* A constant to indicate that the fixedCellHeight has changed. |
603 |
|
*/ |
604 |
|
protected static final int fixedCellHeightChanged = 16; |
605 |
|
|
606 |
|
/** |
607 |
|
* A constant to indicate that the prototypeCellValue has changed. |
608 |
|
*/ |
609 |
|
protected static final int prototypeCellValueChanged = 32; |
610 |
|
|
611 |
|
/** |
612 |
|
* A constant to indicate that the cellRenderer has changed. |
613 |
|
*/ |
614 |
|
protected static final int cellRendererChanged = 64; |
615 |
|
|
616 |
|
/** |
617 |
* Creates a new BasicListUI for the component. |
* Creates a new BasicListUI for the component. |
618 |
* |
* |
619 |
* @param c The component to create a UI for |
* @param c The component to create a UI for |
637 |
/** The mouse listener listening to the list. */ |
/** The mouse listener listening to the list. */ |
638 |
protected MouseInputListener mouseInputListener; |
protected MouseInputListener mouseInputListener; |
639 |
|
|
|
/** The key listener listening to the list */ |
|
|
private KeyHandler keyListener; |
|
|
|
|
640 |
/** The property change listener listening to the list. */ |
/** The property change listener listening to the list. */ |
641 |
protected PropertyChangeListener propertyChangeListener; |
protected PropertyChangeListener propertyChangeListener; |
642 |
|
|
661 |
protected int[] cellHeights; |
protected int[] cellHeights; |
662 |
|
|
663 |
/** |
/** |
664 |
* A simple counter. When nonzero, indicates that the UI class is out of |
* A bitmask that indicates which properties of the JList have changed. |
665 |
|
* When nonzero, indicates that the UI class is out of |
666 |
* date with respect to the underlying list, and must recalculate the |
* date with respect to the underlying list, and must recalculate the |
667 |
* list layout before painting or performing size calculations. |
* list layout before painting or performing size calculations. |
668 |
|
* |
669 |
|
* @see #modelChanged |
670 |
|
* @see #selectionModelChanged |
671 |
|
* @see #fontChanged |
672 |
|
* @see #fixedCellWidthChanged |
673 |
|
* @see #fixedCellHeightChanged |
674 |
|
* @see #prototypeCellValueChanged |
675 |
|
* @see #cellRendererChanged |
676 |
*/ |
*/ |
677 |
protected int updateLayoutStateNeeded; |
protected int updateLayoutStateNeeded; |
678 |
|
|
680 |
* The {@link CellRendererPane} that is used for painting. |
* The {@link CellRendererPane} that is used for painting. |
681 |
*/ |
*/ |
682 |
protected CellRendererPane rendererPane; |
protected CellRendererPane rendererPane; |
683 |
|
|
684 |
|
/** The action bound to KeyStrokes. */ |
685 |
|
ListAction action; |
686 |
|
|
687 |
/** |
/** |
688 |
* Calculate the height of a particular row. If there is a fixed {@link |
* Calculate the height of a particular row. If there is a fixed {@link |
853 |
*/ |
*/ |
854 |
public BasicListUI() |
public BasicListUI() |
855 |
{ |
{ |
|
focusListener = new FocusHandler(); |
|
|
listDataListener = new ListDataHandler(); |
|
|
listSelectionListener = new ListSelectionHandler(); |
|
|
mouseInputListener = new MouseInputHandler(); |
|
|
keyListener = new KeyHandler(); |
|
|
propertyChangeListener = new PropertyChangeHandler(); |
|
|
componentListener = new ComponentHandler(); |
|
856 |
updateLayoutStateNeeded = 1; |
updateLayoutStateNeeded = 1; |
857 |
rendererPane = new CellRendererPane(); |
rendererPane = new CellRendererPane(); |
858 |
} |
} |
865 |
*/ |
*/ |
866 |
protected void installDefaults() |
protected void installDefaults() |
867 |
{ |
{ |
868 |
UIDefaults defaults = UIManager.getLookAndFeelDefaults(); |
LookAndFeel.installColorsAndFont(list, "List.background", |
869 |
list.setForeground(defaults.getColor("List.foreground")); |
"List.foreground", "List.font"); |
870 |
list.setBackground(defaults.getColor("List.background")); |
list.setSelectionForeground(UIManager.getColor("List.selectionForeground")); |
871 |
list.setSelectionForeground(defaults.getColor("List.selectionForeground")); |
list.setSelectionBackground(UIManager.getColor("List.selectionBackground")); |
|
list.setSelectionBackground(defaults.getColor("List.selectionBackground")); |
|
872 |
list.setOpaque(true); |
list.setOpaque(true); |
873 |
} |
} |
874 |
|
|
893 |
*/ |
*/ |
894 |
protected void installListeners() |
protected void installListeners() |
895 |
{ |
{ |
896 |
|
if (focusListener == null) |
897 |
|
focusListener = createFocusListener(); |
898 |
list.addFocusListener(focusListener); |
list.addFocusListener(focusListener); |
899 |
|
if (listDataListener == null) |
900 |
|
listDataListener = createListDataListener(); |
901 |
list.getModel().addListDataListener(listDataListener); |
list.getModel().addListDataListener(listDataListener); |
902 |
|
if (listSelectionListener == null) |
903 |
|
listSelectionListener = createListSelectionListener(); |
904 |
list.addListSelectionListener(listSelectionListener); |
list.addListSelectionListener(listSelectionListener); |
905 |
|
if (mouseInputListener == null) |
906 |
|
mouseInputListener = createMouseInputListener(); |
907 |
list.addMouseListener(mouseInputListener); |
list.addMouseListener(mouseInputListener); |
|
list.addKeyListener(keyListener); |
|
908 |
list.addMouseMotionListener(mouseInputListener); |
list.addMouseMotionListener(mouseInputListener); |
909 |
|
if (propertyChangeListener == null) |
910 |
|
propertyChangeListener = createPropertyChangeListener(); |
911 |
list.addPropertyChangeListener(propertyChangeListener); |
list.addPropertyChangeListener(propertyChangeListener); |
912 |
|
|
913 |
|
// FIXME: Are these two really needed? At least they are not documented. |
914 |
|
//keyListener = new KeyHandler(); |
915 |
list.addComponentListener(componentListener); |
list.addComponentListener(componentListener); |
916 |
|
componentListener = new ComponentHandler(); |
917 |
|
//list.addKeyListener(keyListener); |
918 |
} |
} |
919 |
|
|
920 |
/** |
/** |
926 |
list.getModel().removeListDataListener(listDataListener); |
list.getModel().removeListDataListener(listDataListener); |
927 |
list.removeListSelectionListener(listSelectionListener); |
list.removeListSelectionListener(listSelectionListener); |
928 |
list.removeMouseListener(mouseInputListener); |
list.removeMouseListener(mouseInputListener); |
929 |
list.removeKeyListener(keyListener); |
//list.removeKeyListener(keyListener); |
930 |
list.removeMouseMotionListener(mouseInputListener); |
list.removeMouseMotionListener(mouseInputListener); |
931 |
list.removePropertyChangeListener(propertyChangeListener); |
list.removePropertyChangeListener(propertyChangeListener); |
932 |
} |
} |
933 |
|
|
934 |
/** |
/** |
935 |
* Installs keyboard actions for this UI in the {@link JList}. |
* Installs keyboard actions for this UI in the {@link JList}. |
936 |
*/ |
*/ |
937 |
protected void installKeyboardActions() |
protected void installKeyboardActions() |
938 |
{ |
{ |
939 |
|
UIDefaults defaults = UIManager.getLookAndFeelDefaults(); |
940 |
|
InputMap focusInputMap = (InputMap)defaults.get("List.focusInputMap"); |
941 |
|
InputMapUIResource parentInputMap = new InputMapUIResource(); |
942 |
|
// FIXME: The JDK uses a LazyActionMap for parentActionMap |
943 |
|
ActionMap parentActionMap = new ActionMap(); |
944 |
|
action = new ListAction(); |
945 |
|
Object keys[] = focusInputMap.allKeys(); |
946 |
|
// Register key bindings in the UI InputMap-ActionMap pair |
947 |
|
for (int i = 0; i < keys.length; i++) |
948 |
|
{ |
949 |
|
KeyStroke stroke = (KeyStroke)keys[i]; |
950 |
|
String actionString = (String) focusInputMap.get(stroke); |
951 |
|
parentInputMap.put(KeyStroke.getKeyStroke(stroke.getKeyCode(), |
952 |
|
stroke.getModifiers()), |
953 |
|
actionString); |
954 |
|
|
955 |
|
parentActionMap.put (actionString, |
956 |
|
new ActionListenerProxy(action, actionString)); |
957 |
|
} |
958 |
|
// Register the new InputMap-ActionMap as the parents of the list's |
959 |
|
// InputMap and ActionMap |
960 |
|
parentInputMap.setParent(list.getInputMap().getParent()); |
961 |
|
parentActionMap.setParent(list.getActionMap().getParent()); |
962 |
|
list.getInputMap().setParent(parentInputMap); |
963 |
|
list.getActionMap().setParent(parentActionMap); |
964 |
} |
} |
965 |
|
|
966 |
/** |
/** |
968 |
*/ |
*/ |
969 |
protected void uninstallKeyboardActions() |
protected void uninstallKeyboardActions() |
970 |
{ |
{ |
971 |
|
// TODO: Implement this properly. |
972 |
} |
} |
973 |
|
|
974 |
/** |
/** |
1236 |
} |
} |
1237 |
return loc; |
return loc; |
1238 |
} |
} |
1239 |
|
|
1240 |
|
/** |
1241 |
|
* Creates and returns the focus listener for this UI. |
1242 |
|
* |
1243 |
|
* @return the focus listener for this UI |
1244 |
|
*/ |
1245 |
|
protected FocusListener createFocusListener() |
1246 |
|
{ |
1247 |
|
return new FocusHandler(); |
1248 |
|
} |
1249 |
|
|
1250 |
|
/** |
1251 |
|
* Creates and returns the list data listener for this UI. |
1252 |
|
* |
1253 |
|
* @return the list data listener for this UI |
1254 |
|
*/ |
1255 |
|
protected ListDataListener createListDataListener() |
1256 |
|
{ |
1257 |
|
return new ListDataHandler(); |
1258 |
|
} |
1259 |
|
|
1260 |
|
/** |
1261 |
|
* Creates and returns the list selection listener for this UI. |
1262 |
|
* |
1263 |
|
* @return the list selection listener for this UI |
1264 |
|
*/ |
1265 |
|
protected ListSelectionListener createListSelectionListener() |
1266 |
|
{ |
1267 |
|
return new ListSelectionHandler(); |
1268 |
|
} |
1269 |
|
|
1270 |
|
/** |
1271 |
|
* Creates and returns the mouse input listener for this UI. |
1272 |
|
* |
1273 |
|
* @return the mouse input listener for this UI |
1274 |
|
*/ |
1275 |
|
protected MouseInputListener createMouseInputListener() |
1276 |
|
{ |
1277 |
|
return new MouseInputHandler(); |
1278 |
|
} |
1279 |
|
|
1280 |
|
/** |
1281 |
|
* Creates and returns the property change listener for this UI. |
1282 |
|
* |
1283 |
|
* @return the property change listener for this UI |
1284 |
|
*/ |
1285 |
|
protected PropertyChangeListener createPropertyChangeListener() |
1286 |
|
{ |
1287 |
|
return new PropertyChangeHandler(); |
1288 |
|
} |
1289 |
|
|
1290 |
|
/** |
1291 |
|
* Selects the next list item and force it to be visible. |
1292 |
|
*/ |
1293 |
|
protected void selectNextIndex() |
1294 |
|
{ |
1295 |
|
int index = list.getSelectionModel().getLeadSelectionIndex(); |
1296 |
|
if (index < list.getModel().getSize() - 1) |
1297 |
|
{ |
1298 |
|
index++; |
1299 |
|
list.setSelectedIndex(index); |
1300 |
|
} |
1301 |
|
list.ensureIndexIsVisible(index); |
1302 |
|
} |
1303 |
|
|
1304 |
|
/** |
1305 |
|
* Selects the previous list item and force it to be visible. |
1306 |
|
*/ |
1307 |
|
protected void selectPreviousIndex() |
1308 |
|
{ |
1309 |
|
int index = list.getSelectionModel().getLeadSelectionIndex(); |
1310 |
|
if (index > 0) |
1311 |
|
{ |
1312 |
|
index--; |
1313 |
|
list.setSelectedIndex(index); |
1314 |
|
} |
1315 |
|
list.ensureIndexIsVisible(index); |
1316 |
|
} |
1317 |
} |
} |