import java.awt.*; import java.applet.*; import java.util.*; import java.io.*; import java.net.*; /** * Each node in the tree is represented by a slidescroll_item object. This object holds all properties of a single node, * for example, text, link, color, Font, and pointers to its children. */ class slidescroll_item { int arrowState = 1; //1 = right, 2 = down, 3 = up slidescroll_canvas nc; String thisItemName; Vector childVector = new Vector(); Enumeration e = childVector.elements(); StringTokenizer t; String temp; slidescroll_item item; slidescroll_item parentItem; boolean root; Color textColor; Font f; boolean active = false; boolean haveChild = false; Font font; Image itemImage; Graphics itemImageg; int itemImageHeight; int partialImageHeight; int xpos = 0; String fontType; int fontStyle; int fontSize = 0; String text; Vector textVector = new Vector(10); FontMetrics fontMetrics; String lastChildLine = ""; slidescroll_item lastChildItem; boolean open; // false = collapsed, true = open int childLines = 0; int scrolledLineIndex; int scrolledLastlined; String childLink; String childTarget = null; String target = null; String link = null; boolean last; Image bullet; Color arrowColor; Color arrowShadeColor; Color bulletColor; Color bulletShadeColor; Color arrowColorHL; Color arrowShadeColorHL; Color bulletColorHL; Color bulletShadeColorHL; Color textColorHL; boolean forcecHighlited = false; Font mouseOverFont; slidescroll_item(slidescroll_canvas nc, String thisItemName, boolean show, slidescroll_item parentItem, boolean root, String link, String target, int xpos, String fontType, int fontStyle, int fontSize, boolean last, Image bullet, Color arrowColor, Color arrowShadeColor, Color bulletColor, Color bulletShadeColor, Color highliteColor) { this.nc = nc; this.thisItemName = thisItemName; this.parentItem = parentItem; this.root = root; this.target = target; this.xpos = xpos; this.fontType = fontType; this.fontStyle = fontStyle; this.fontSize = fontSize; this.open = open; this.last = last; this.bullet = bullet; this.arrowColor = arrowColor; this.arrowShadeColor = arrowShadeColor; this.bulletColor = bulletColor; this.bulletShadeColor = bulletShadeColor; if(nc.mouseOverArrowEffect) { this.arrowShadeColorHL = arrowColor; //if the mouseover arrow affect is turned on, this.arrowColorHL = arrowShadeColor; //set the highlite colors opposite from the default colors. } else { this.arrowShadeColorHL = arrowShadeColor; //if mouseOver arrow affect is turned off, this.arrowColorHL = arrowColor; //set the highlite colors ot the default colors. } if(nc.mouseOverBulletEffect){ this.bulletShadeColorHL = bulletColor; this.bulletColorHL = bulletShadeColor; } else { this.bulletShadeColorHL = bulletShadeColor; this.bulletColorHL = bulletColor; } this.font = new Font(fontType, fontStyle, fontSize); fontMetrics = nc.getFontMetrics(this.font); mouseOverFont = new Font(fontType, nc.mouseOverStyleEffect, fontSize); int temp = testNumber(thisItemName.substring(0,1)); if(temp < 0) text = thisItemName; else text = thisItemName.substring(1,thisItemName.length()); if(link != null) if(!link.trim().equals("") && !link.startsWith("http") && !link.startsWith("ftp") && !link.startsWith("mailto")) link = nc.hostPath+link; this.link = link; this.textColor = getColor(); if(nc.highliteEffect) this.textColorHL = highliteColor; else this.textColorHL = textColor; FontMetrics fm2 = nc.getFontMetrics(mouseOverFont); int sw1 = fontMetrics.stringWidth("W"); int sw2 = fm2.stringWidth("W"); if(sw1 > sw2) wordWrap(text, fontMetrics); else wordWrap(text, fm2); setUpchild(); createItemImage(); childLines = countChildLines(); } /** * This method will scan the slidescroll indexVector for its label name. It the name is found, all names * found after are children of this node, call the addNewChild method to set up each child and return. */ private void setUpchild() { if(childVector.size() > 0) return; String vectorElement = null; String temp = ""; Enumeration e = nc.indexVector.elements(); while(e.hasMoreElements()){ vectorElement = (String)e.nextElement(); temp = vectorElement.substring(0,vectorElement.indexOf(";")); if (thisItemName.equals(temp)){ addNewChild(vectorElement); break; } } } /** * This method will accept a string that contains its children's label names. For each child name, create an child * item object, and add the child object to this object's childVector. */ private void addNewChild(String vectorElement) { t = new StringTokenizer(vectorElement, ";"); temp = t.nextToken(); while(t.hasMoreTokens()) { temp = t.nextToken(); getLink(temp); boolean last =false; if(!t.hasMoreTokens()) last = true; item = new slidescroll_item(nc, temp, true, this, false, childLink, childTarget, xpos+15, fontType, fontStyle, fontSize, last, bullet, arrowColor, arrowShadeColor,bulletColor, bulletShadeColor, textColorHL); childVector.addElement(item); } } /** * This method will return the correct color for the objects label. Change color every other decendant. */ private Color getColor() { slidescroll_item parentItem = this.parentItem; if(parentItem == null) return nc.textColor1; int i = 1; while (parentItem != null) { parentItem = parentItem.parentItem; i++; } int r = i % 2; if(r == 0) return nc.textColor2; return nc.textColor1; } /** * This method will create an image that contains the current objects child labels. It will also draw the horizontal, * and vertical dots in the image. This image will later be scrolled down when the user clicks a parent label in * the tree. */ private void createItemImage() { if(childVector.size() <= 0) return; int decent = fontMetrics.getDescent(); itemImageHeight = nc.lineSpace * countChildLines() + decent; itemImage = nc.createImage(nc.width, itemImageHeight); itemImageg = itemImage.getGraphics(); itemImageg.setColor(nc.getBackground()); itemImageg.fillRect(0,0, nc.width, itemImageHeight); Enumeration enum = childVector.elements(); int i = 0; while (enum.hasMoreElements()) { slidescroll_item navItem = (slidescroll_item)enum.nextElement(); drawHorDots(i, itemImageg, navItem); i = navItem.drawLines(itemImageg, i, false); } slidescroll_item lastChildItem = (slidescroll_item)childVector.lastElement(); int childLines = countChildLines() - lastChildItem.textVector.size(); drawVertDots(itemImageg, this, childLines); slidescroll_item parentItem = this.parentItem; parentItem = findParentItem(parentItem, this); while (parentItem != null) { childLines = countChildLines(); drawVertDots(itemImageg, parentItem, childLines); slidescroll_item item = parentItem; parentItem = parentItem.parentItem; parentItem = findParentItem(parentItem, item); } } /** * This method is used to draw the vertical dots in the child image that will seamlessly connect to the * parents dotted lines. Do not draw the parents dotted line if the parent of this child is the last child * under its parent. */ private slidescroll_item findParentItem(slidescroll_item parentItem, slidescroll_item item) { while (true) { if(parentItem == null) return null; if(item.last) { item = parentItem; parentItem = parentItem.parentItem; } else return parentItem; } } /** * This method draws the vertical dotted lines. */ private void drawVertDots(Graphics g, slidescroll_item navItem, int childLines) { itemImageg.setColor(nc.dotColor); int tempInt = (childLines+1)*nc.lineSpace; tempInt -= (fontSize/2); for(int y = 0; y < tempInt+1 ; y = y + nc.dotSpace) itemImageg.drawLine(navItem.xpos-8, y, navItem.xpos-8, y ); } /** * This method draws the hotizontal dotted lines. */ private void drawHorDots(int index, Graphics g, slidescroll_item navItem) { if(navItem.text.trim().equals("")) return; itemImageg.setColor(nc.dotColor); int ypos = nc.lineSpace *(index+1); ypos = ypos - (fontSize/2); for(int i = 0; i < 7; i = i + nc.dotSpace) g.drawLine(xpos-8+i, ypos, xpos-8+i, ypos); } /** * This method returns a count of the child lines under this parent. */ private int countChildLines() { Enumeration enum = childVector.elements(); int i = 0; while (enum.hasMoreElements()) { slidescroll_item navItem = (slidescroll_item)enum.nextElement(); i = i + navItem.textVector.size(); } return i; } /** * This method returns the number of lines currently displayed within this parent object. It counts the child * lines under this parent, and if a child is also a parent and is open revealing children, also count those * lines (and so on recursively), then add the number of lines of this object. */ private int countLinesRecursive() { Enumeration enum = childVector.elements(); int i = 0; if(open) { while (enum.hasMoreElements()) { slidescroll_item navItem = (slidescroll_item)enum.nextElement(); i = i + navItem.countLinesRecursive(); } } i = i + textVector.size(); return i; } /** * This method scrolls the child image down. As the child image scrolls, the labels below the line clicked * will also scroll down. */ void scrollDownChildren(int lineIndex) { if(childVector.size() <= 0) return; arrowState = 2; nc.repaint(); drawLines(nc.offscreeng, lineIndex, false); int decent = fontMetrics.getDescent(); int lastlined = nc.lineSpace * (lineIndex+1); scrolledLineIndex = lineIndex; scrolledLastlined = lastlined; int width = nc.width; int height = ((nc.navItemVector.size()+1)*nc.lineSpace) + itemImageHeight; Image offscreen = nc.createImage(width, height); Graphics offscreeng = offscreen.getGraphics(); offscreeng.drawImage(nc.offscreen, 0,0, null); Vector navItemVector = nc.navItemVector; lastlined += (textVector.size()-1)*nc.lineSpace; lineIndex += textVector.size()-1; offscreeng.clipRect(0, lastlined+decent, width, height-lastlined+decent); Image image = nc.createImage(width, height-lastlined-itemImageHeight); Graphics imageg = image.getGraphics(); imageg.drawImage(offscreen, 0, -lastlined, null); for(int i = 1; i < itemImageHeight+1-decent; i++){ offscreeng.drawImage(image, 0, lastlined+i, null); offscreeng.drawImage(itemImage, 0, (lastlined-itemImageHeight)+i+decent, null); nc.getGraphics().drawImage(offscreen, 0, nc.y, null); pause(nc.pauseValue); } imageg.dispose(); Enumeration enum = childVector.elements(); int i = lineIndex; while (enum.hasMoreElements()) { slidescroll_item item = (slidescroll_item)enum.nextElement(); i = item.insertVector(nc.navItemVector, i); } nc.offscreen = offscreen; nc.offscreeng = offscreen.getGraphics(); offscreen = null; nc.setUpOffscreen(); nc.repaint(); open = true; } /** * This method will scroll up the tree, collapsing the children of a parent. Before a parent is collapsed, * any child of the parent will also collapse. */ private void scrollUpChildren() { if(childVector.size() <= 0) return; if(!open) return; Enumeration enum = childVector.elements(); while (enum.hasMoreElements()) { slidescroll_item navItem = (slidescroll_item)enum.nextElement(); navItem.scrollUpChildren(); } arrowState = 3; drawLines(nc.offscreeng, scrolledLineIndex, false); int width = nc.width; int height = (nc.navItemVector.size()+1)*nc.lineSpace; if(height < nc.getBounds().height) height = nc.getBounds().height; Vector navItemVector = nc.navItemVector; Image scrollUp = nc.createImage(nc.width, height); Graphics scrollUpg = scrollUp.getGraphics(); scrollUpg.drawImage(nc.offscreen, 0, 0, null); scrolledLastlined += (textVector.size()-1)*nc.lineSpace; scrolledLineIndex += textVector.size()-1; int decent = fontMetrics.getDescent(); nc.offscreeng.clipRect(0, scrolledLastlined+decent, width, height-decent); for(int i = 0; i > -(itemImageHeight-decent); i--){ nc.offscreeng.drawImage(scrollUp, 0, i-1, null); nc.getGraphics().drawImage(nc.offscreen, 0, nc.y, null); pause(nc.pauseValue); } scrollUpg.dispose(); arrowState = 1; for(int i = 0; i < childLines; i++) nc.navItemVector.removeElementAt(scrolledLineIndex+1); nc.setUpOffscreen(); nc.repaint(); open = false; } /** * This method will be used to check to see if the current item object should scroll up. Only one child of a * parent can be opened at a time, but a child under a parent may be opened, as well as children under the child. * If a child, or children of the current item's child, is clicked on, do not close the current item. */ int checkToScrollUp(int i, int lineIndex) { int lastlined = nc.lineSpace * (i+1); int firstChild = i + textVector.size(); int lastChild = i + countLinesRecursive() - textVector.size(); if(textVector.size() > 1) lastChild += textVector.size()-1; if(open) { if(childLines > 0 && (lineIndex >= firstChild && lineIndex <= lastChild)) return -1; int linesUp = countLinesRecursive()-textVector.size(); //We have now determined to scroll up this item objects children. Since the tree is contracting, //the scrollbar may not be needed now. If the scroll bar is scrolled down, remove the scroll //bar now only if this item does not have a parent node currently open (expanded). if(!parentOpen(parentItem)) { while(nc.y < 0) { nc.drawScrollBar(); if(nc.sby > 0) nc.sby--; nc.y++; nc.paint(nc.getGraphics()); pause(nc.pauseValue); } } scrollUpChildren(); return linesUp; } return -1; } /** * This method will return a true if a parent node is open. */ boolean parentOpen(slidescroll_item parentItem) { while (true) { if(parentItem == null) return false; if(parentItem.open) return true; parentItem = parentItem.parentItem; } } private void pause (int time) { try { Thread.sleep(time); } catch (InterruptedException e) { } } /** * Search the slidescroll linkVector for the passed name and set global variables childLink, and childTarget. */ private void getLink(String ItemName) { String vectorElement = null; String temp = ""; StringTokenizer t; Enumeration e = nc.linkVector.elements(); childLink = null; int tempInt; while(e.hasMoreElements()){ vectorElement = (String)e.nextElement(); t = new StringTokenizer(vectorElement, ";"); temp = t.nextToken(); if(ItemName.equals(temp)) { childLink = t.nextToken(); childTarget = null; while(t.hasMoreTokens()) childTarget = t.nextToken(); return; } } return; } /** * Check if the passed string is numeric. */ private int testNumber(String num) { int temp; try {temp = Integer.valueOf(num).intValue();} catch (NumberFormatException e) { return -2; } return temp; } /** * This method will wordwrap the passed line. Do not allow lines to display if their string width is greater than the * applet's width plus the y position of the label. */ private void wordWrap(String inline, FontMetrics fontMetrics) { String line; String nextWord; StringTokenizer st; line = ""; st = new StringTokenizer(inline, " "); while (st.hasMoreTokens()) { nextWord = st.nextToken(); if(line.equals("")) line = nextWord; else if (fontMetrics.stringWidth(line + " " + nextWord) < nc.width-xpos ) line += " " + nextWord; else { textVector.addElement(line); line = nextWord; } } textVector.addElement(line); } /** * This method will insert a reference to this current object into slidescroll's navItemVector at the passed index. * Insert multiple references to this object depending on the length of the textVector. */ int insertVector(Vector navItemVector, int index) { for (int i = 0; i < textVector.size(); i++) { navItemVector.insertElementAt(this, ++index); } return index; } /** * This method will insert a reference to this current object into slidescroll's navItemVector at the end of the Vector. * Insert multiple references to this object depending on the length of the textVector. */ void addVector(Vector navItemVector) { for (int i = 0; i < textVector.size(); i++) navItemVector.addElement(this); } /** * This method will draw this objects label in the tree. Loop through textVector to and draw the lines. This method * will also draw the lines icons, and vertical dots found within the line. */ int drawLines(Graphics g, int index, boolean highlite) { Color textColor = this.textColor; Color arrowColor = this.arrowColor; Color arrowShadeColor = this.arrowShadeColor; Color bulletColor = this.bulletColor; Color bulletShadeColor = this.bulletShadeColor; Font font = this.font; if(highlite || forcecHighlited) { textColor = this.textColorHL; arrowColor = this.arrowColorHL; arrowShadeColor = this.arrowShadeColorHL; bulletColor = this.bulletColorHL; bulletShadeColor = this.bulletShadeColorHL; font = mouseOverFont; } int y; if(text.trim().equals("")) //if this object has no text, return next index return index+1; y = nc.lineSpace*(index+1); g.setColor(nc.backgroundColor); g.fillRect(xpos-15, y-nc.lineSpace, 15, nc.lineSpace); //clear icons if(childVector.size() <= 0){ //draw diamond g.setColor(bulletShadeColor); Polygon p = new Polygon(); p.addPoint(xpos-8,y-8); p.addPoint(xpos-11,y-5); p.addPoint(xpos-8,y-2); p.addPoint(xpos-5,y-5); g.fillPolygon(p); g.setColor(bulletColor); p = new Polygon(); p.addPoint(xpos-8,y-7); p.addPoint(xpos-10,y-5); p.addPoint(xpos-8,y-3); p.addPoint(xpos-6,y-5); g.fillPolygon(p); //g.drawImage(bullet, xpos-10, y-8, null); } if(arrowState == 1 && childVector.size() > 0) { //point right g.setColor(arrowShadeColor); Polygon p = new Polygon(); p.addPoint(xpos-10,y-10); p.addPoint(xpos-10,y); p.addPoint(xpos-5,y-5); g.fillPolygon(p); g.setColor(arrowColor); p = new Polygon(); p.addPoint(xpos-10,y-8); p.addPoint(xpos-10,y-2); p.addPoint(xpos-7,y-5); g.fillPolygon(p); } if(arrowState == 2 && childVector.size() > 0) { //point down g.setColor(arrowShadeColor); Polygon p = new Polygon(); p.addPoint(xpos-12,y-7); p.addPoint(xpos-2,y-7); p.addPoint(xpos-7,y-2); g.fillPolygon(p); g.setColor(arrowColor); p = new Polygon(); p.addPoint(xpos-10,y-7); p.addPoint(xpos-7,y-4); p.addPoint(xpos-4,y-7); g.fillPolygon(p); } if(arrowState == 3 && childVector.size() > 0) { //point up g.setColor(arrowShadeColor); Polygon p = new Polygon(); p.addPoint(xpos-7,y-7); p.addPoint(xpos-13,y-1); p.addPoint(xpos-1,y-1); g.fillPolygon(p); g.setColor(arrowColor); p = new Polygon(); p.addPoint(xpos-7,y-5); p.addPoint(xpos-11,y-1); p.addPoint(xpos-3,y-1); g.fillPolygon(p); } //draw the text of this object to the image for (int i = 0; i < textVector.size(); i++){ y = nc.lineSpace*++index; g.setColor(nc.backgroundColor); int decent = fontMetrics.getMaxDescent(); int ascent = fontMetrics.getMaxAscent(); if(i == 0) g.fillRect(xpos-2, y-ascent, nc.width, ascent+decent); //clear line else g.fillRect(xpos-2, y-ascent+decent, nc.width, ascent); g.setColor(textColor); g.setFont(font); String text = (String)textVector.elementAt(i); g.drawString(text, xpos, y); if(i > 0) { //draw vertical dotted line if this is not the 1st line g.setColor(nc.backgroundColor); g.fillRect(xpos-10, y-nc.lineSpace, 5, nc.lineSpace+decent); //clear old dotted line if(arrowState == 2 || arrowState == 3 ) { int mypos = y - nc.lineSpace; g.setColor(nc.dotColor); for(int i2 = 0; i2 < nc.lineSpace+decent; i2 = i2 + nc.dotSpace) g.drawLine(xpos-8, mypos+i2, xpos-8, mypos+i2 ); } } } return index; } }// end of Item class