📄 hiercanvas.java
字号:
/* Attempt at hierarchy representation with expand/contract display
* 12/22 - split NodeMem out to NodeMem.java
* 12/23, 24 - adding goodies
* 12/25 - separate HierCanvas out as HierCanvas.java
* 01/05/96 - debug why Netscape doesn't show first time
* 01/18 - suggestion by Ian Leicht <ivl@cs.hmc.edu> speeds up hideNChild()
*/
/* Public Notice
* Hier.java, HierCanvas.java and NodeMem.java are copyright (c) 1996
* by William B. Brogden - wbrogden@bga.com
* 130 Woodland Trail, Leander, TX 78641
* These classes can be used for private or commercial applications
* without restriction, but I would appreciate it if you let me know
* what you are using them for & if you make improvements.
*/
import java.applet.Applet;
import java.awt.*;
import java.io.StreamTokenizer;
import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Vector ;
// a class to contain java.util.Vector of elements and display it
// based on Canvas as simplest class
class HierCanvas extends Canvas {
int state ; // 0 = no vector resident
Vector nodelist ; // which we get from applet
int nodect ;
int topnode ; // displayed on first line
int selnode ; // always a visible selection
int level ;
int depth ; // number of layers in hierarchy
// display related
boolean gotFocus ;
int insets[] ; // x position for starting display - may chg w size
int hCheight ; // canvas height as initialized
Dimension sizeC ; // canvas size.height, size.width - as seen by paint
// which could be affected by resize
int nLines ; // desired number of lines in the canvas
int c_height, c_ascent ; // reset every paint
int fontsize ; // point size, smaller than height
FontMetrics fmtr ;
Font curFont ;
// TextArea xtraText ; // display in right panel which we update
Hier parent ; // so we can inform of text change
Scrollbar scB ; // on left edge which we update
public Dimension minimumSize() {
return new Dimension( 100,100 ) ; // room for improvement
}
void updateTx() {
NodeMem thisN = (NodeMem) nodelist.elementAt( selnode );
if( parent != null ) {
parent.TextChange( thisN.desc );
}
}
// selnode may have changed, recalculate topnode to ensure display
void calcTop() {
int i, nlines, posct ;
NodeMem thisN ;
if( state == 0 ) return ;
int poss[] = new int[ nodect ] ;
nlines = sizeC.height / c_height ; // need to handle small nlines?
if( nlines < 2 ) nlines = 2 ;
if( selnode <= topnode ) { topnode = selnode ; return ; }
if( selnode < topnode + nlines ) return ;
// make list of possibles (exposed lines) until we hit selnode
posct = 0 ;
for( i = 0 ; i < nodect ; i++ ) {
thisN = (NodeMem) nodelist.elementAt( i );
if( thisN.exposed ) poss[ posct++ ] = i ;
if( i >= selnode ) break ;
}
i = 1 + (posct - nlines ) ;
if( i < 0 ) i = 0 ;
if( topnode < poss[i] ) topnode = poss[ i ] ;
}
// action items
public boolean mouseDown( Event evt, int x, int y ) {
NodeMem thisN ;
int i ;
// System.out.println("Hier m " + evt.toString() ) ;
for( i = topnode ; i < nodect ; i++ ) {
thisN = (NodeMem) nodelist.elementAt( i );
if( thisN.visible ) {
if( thisN.sRect.inside( x, y ) ) {
if( selnode == i ) { toggle();
}
else selnode = i ;
repaint();
return true ;
}
}
}
return false ;
}
public void absSel( int n ) { // from scrollbar move
int target, del, prev ;
target = n ;
if( n >= nodect ) target = nodect - 1 ;
if( n < 0 ) target = 0 ; // don't know if thats possible,chk anyway
del = target - selnode ; // neg means up, pos down
if( del == 0 ) return ;
if( del < 0 ) {
while( target < selnode ) upSel( 1 ) ;
}
else { // target may not be exposed
prev = selnode ;
while( target > selnode ) {
dnSel( 1 ) ;
if( prev == selnode ) break ; // unable to go further down
prev = selnode ; // try for another
}
}
}
public void upSel( int n ) {
int ct ;
NodeMem thisN ;
ct = n ;
while( ct > 0 )
{ if( --selnode <= 0 ) { selnode = 0 ; break ;} // at top already
thisN = (NodeMem) nodelist.elementAt( selnode );
if( selnode < topnode ) topnode = selnode ;
if( thisN.exposed ) ct-- ; // found another exposed
}
calcTop();
}
public void dnSel( int n ) {
int i, ct ;
NodeMem thisN ;
ct = n ;
while( ct > 0 )
{ if( selnode + 1 == nodect ) break ; // at bottom
for( i = selnode + 1 ; i < nodect ; i++ ) {
thisN = (NodeMem) nodelist.elementAt( i );
if( thisN.exposed ) {
ct-- ; selnode = i ; break ;
}
}
// System.out.println("dnSel " + selnode + " i " + i + " ct " + ct ) ;
// i == nodect if we got to end w no more exposed
if( i >= nodect ) break ;
}
calcTop();
}
// toggle state of selnode, if children exposed, contract, etc
public void toggle() {
NodeMem thisN = (NodeMem) nodelist.elementAt( selnode );
int n ;
n = thisN.child ;
if( n == 0 ) return ;
thisN = (NodeMem) nodelist.elementAt( n ) ;
if( thisN.exposed ) contract() ; // already expanded
else expand();
}
public void expand() {
NodeMem thisN = (NodeMem) nodelist.elementAt( selnode );
int n ;
n = thisN.child ;
// System.out.print("Expand " + selnode + " Child = " + n ) ;
if( n <= 0 ) return ; // no child, cant expand
thisN = (NodeMem) nodelist.elementAt( n ) ;
if( thisN.exposed ) return ; // already expanded
thisN.exposed = true ;
selnode = n ;
while( thisN.nxsib > 0 ) { // do all the sibs
thisN = (NodeMem) nodelist.elementAt( thisN.nxsib ) ;
thisN.exposed = true ;
}
calcTop();
}
// hide any children of this n - then itself & sibs - recursive - I hope
void hideNChild( int n ) {
int chn ;
NodeMem thisN = (NodeMem) nodelist.elementAt( n );
chn = thisN.child ;
if( chn > 0 ) hideNChild( chn ) ;
thisN.exposed = false ;
// this suggestion by Ian Leicht eliminated much excess looping
if( thisN.nxsib > 0 ) {
hideNChild( thisN.nxsib ) ;
}
/* this is what I had before - while un-needed because of recursion
while( thisN.nxsib > 0 ) {
hideNChild( thisN.nxsib ) ;
thisN = (NodeMem) nodelist.elementAt( thisN.nxsib ) ;
} */
}
// contract is tricky because we may be at a node with exposed children
// or on a node without any, but with a parent
public void contract() {
int n ;
NodeMem thisN = (NodeMem) nodelist.elementAt( selnode );
n = thisN.child ;
if( n <= 0 ) return ;
if( ((NodeMem) nodelist.elementAt( n )).exposed ) {
hideNChild( n ) ;
}
/* else {
System.out.println("No exposed children");
} */
calcTop();
}
// constructor
public HierCanvas( int hi ) {
state = 0 ;
nodect = 0 ;
topnode = 0 ;
selnode = 0 ;
level = 1 ;
hCheight = hi ;
gotFocus = false ;
} // end constructor
public void SetVector( Vector nlist, int nc, int dp, int nln ) {
int prevS, tmpN ;
nodelist = nlist ;
nodect = nc ;
topnode = 0 ;
selnode = 0 ;
state = 1 ;
level = 1 ;
nLines = nln ;
depth = dp ;
gotFocus = false ;
insets = new int[ depth ] ;
for( int i = 1 ; i <= depth ; i++ ) {
insets[ i - 1 ] = i * 15 ;
}
curFont = getFont();
fmtr = getFontMetrics( getFont() ) ;
fontsize = curFont.getSize() ;
prevS = fontsize ;
tmpN = hCheight / fmtr.getHeight() ;
if( tmpN != nLines ) {
if( tmpN < nLines )while( decrFont());
else while( incrFont());
}
} // end constructor
public void AddParent( Hier p ) { parent = p ; }
public void setFocus( boolean flg ) { gotFocus = flg ; }
public void AddScrollbar( Scrollbar s ) { scB = s ; }
// decrease font size to meet nLines target, min size is 8 point
// return true if latest decr fails to meet target
boolean decrFont() {
int tmpN, prevS ;
if( fontsize <= 8 ) return false ;
setFont( new Font( curFont.getName(), Font.PLAIN, fontsize - 1 ));
curFont = getFont();
fontsize = curFont.getSize() ;
fmtr = getFontMetrics( getFont() ) ;
// System.out.println("Resized Font = " + fmtr.toString() ) ;
tmpN = hCheight/ fmtr.getHeight() ;
return ( tmpN < nLines ) ;
}
// similar to increase font size - max 40
boolean incrFont() {
int tmpN ;
if( fontsize >= 40 ) return false ;
setFont( new Font( curFont.getName(), Font.PLAIN, fontsize + 1 ));
curFont = getFont();
fontsize = curFont.getSize() ;
fmtr = getFontMetrics( getFont() ) ;
// System.out.println("Resized Font = " + fmtr.toString() ) ;
tmpN = hCheight/ fmtr.getHeight() ;
return ( tmpN > nLines ) ;
}
public void paint(Graphics g) {
NodeMem thisN ;
int i, x, y, txwid, pluswid ;
x = 1 ;
if( state == 0 ) {
g.drawString("Working", 10,10 ); return ;
}
if( state == 1 )
{ g.drawString("Read " + nodect, 10, 10 ) ; state = 2 ; return ;
} // NOTE: this means we have to repaint twice I think
sizeC = size() ; // current size of canvas
fmtr = getFontMetrics( getFont() ) ;
c_height = fmtr.getHeight() ;
c_ascent = fmtr.getAscent() ;
pluswid = fmtr.stringWidth( " + " ) ; // indicator of more
// calculate visibility & layout
calculateVis() ;
// update text area in right panel from selnode
updateTx() ;
if( gotFocus ) g.setColor( Color.red ) ; // so I can see what it does
else g.setColor( Color.black ) ;
sizeC.width -= 4 ; sizeC.height -= 4 ;
g.draw3DRect( 1,1, sizeC.width ,sizeC.height, true ) ;
scB.setValue( selnode ) ;
// prepare to show
i = 0 ; y = c_height + 1 ;
while(( y < sizeC.height) && ( i < nodect )) {
thisN = (NodeMem) nodelist.elementAt( i );
if( thisN == null ) {
System.out.println("null thisN from list") ; break ;
}
// thisN.dump();
if( thisN.visible ) {
x = insets[ thisN.level - 1 ] ; // level 1 - depth
if( i == selnode )
{ g.setColor( Color.darkGray ) ;
txwid = fmtr.stringWidth( thisN.tags[ thisN.level - 1] ) ;
g.fillRect( x, y - c_ascent , txwid + pluswid, c_height );
g.setColor( Color.white ) ;
}
else { g.setColor( Color.black ) ; }
if( thisN.child > 0 ) {
g.drawString( thisN.tags[ thisN.level - 1 ] + " +", x, y ) ;
}
else {
g.drawString( thisN.tags[ thisN.level - 1 ], x, y ) ;
}
thisN.sRect.reshape( x,y - c_ascent,sizeC.width ,c_height );
y += c_height ;
} // from visible test
i++ ;
}
}
// enter with n = possible parent node, 0 based, check for children
// NOTE: any child would be following immediately and have next level
// as well as matching tags - print errors
// IF there is a child, fill in child slot in element n,
// fill in parent slot in element n + 1, return true
boolean childCheck( int n ) {
int i ;
if( n >= nodect ) return false ;
NodeMem thisN = (NodeMem) nodelist.elementAt( n );
thisN.child = 0 ; // default
if( (n+ 1) >= nodect ) return false ; // at end of list
NodeMem nextN = (NodeMem) nodelist.elementAt( n + 1 );
nextN.parent = 0 ;
if( nextN.level <= thisN.level ) return false ; // child not possible
// probably a child but check tags in case of error
for( i = 0 ; i < thisN.level ; i++ ) {
if( thisN.tags[i].compareTo( nextN.tags[i] ) != 0 ) {
System.out.println("Err in tag order " + n + thisN.tags[i] + nextN.tags[i] );
return false ;
}
}
thisN.child = n + 1 ;
nextN.parent = n ;
return true ;
}
// link siblings with n - known to be a first child
// return count of sibs found
int sibCheck( int n ) {
int i, j,ps, ct, mtch ;
NodeMem nextN ;
if( n + 1 >= nodect ) return 0 ; // no sibs possible
NodeMem thisN = (NodeMem) nodelist.elementAt( n );
if( thisN.prevsib > 0 ) {
// System.out.println("sibCheck of node " + n +" already set" ) ;
return 1 ;
}
ps = n ; // use for prevsib pointer
i = n + 1 ; ct = 0 ;
// a sib could occur anywhere in remainder of the list
while( i < nodect ) {
nextN = (NodeMem) nodelist.elementAt( i );
if( thisN.level == nextN.level ) { // level must match
if( thisN.level == 1 ) mtch = 0 ; // all level 1s are sibs
else {
mtch = 1 ;
for( j = 1; j < thisN.level ; j++ ) { // tags must match
mtch = thisN.tags[j - 1].compareTo( nextN.tags[j - 1] ) ;
if( mtch != 0 ) break ;
}
}
if( mtch == 0 ) { // i is sib to n and ps
thisN.nxsib = i ;
nextN.parent = thisN.parent ;
nextN.prevsib = ps ;
ps = i ;
thisN = nextN ;
// System.out.print("found sib "+ i ) ; nextN.dump();
ct++ ;
}
else break ; // tested tags[], no match
}
i++ ;
}
return ct ;
}
public void calculateHier()
// calculate hierarchy structure
{ int i ;
NodeMem thisN ;
i = 0 ;
while( i < nodect )
{ thisN = (NodeMem) nodelist.elementAt( i );
if( childCheck( i ) ) { // childCheck sets Child in n, Parent in n + 1
// System.out.print("has child ") ; thisN.dump();
}
sibCheck( i ) ; // set sib pointers
i++ ;
}
}
// calculate visibility based on current top, etc.
void calculateVis()
{ int i, j, y ;
NodeMem thisN ;
i = 0 ;
while(i < topnode)((NodeMem)nodelist.elementAt(i++ )).visible = false ;
y = c_height + 1 ; // first line painted here
for( i = topnode ; i < nodect ; i++ ) {
thisN = (NodeMem) nodelist.elementAt( i );
if( thisN == null ) break ;
if( thisN.exposed ) {
// System.out.print("Exposed " + i ); thisN.dump() ;
thisN.visible = true ;
y += c_height ;
}
else thisN.visible = false ;
if( y >= sizeC.height ) break ;
}
}
}
//******************** end HierCanvas
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -