Created
April 29, 2010 07:28
-
-
Save lqd/383266 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.hybird.tests.ui; | |
import java.awt.*; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import javax.swing.*; | |
import javax.swing.border.EmptyBorder; | |
public class ListViewTest | |
{ | |
public static void main (String [] args) | |
{ | |
SwingUtilities.invokeLater (new Runnable() | |
{ | |
@Override | |
public void run () | |
{ | |
JFrame f = new JFrame ("Virtualized ListView"); | |
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); | |
JPanel main = new JPanel (new BorderLayout ()); | |
ListView list = new ListView (); | |
list.setProvider (new LabeledCellProvider()); | |
list.setRenderer (new StripingCellRenderer()); | |
list.setModel (new ListViewModel (100)); | |
list.setPreferredSize (new Dimension (640, 480)); | |
main.add (list, BorderLayout.CENTER); | |
f.setContentPane (main); | |
f.pack (); | |
f.setLocationRelativeTo (null); | |
f.setVisible (true); | |
} | |
}); | |
} | |
public static abstract class CellProvider | |
{ | |
private List<Cell> availableCells, usedCells; | |
public CellProvider() | |
{ | |
availableCells = new ArrayList<Cell>(); | |
usedCells = new ArrayList<Cell>(); | |
} | |
public abstract Cell createCell (ListView list); | |
public Cell getUnusedCell (ListView list) | |
{ | |
if (availableCells.isEmpty()) | |
{ | |
Cell cell = createCell (list); | |
list.view.add (cell); | |
markCellAvailable (list, cell); | |
} | |
return availableCells.get (0); | |
} | |
public void markCellUsed (ListView list, Cell cell) | |
{ | |
usedCells.add (cell); | |
availableCells.remove (cell); | |
} | |
public void markCellAvailable (ListView list, Cell cell) | |
{ | |
availableCells.add (cell); | |
usedCells.remove (cell); | |
} | |
public void markAllUsedCellsAvailable () | |
{ | |
for (int i = usedCells.size(); i-- > 0; ) | |
{ | |
Cell usedCell = usedCells.get (i); | |
markCellAvailable (null, usedCell); | |
} | |
usedCells.clear(); | |
} | |
} | |
public static class LabeledCell extends Cell | |
{ | |
private JLabel label; | |
public void setLabel (String text) | |
{ | |
if (label == null) | |
{ | |
label = new JLabel (); | |
add (label); | |
} | |
label.setText (text); | |
} | |
} | |
public static class LabeledCellProvider extends CellProvider | |
{ | |
@Override | |
public Cell createCell (ListView list) | |
{ | |
return new LabeledCell (); | |
} | |
} | |
public static class StripingCellRenderer implements CellRenderer | |
{ | |
private Color [] colors = {Color.orange, Color.yellow}; | |
@Override | |
public Cell renderCell (ListView list, Cell cell, Object value, int row) | |
{ | |
LabeledCell x = (LabeledCell) cell; | |
cell.setBackground (colors [row % colors.length]); | |
x.setLabel (value.toString ()); | |
cell.setPreferredSize (new Dimension (-1, x.label.getPreferredSize().height + row)); | |
// if (row % 3 == 0) | |
// list.setCellHeight (row, 50); | |
return cell; | |
} | |
} | |
public static interface CellRenderer | |
{ | |
Cell renderCell (ListView list, Cell cell, Object value, int row); | |
} | |
public static class ListView extends JScrollPane | |
{ | |
private JPanel view; | |
private CellProvider provider; | |
public ListView () | |
{ | |
super (JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); | |
setBorder (new EmptyBorder (new Insets (0, 0, 0, 0))); | |
view = new JPanel (null); | |
view.setBackground (Color.green); | |
setViewportView (view); | |
provider = new CellProvider() | |
{ | |
@Override | |
public Cell createCell (ListView list) | |
{ | |
return new Cell(); | |
} | |
}; | |
} | |
public void setProvider (CellProvider provider) | |
{ | |
this.provider = provider; | |
} | |
private ListViewport viewport; | |
@Override | |
protected JViewport createViewport () | |
{ | |
viewport = new ListViewport(); | |
return viewport; | |
} | |
private class ListViewport extends JViewport | |
{ | |
private Point viewPosition; | |
@Override | |
public void setViewPosition (Point p) | |
{ | |
super.setViewPosition (p); | |
boolean changed = true; | |
if (viewPosition == null) | |
viewPosition = p; | |
else | |
{ | |
if (viewPosition.x != p.x || viewPosition.y != p.y) | |
{ | |
viewPosition.x = p.x; | |
viewPosition.y = p.y; | |
} | |
else | |
changed = false; | |
} | |
if (changed) | |
layoutComponents (); | |
} | |
} | |
private int width, height; | |
@Override | |
public void setBounds (int x, int y, int width, int height) | |
{ | |
boolean changed = this.width != width || this.height != height; | |
this.width = width; | |
this.height = height; | |
super.setBounds (x, y, width, height); | |
if (changed) | |
{ | |
layoutComponents(); | |
} | |
} | |
private CellRenderer renderer; | |
public void setRenderer (CellRenderer renderer) | |
{ | |
this.renderer = renderer; | |
} | |
private static class LayoutInfo | |
{ | |
public int y, height; | |
} | |
private ListModel model; | |
private Map<Integer, LayoutInfo> layoutInfos; | |
public void setModel (ListModel model) | |
{ | |
this.model = model; | |
layoutInfos = new HashMap<Integer, LayoutInfo> (); | |
} | |
public LayoutInfo setCellHeight (int row, int height) | |
{ | |
LayoutInfo info = layoutInfos.get (row); | |
if (info == null) | |
{ | |
info = new LayoutInfo (); | |
layoutInfos.put (row, info); | |
} | |
info.height = height; | |
return info; | |
} | |
private int knownHeight () | |
{ | |
int height = 0; | |
for (int row : layoutInfos.keySet()) | |
height += layoutInfos.get (row).height; | |
return height; | |
} | |
private Dimension tmpDimension; | |
private void layoutComponents () | |
{ | |
if (viewport.viewPosition == null) | |
return; | |
System.out.println (""); | |
if (tmpDimension == null) | |
tmpDimension = new Dimension(); | |
provider.markAllUsedCellsAvailable(); | |
int size = model.getSize (); | |
int y = 0; | |
int row = 0; | |
for ( ; row < size; ++row) | |
{ | |
LayoutInfo info = layoutInfos.get (row); | |
if (row == 0 && info == null) | |
break; | |
if (info == null) | |
{ | |
System.out.println("Layout info is null for row " + row + ", pos: " | |
+ viewport.viewPosition.y + ", fake row: " + (viewport.viewPosition.y / 16)); | |
row = Math.min (viewport.viewPosition.y / 16 - 1, size); | |
y = viewport.viewPosition.y; | |
// ds ce cas ci, il faudrait plutot setter le thumb au max et partir par la fin | |
break; | |
} | |
if (info.y + info.height > viewport.viewPosition.y) | |
{ | |
y = info.y; | |
break; | |
} | |
} | |
// row = Math.max (row - 2, 0); | |
// if (layoutInfos.containsKey (row)) | |
// y = layoutInfos.get (row).y; | |
System.out.println ("view pos: " + viewport.viewPosition + ", row: " + row + ", y: " + y); | |
int i = row; | |
for ( ; i < size; ++i) | |
{ | |
System.out.println ("1Laying out row " + i); | |
Cell cell = provider.getUnusedCell (this); | |
renderer.renderCell (this, cell, model.getElementAt (i), i); | |
provider.markCellUsed (this, cell); | |
LayoutInfo info = layoutInfos.get (i); | |
if (info == null) | |
{ | |
cell.getPreferredSize (tmpDimension); | |
info = setCellHeight (i, tmpDimension.height); | |
info.y = y; | |
} | |
cell.setBounds (0, y, width, info.height); | |
if (y + info.height > viewport.viewPosition.y + height) | |
{ | |
if (row == 0) | |
{ | |
System.out.println ("ay: " + y + ", height: " + height + ", row: " + i | |
+ ", size: " + size + ", hidden: " + (size - i) + ", component count: " + view.getComponentCount ()); | |
tmpDimension.width = width; | |
tmpDimension.height = knownHeight() + (size - layoutInfos.size() - 1) * 32; | |
System.out.println("setting view1: " + tmpDimension); | |
view.setPreferredSize (tmpDimension); | |
} | |
++i; | |
y += info.height; | |
break; | |
} | |
y += info.height; | |
} | |
if (row != 0) | |
{ | |
System.out.println ("Can layout " + row + " rows from row " + i + " to the bottom: " + y + ", viewpos: " + viewport.viewPosition.y); | |
int max = Math.min (i + row, size); | |
for ( ; i < max; ++i) | |
{ | |
System.out.println ("2Laying out row " + i); | |
Cell cell = provider.getUnusedCell (this); | |
renderer.renderCell (this, cell, model.getElementAt (i), i); | |
provider.markCellUsed (this, cell); | |
LayoutInfo info = layoutInfos.get (i); | |
if (info == null) | |
{ | |
cell.getPreferredSize (tmpDimension); | |
info = setCellHeight (i, tmpDimension.height); | |
info.y = y; | |
} | |
cell.setBounds (0, y, width, info.height); | |
if (y + info.height > viewport.viewPosition.y + height) | |
{ | |
System.out.println ("by: " + y + ", height: " + height + ", row: " + i | |
+ ", size: " + size + ", hidden: " + (size - i) + ", component count: " + view.getComponentCount () | |
+ ", max: " + max); | |
tmpDimension.width = width; | |
tmpDimension.height = y + (size - i) * 32; | |
tmpDimension.height = knownHeight() + (size - layoutInfos.size()) * 32; | |
//System.out.println("setting view2: " + tmpDimension); | |
view.setPreferredSize (tmpDimension); | |
break; | |
} | |
y += info.height; | |
} | |
} | |
validate(); | |
} | |
} | |
public static class Cell extends JPanel | |
{ | |
private Dimension preferredSize; | |
public Cell () | |
{ | |
setLayout (new GridLayout()); | |
} | |
@Override | |
public void setPreferredSize (Dimension preferredSize) | |
{ | |
this.preferredSize = preferredSize; | |
super.setPreferredSize (preferredSize); | |
} | |
public Dimension getPreferredSize (Dimension preferredSize) | |
{ | |
preferredSize.width = this.preferredSize.width; | |
preferredSize.height = this.preferredSize.height; | |
return preferredSize; | |
} | |
} | |
public static class ListViewModel extends AbstractListModel | |
{ | |
private int size; | |
public ListViewModel (int size) | |
{ | |
this.size = size; | |
} | |
@Override | |
public Object getElementAt (int index) | |
{ | |
return "row " + index; | |
} | |
@Override | |
public int getSize () | |
{ | |
return size; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment