23 package com.realtime.crossfire.jxclient.gui.list;
35 import java.awt.Adjustable;
36 import java.awt.Dimension;
37 import java.awt.Point;
38 import java.awt.Rectangle;
39 import java.awt.event.MouseEvent;
40 import javax.swing.DefaultListModel;
41 import javax.swing.JList;
42 import javax.swing.JScrollPane;
43 import javax.swing.JViewport;
44 import javax.swing.ListSelectionModel;
45 import javax.swing.ScrollPaneConstants;
46 import javax.swing.border.EmptyBorder;
47 import javax.swing.event.ListSelectionListener;
48 import org.jetbrains.annotations.NotNull;
49 import org.jetbrains.annotations.Nullable;
91 private final DefaultListModel<T>
model =
new DefaultListModel<>();
149 list.setFixedCellWidth(cellWidth);
151 list.setOpaque(
false);
152 list.setFocusable(
false);
153 list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
157 viewport.setScrollMode(JViewport.BLIT_SCROLL_MODE);
161 scrollPane =
new JScrollPane(
null, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
165 scrollPane.setBorder(
new EmptyBorder(0, 0, 0, 0));
176 synchronized (getTreeLock()) {
188 return model.get(index);
196 assert Thread.holdsLock(getTreeLock());
197 model.addElement(element);
198 list.setSize(getWidth(), Integer.MAX_VALUE);
200 if (
model.getSize() == 1) {
213 assert Thread.holdsLock(getTreeLock());
214 final int index =
list.getSelectedIndex();
215 final int oldSize =
model.getSize();
216 if (newSize < oldSize) {
217 for (
int i = newSize; i < oldSize; i++) {
223 model.removeRange(newSize, oldSize-1);
224 list.setSize(getWidth(), Integer.MAX_VALUE);
225 if (index >= newSize && newSize > 0) {
240 synchronized (getTreeLock()) {
242 final int distance =
switch (
list.getLayoutOrientation()) {
243 case JList.HORIZONTAL_WRAP -> (
list.getWidth()/
cellHeight)*diffLines+diffElements;
244 default -> diffLines+diffElements;
246 final int index =
list.getSelectedIndex();
248 return index == -1 || index+distance <
list.getModel().getSize();
252 return index == -1 || index >= -distance;
264 synchronized (getTreeLock()) {
266 final int distance =
switch (
list.getLayoutOrientation()) {
267 case JList.HORIZONTAL_WRAP -> (
list.getWidth()/
cellHeight)*diffLines+diffElements;
268 default -> diffLines+diffElements;
270 final int index =
list.getSelectedIndex();
273 newIndex = index == -1 ? 0 : Math.min(index+distance,
list.getModel().getSize()-1);
274 }
else if (distance < 0) {
277 newIndex =
list.getModel().getSize()-1;
279 newIndex = Math.max(index+distance, 0);
282 newIndex = index == -1 ? 0 : index;
295 synchronized (getTreeLock()) {
296 final Adjustable scrollBar =
scrollPane.getVerticalScrollBar();
298 return scrollBar.getValue() < scrollBar.getMaximum()-scrollBar.getVisibleAmount();
302 return scrollBar.getValue() > scrollBar.getMinimum();
314 synchronized (getTreeLock()) {
315 final Adjustable scrollBar =
scrollPane.getVerticalScrollBar();
316 final int value = scrollBar.getValue()+distance*
cellHeight;
317 scrollBar.setValue(value);
318 final int index =
list.getSelectedIndex();
320 final int firstIndex =
list.getFirstVisibleIndex();
321 if (index < firstIndex) {
323 switch (
list.getLayoutOrientation()) {
324 case JList.HORIZONTAL_WRAP:
334 final int lastIndex =
list.getLastVisibleIndex();
335 if (index > lastIndex) {
337 switch (
list.getLayoutOrientation()) {
338 case JList.HORIZONTAL_WRAP:
340 final int newTmpColumn = lastIndex-lastIndex%columns+index%columns;
342 if (newTmpColumn <= lastIndex) {
343 newColumn = newTmpColumn;
345 newColumn = newTmpColumn >= columns ? newTmpColumn-columns : lastIndex;
374 super.mouseClicked(e);
379 super.mouseEntered(e);
387 super.mouseExited(e);
395 super.mousePressed(e);
411 super.mouseDragged(e);
419 super.mouseWheelMoved(wheelRotation);
427 private void doSelect(@NotNull
final MouseEvent e) {
428 synchronized (getTreeLock()) {
441 synchronized (getTreeLock()) {
462 private Rec
getIndex(@NotNull
final MouseEvent e) {
463 final Point point = e.getPoint();
464 final Point location =
list.getLocation();
465 point.translate(-location.x, -location.y);
467 final int index =
list.locationToIndex(point);
472 final Rectangle rectangle =
list.getCellBounds(index, index);
473 if (rectangle ==
null || !rectangle.contains(point)) {
476 rectangle.translate(location.x, location.y);
478 return new Rec(index, rectangle);
486 synchronized (getTreeLock()) {
487 final int newIndex2 = Math.min(Math.max(newIndex, 0),
list.getModel().getSize()-1);
488 final int index =
list.getSelectedIndex();
489 if (newIndex2 == index) {
493 list.setSelectedIndex(newIndex2);
494 if (newIndex2 >= 0) {
495 list.ensureIndexIsVisible(newIndex2);
505 synchronized (getTreeLock()) {
530 if (rectangle ==
null) {
542 return text ==
null ? null :
new TooltipText(text, gui.
getComponent().getX()+getX()+rectangle.x, gui.
getComponent().getY()+getY()+rectangle.y, rectangle.width, rectangle.height);
556 protected abstract String
getTooltip(
final int index);
565 synchronized (getTreeLock()) {
566 list.setLayoutOrientation(layoutOrientation);
567 list.setVisibleRowCount(visibleRowCount);
577 synchronized (getTreeLock()) {
578 return list.getSelectedValue();
583 @SuppressWarnings(
"MethodDoesntCallSuperMethod")
585 return new Dimension(64, 64);
589 @SuppressWarnings(
"MethodDoesntCallSuperMethod")
591 return list.getMinimumSize();
595 @SuppressWarnings(
"MethodDoesntCallSuperMethod")
597 return new Dimension(320, 160);
601 public void setBounds(
final int x,
final int y,
final int width,
final int height) {
602 super.setBounds(x, y, width, height);
610 private static class Rec {