Last active
October 22, 2016 20:47
-
-
Save rherrmann/fc248fb01a00fb4fa73187cbbdaf441f to your computer and use it in GitHub Desktop.
A row number ruler for SWT trees (see also: http://stackoverflow.com/questions/40144071/how-to-create-a-jface-treeviewer-with-row-numbering/40151820#40151820)
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
/*************************************************************************************************** | |
* 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