Skip to content

Instantly share code, notes, and snippets.

@rherrmann
Last active October 22, 2016 20:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rherrmann/fc248fb01a00fb4fa73187cbbdaf441f to your computer and use it in GitHub Desktop.
Save rherrmann/fc248fb01a00fb4fa73187cbbdaf441f to your computer and use it in GitHub Desktop.
/***************************************************************************************************
* Copyright (c) 2016 Rüdiger Herrmann
* All rights reserved. This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Rüdiger Herrmann - initial API and implementation
* The SWT Team - compute the number of visible rows in a tree (see http://tinyurl.com/gmhhsmy)
**************************************************************************************************/
package com.codeaffine.swt;
import static java.lang.String.valueOf;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
public class TreeRulerSnippet {
public static void main( String[] args ) {
Display display = new Display();
Shell shell = new Shell( display );
TreeRuler treeRuler = new TreeRuler( shell, SWT.NONE );
Tree tree = new Tree( shell, SWT.BORDER );
for( int i = 0; i < 4; i++ ) {
TreeItem iItem = new TreeItem( tree, 0 );
iItem.setText( "TreeItem (0) -" + i );
for( int j = 0; j < 4; j++ ) {
TreeItem jItem = new TreeItem( iItem, 0 );
jItem.setText( "TreeItem (1) -" + j );
for( int k = 0; k < 4; k++ ) {
TreeItem kItem = new TreeItem( jItem, 0 );
kItem.setText( "TreeItem (2) -" + k );
for( int l = 0; l < 4; l++ ) {
TreeItem lItem = new TreeItem( kItem, 0 );
lItem.setText( "TreeItem (3) -" + l );
}
}
}
}
treeRuler.setTree( tree );
GridLayout layout = new GridLayout( 2, false );
layout.horizontalSpacing = 0;
shell.setLayout( layout );
treeRuler.setLayoutData( new GridData( SWT.BEGINNING, SWT.FILL, false, true ) );
tree.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true ) );
shell.setSize( 200, 200 );
shell.open();
while( !shell.isDisposed() ) {
if( !display.readAndDispatch() )
display.sleep();
}
display.dispose();
}
public static class TreeRuler extends Canvas {
private Tree tree;
private Listener treeListener;
public TreeRuler( Composite parent, int style ) {
super( parent, style );
this.treeListener = this::handleTreeChange;
this.addListener( SWT.Paint, this::handlePaint );
}
public Tree getTree() {
checkWidget();
return tree;
}
public void setTree( Tree tree ) {
checkWidget();
deregisterTreeListener();
this.tree = tree;
registerTreeListener();
}
@Override
public Point computeSize( int widthHint, int heightHint, boolean changed ) {
Point size = super.computeSize( widthHint, heightHint, changed );
if( widthHint == SWT.DEFAULT ) {
size.x = getTextWidth( "9999" );
}
if( heightHint == SWT.DEFAULT && tree != null ) {
size.y = tree.getBounds().height;
}
return size;
}
private void registerTreeListener() {
if( this.tree != null ) {
this.tree.addListener( SWT.Resize, treeListener );
this.tree.addListener( SWT.Selection, treeListener );
this.tree.addListener( SWT.DefaultSelection, treeListener );
this.tree.addListener( SWT.Expand, treeListener );
this.tree.addListener( SWT.Collapse, treeListener );
if( this.tree.getHorizontalBar() != null ) {
this.tree.getHorizontalBar().addListener( SWT.Selection, treeListener );
}
if( this.tree.getVerticalBar() != null ) {
this.tree.getVerticalBar().addListener( SWT.Selection, treeListener );
}
}
}
private void deregisterTreeListener() {
if( this.tree != null ) {
this.tree.removeListener( SWT.Resize, treeListener );
this.tree.removeListener( SWT.Selection, treeListener );
this.tree.removeListener( SWT.DefaultSelection, treeListener );
this.tree.removeListener( SWT.Expand, treeListener );
this.tree.removeListener( SWT.Collapse, treeListener );
if( this.tree.getHorizontalBar() != null ) {
this.tree.getHorizontalBar().removeListener( SWT.Selection, treeListener );
}
if( this.tree.getVerticalBar() != null ) {
this.tree.getVerticalBar().removeListener( SWT.Selection, treeListener );
}
}
}
private int getTextWidth( String string ) {
GC gc = new GC( this );
try {
return gc.textExtent( string ).x;
} finally {
gc.dispose();
}
}
private void handlePaint( Event event ) {
if( tree != null && !tree.isDisposed() && tree.getTopItem() != null ) {
Rectangle remainingRect = getClientArea();
remainingRect.height -= getHorizontalBarHeight();
int itemHeight = tree.getItemHeight();
int topIndex = getTopIndex();
int currentIndex = topIndex;
int itemCount = getVisibleItemCount();
while( remainingRect.y < remainingRect.height && currentIndex < topIndex + itemCount ) {
String rowNumber = valueOf( currentIndex + 1 );
int yOffset = ( itemHeight - event.gc.getFontMetrics().getHeight() ) / 2;
event.gc.drawString( rowNumber, remainingRect.x, remainingRect.y + yOffset, true );
remainingRect.y += itemHeight;
currentIndex++;
}
}
}
private int getHorizontalBarHeight() {
int height = 0;
if( tree.getHorizontalBar() != null && tree.getHorizontalBar().getVisible() ) {
height = tree.getHorizontalBar().getSize().y;
}
return height;
}
private int getTopIndex() {
int topIndex = -1;
TreeItem topItem = tree.getTopItem();
if( topItem != null && tree.getItemCount() > 0 ) {
topIndex = 0;
TreeItem currentItem = tree.getItem( 0 );
while( currentItem != null && currentItem != topItem ) {
currentItem = nextItem( currentItem );
topIndex++;
}
}
return topIndex;
}
private int getVisibleItemCount() {
int visibleItemCount = 0;
Rectangle rect = tree.getClientArea();
TreeItem currentItem = tree.getTopItem();
while( currentItem != null ) {
visibleItemCount++;
Rectangle itemRect = currentItem.getBounds();
if( itemRect.y + itemRect.height > rect.y + rect.height ) {
currentItem = null;
} else {
currentItem = nextItem( currentItem );
}
}
return visibleItemCount;
}
private TreeItem nextItem( TreeItem item ) {
if( item == null ) {
return null;
}
if( item.getExpanded() && item.getItemCount() > 0 ) {
return item.getItem( 0 );
}
TreeItem childItem = item;
TreeItem parentItem = childItem.getParentItem();
int index = parentItem == null ? tree.indexOf( childItem ) : parentItem.indexOf( childItem );
int count = parentItem == null ? tree.getItemCount() : parentItem.getItemCount();
while( true ) {
if( index + 1 < count ) {
return parentItem == null ? tree.getItem( index + 1 ) : parentItem.getItem( index + 1 );
}
if( parentItem == null ) {
return null;
}
childItem = parentItem;
parentItem = childItem.getParentItem();
index = parentItem == null ? tree.indexOf( childItem ) : parentItem.indexOf( childItem );
count = parentItem == null ? tree.getItemCount() : parentItem.getItemCount();
}
}
private void handleTreeChange( Event event ) {
redraw();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment