// Job: Jay's Own Browser, a web browser written in Java by Jay Skeer // Copyright (C) 1996 Jay Skeer, Jay Prime Positive // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // import java.awt.*; import HtmlDocumentArea; import HtmlDocumentAreaVector; import HtmlDocumentAreaStream; /** A panel (containing a display area and a vertical scroll bar) for showing (Html)Documents. Assumes the ducument is all broken up into displayable HtmlDocumentArea's. */ public class HtmlDocumentAreaPanel extends Panel { /* * * the data being displayed */ HtmlDocumentAreaVector area_cache= null; HtmlDocumentAreaStream area_stream= null; /** the position of the last area read from the stream */ int last_read_area_x= 999; int last_read_area_y= 999; /* * * The portion begin displayed */ /** top line displayed */ public int top_line= 0; /** botom line displayed */ public int bot_line= -1; /** number of lines displayed */ public int disp_lines= 0; /** number of lines in doc */ public int doc_lines= 0; /* * * The widgets doing the displaying */ /** the scroll bar which reflects the position (and amount) of doc */ Scrollbar scrollbar= null; /** the canvas the document is drawn on */ Canvas display= null; /** the Normal body font the text is drawn in */ Font appBodyFont= null; /** the Bold font the text is drawn in */ Font appBoldFont= null; /** the Typewriter font the text is drawn in */ Font appTypeFont= null; /** the top level heading font */ Font appH1Font= null; /** the second level heading font */ Font appH2Font= null; /** the third level heading font */ Font appH3Font= null; /** the fourth level heading font */ Font appH4Font= null; /** the fifth level heading font */ Font appH5Font= null; /** graphics device on which we are did the displaying most recently */ Graphics saved_graphics= null; /** the document region stream we convert to areas -- must keep this around cause we need to build the area stream based on the graphics device. */ HtmlDocumentRegionStream region_stream= null; public HtmlDocumentAreaPanel() { /* area{stream,cache} stuff */ area_cache= new HtmlDocumentAreaVector(); Jdb.trace("area_cache set to new (1)"); area_stream= null; top_line= 0; bot_line= 0; doc_lines= 0; disp_lines= 0; last_read_area_x= -1; last_read_area_y= -1; /* display stuff */ display= new Canvas(); scrollbar= new Scrollbar(Scrollbar.VERTICAL); this.setLayout(new BorderLayout()); this.add("East", scrollbar); this.add("Center", display); appH1Font= new Font("TimesRoman", Font.BOLD, 28); appH2Font= new Font("TimesRoman", Font.BOLD, 25); appH3Font= new Font("TimesRoman", Font.BOLD, 22); appH4Font= new Font("TimesRoman", Font.BOLD, 19); appH5Font= new Font("TimesRoman", Font.BOLD, 17); appBodyFont= new Font("TimesRoman", Font.PLAIN, 15); appBoldFont= new Font("TimesRoman", Font.BOLD, 15); appTypeFont= new Font("Courier", Font.PLAIN, 15); display.setFont(appBodyFont); HtmlDocumentArea.initFonts (appH1Font, appH2Font, appH3Font, appH4Font, appH5Font, appBodyFont, appBoldFont, appTypeFont); display.setForeground(Color.black); display.setBackground(Color.white); // this.layout(); // scrollbar.show(); // display.show(); // this.show(); } // public void setAreas(HtmlDocumentAreaVector a) { // this.area_cache= a; // if (null != area_cache) { // doc_lines= area_cache.size(); // if (doc_lines < top_line) { // top_line= 0; // bot_line= -1; // } // } else { // setTopLine(0); // doc_lines= 0; // } // } public void setAreas(HtmlDocumentRegionStream rs) { this.area_cache= new HtmlDocumentAreaVector(); Jdb.enter("HDAP.setAreas()"); Jdb.trace("area_cache set to new (2)"); this.region_stream= rs; // cause we need the graphics device to // build the area_stream; this.area_stream= null; setTopLine(0); doc_lines= 0; last_read_area_x= -1; last_read_area_y= -1; Jdb.exit("HDAP.setAreas()"); } public void blank_and_repaint(int msdelay) { Jdb.enter("HDAP.blank_and_repaint(msdelay "+msdelay+")"); Graphics myg= display.getGraphics(); Rectangle cr= bounds(); Jdb.trace("bounds == " + cr); Jdb.trace("cliprect == " + myg.getClipRect()); myg.clearRect(cr.x, cr.y, cr.width, cr.height); repaint(msdelay); Jdb.exit("HDAP.blank_and_repaint(msdelay "+msdelay+")"); } public void blank_and_repaint() { Jdb.enter("HDAP.blank_and_repaint()"); blank_and_repaint(0); Jdb.exit("HDAP.blank_and_repaint()"); } private boolean can_read_from_stream() { //Jdb.enter("HDAP.can_read_from_stream()"); boolean rv= false; boolean nn= (null != area_stream); if (nn) { boolean ne= (!area_stream.eof()); rv= ne; } else { rv= false; } //Jdb.exit("HDAP.can_read_from_stream() => " + rv); return rv; } private HtmlDocumentArea read_from_stream() { //Jdb.enter("HDAP.read_from_stream()"); HtmlDocumentArea rv= null; if (can_read_from_stream()) { rv= area_stream.readHtmlDocumentArea(); if (null != rv) { last_read_area_y= rv.getY(); last_read_area_x= rv.getX(); if (null != area_cache) { area_cache.add(rv); } } } //Jdb.trace("area_cache == "+area_cache.jtoString()); //Jdb.exit("HDAP.read_from_stream() => " + rv); return rv; } private HtmlDocumentArea findArea (Graphics g, int look_x, int look_y) { //Jdb.enter("HDAP.findArea(g"+g+", "+look_x+", "+look_y+")"); HtmlDocumentArea this_area= null; if (null != area_cache) this_area= area_cache.findArea(look_x, look_y); if ((null == this_area) && can_read_from_stream()) { int best_area_x= 999; int best_area_y= 999; HtmlDocumentArea best_area= null; if (last_read_area_y <= look_y) { while ((can_read_from_stream()) && (last_read_area_y <= look_y)) { this_area= read_from_stream(); //(null != this_area) // && if (this_area.inside(look_x, look_y)) { best_area= this_area; } } } this_area= best_area; } //Jdb.exit("HDAP.findArea(g"+g+", "+look_x+", "+look_y+") => "+this_area); return this_area; } private HtmlDocumentArea findAreaRight (Graphics g, int look_x, int look_y) { // assume look_y fall in discrete line sized peices Jdb.enter("HDAP.findAreaRight(g"+g+", "+look_x+", "+look_y+")"); HtmlDocumentArea this_area= null; if (null != area_cache) this_area= area_cache.findAreaRight(look_x, look_y); if (null == this_area) { int this_area_x= 999; int this_area_y= 999; HtmlDocumentArea best_area= null; int best_area_x= 999; int best_area_y= 999; while ((can_read_from_stream()) && (last_read_area_y <= look_y)) { this_area= read_from_stream(); if (null != this_area) { this_area_x= this_area.getX(); this_area_y= this_area.getY(); if ((look_y == this_area_y) && (look_x <= this_area_x)) { if (last_read_area_x < best_area_x) { best_area= this_area; best_area_x= this_area_x; best_area_y= this_area_y; } } } } this_area= best_area; } Jdb.exit("HDAP.findAreaRight(g"+g+", "+look_x+", "+look_y+") => "+this_area); return this_area; } private HtmlDocumentArea findAreaBelow (Graphics g, int look_x, int look_y) { Jdb.enter("HDAP.findAreaBelow("+g+", "+look_x+", "+look_y+")"); HtmlDocumentArea this_area= null; if (null != area_cache) { Jdb.trace("area_cache.size() == "+area_cache.size()); this_area= area_cache.findAreaBelow(look_x, look_y); Jdb.trace("area_cache.findBelow("+g+", "+look_x+", "+look_y+") == "+this_area); } //Jdb.trace("area_cache == "+area_cache); //Jdb.trace("area_stream == "+area_stream); if (null == this_area) { int this_area_x= 999; int this_area_y= 999; HtmlDocumentArea best_area= null; int best_area_x= 999; int best_area_y= 999; while ((can_read_from_stream()) // && (last_read_area_y <= look_y)) && (null == best_area)) { this_area= read_from_stream(); //Jdb.trace("read_from_stream() == "+this_area); if (null != this_area) { this_area_x= this_area.getX(); this_area_y= this_area.getY(); if (look_y < this_area_y) { if ( (this_area_y < best_area_y) || ( (this_area_y == best_area_y) && (this_area_x < best_area_x))) { best_area= this_area; best_area_x= this_area_x; best_area_y= this_area_y; } } } } this_area= best_area; } Jdb.exit("HDAP.findAreaBelow("+g+", "+look_x+", "+look_y+") == "+this_area); return this_area; } private HtmlDocumentArea findAreaInRightBelow (Graphics g, int look_x, int look_y) { Jdb.enter("HDAP.findAreaIRB("+g+", "+look_x+", "+look_y+")"); HtmlDocumentArea this_area= null; if (null != area_cache) this_area= area_cache.findAreaInRightBelow(look_x, look_y); Jdb.trace("area_cache.size() == "+area_cache.size()); Jdb.trace("area_cache.findIRB("+g+", "+look_x+", "+look_y+") == "+this_area); //Jdb.trace("area_cache == "+area_cache); //Jdb.trace("area_stream == "+area_stream); if (null == this_area) { int this_area_x= 999; int this_area_y= 999; HtmlDocumentArea best_area= null; int best_area_x= 999; int best_area_y= 999; while ((can_read_from_stream()) // && (last_read_area_y <= look_y)) && (null == best_area) ) { this_area= read_from_stream(); Jdb.trace("read_from_stream() == "+this_area); if (null != this_area) { this_area_x= this_area.getX(); this_area_y= this_area.getY(); if (this_area.inside(look_x, look_y)) { Jdb.trace("area inside"); if ( (this_area_y < best_area_y) || ( (this_area_y == best_area_y) && (this_area_x < best_area_x)) ) { Jdb.trace("best"); best_area= this_area; best_area_x= this_area_x; best_area_y= this_area_y; } } else if ((look_x <= this_area_x) && (look_y <= this_area_y)) { Jdb.trace("area RB"); if ( (this_area_y < best_area_y) // || ( (this_area_y == best_area_y) // && (this_area_x < best_area_x)) ) { Jdb.trace("best"); best_area= this_area; best_area_x= this_area_x; best_area_y= this_area_y; } } else { Jdb.trace("area not inside, and not RB"); } } } this_area= best_area; } Jdb.exit("HDAP.findAreaIRB("+g+", "+look_x+", "+look_y+") == "+this_area); return this_area; } public void paintAreas(Graphics g) { Jdb.enter("HDAP.paintAreas(Graphics g)"); /* the position the scroll bar has slid us too */ int scroll_y= top_line; int scroll_x= 0; /* the left most point we draw at in the display area */ int line_x= scroll_x + 2; /* where in the document areas we are */ int area_x= scroll_x; int area_y= scroll_y; Dimension r= size(); int max_y= r.height + scroll_y; /* the tallest item found, used to advance area_y */ int max_height= -1; int bot_y= doc_lines; HtmlDocumentArea area; area= findAreaInRightBelow(g, area_x, area_y); if (null != area) { // move to start of this line; // could be before or after top of display; area_y= area.getY(); } while ((area_y < max_y) && (null != area)) { area.paint(g, scroll_x, scroll_y); max_height= area.getHeight(); area_x= area.getX() + area.getWidth(); area= findAreaRight(g, area_x, area_y); while (null != area) { area.paint(g, scroll_x, scroll_y); area_x= area.getX() + area.getWidth(); max_height= Math.max(max_height, area.getHeight()); area= findAreaRight(g, area_x, area_y); } area= findAreaBelow(g, area_x, area_y); if (null != area) { area_y= area.getY(); bot_y= Math.max(bot_y, area_y + area.getHeight()); } } /* area_y is the first free row, max_y is the first roww off screen */ bot_line= Math.max(area_y, max_y) - 1; /* ### need to correctly account for partial final lines */ // disp_lines= bot_line - top_line + 1; disp_lines= r.height; /* if we went farther down the document, update doc_lines */ if (doc_lines < bot_y) { doc_lines= bot_y; } Jdb.trace("HtmlDocumentAreaPanel.paintAreas(g) [" + top_line + "-" + bot_line + "==" + disp_lines + "] of " + doc_lines); Jdb.exit("HDAP.paintAreas(Graphics g)"); } public void paint(Graphics g) { Jdb.enter("HDAP.paint(g=="+g+")"); saved_graphics= g; //Jdb.trace("paint scrollbar"); if (null != scrollbar) scrollbar.paint(scrollbar.getGraphics()); if ((null == area_stream) && (null != region_stream)) { //Jdb.trace("new area_stream"); area_stream= new HtmlDocumentAreaStream(g, display, region_stream); } if ((area_cache != null) || (area_stream != null)) { //Jdb.trace("paint areas"); paintAreas(display.getGraphics()); } else { //Jdb.trace("super.paint?"); // super.paint(g); } Jdb.exit("HDAP.paint()"); } public void update(Graphics g) { Jdb.enter("HDAP.update(g=="+g+")"); super.update(g); Jdb.exit("HDAP.update(g=="+g+")"); } public void paintAll(Graphics g) { Jdb.enter("HDAP.paintAll(g=="+g+")"); super.paintAll(g); Jdb.exit("HDAP.paintAll(g=="+g+")"); } public void repaint() { Jdb.enter("HDAP.repaint()"); super.repaint(); Jdb.exit("HDAP.repaint()"); } public void repaint(long tm) { Jdb.enter("HDAP.repaint("+tm+"ms)"); super.repaint(tm); Jdb.exit("HDAP.repaint("+tm+"ms)"); } public void repaint(int x, int y, int wide, int tall) { Jdb.enter("HDAP.repaint("+x+", "+y+", "+wide+", "+tall+")"); super.repaint(x, y, wide, tall); Jdb.exit("HDAP.repaint("+x+", "+y+", "+wide+", "+tall+")"); } public void repaint(long tm, int x, int y, int wide, int tall) { Jdb.enter("HDAP.repaint("+tm+"ms, "+x+", "+y+", "+wide+", "+tall+")"); super.repaint(tm, x, y, wide, tall); Jdb.exit("HDAP.repaint("+tm+"ms, "+x+", "+y+", "+wide+", "+tall+")"); } public boolean imageUpdate(Image im, int flags, int x, int y, int wide, int tall) { Jdb.enter("HDAP.imageUpdate(im, "+flags+"flags, "+x+", "+y+", "+wide+", "+tall+")"); boolean rv= super.imageUpdate(im, flags, x, y, wide, tall); Jdb.exit("HDAP.imageUpdate(im, "+flags+"flags, "+x+", "+y+", "+wide+", "+tall+") => "+rv); return rv; } public void setTopLine(int t) { Jdb.enter("HDAP.setTopLine(" + t + ")"); Jdb.trace("doc_lines == " + doc_lines); if ((0 <= t) && (t <= doc_lines)) { Jdb.trace("fiddle top line"); if (top_line != t) { top_line= t; bot_line= -1; blank_and_repaint(100); } } Jdb.exit("HDAP.setTopLine(" + t + ")"); } public void softSetTopLine(int ntl) { ntl= Math.max(ntl, 0); ntl= Math.min(ntl, doc_lines - disp_lines); setTopLine(ntl); } public void scrollToLine(int l) { softSetTopLine(l); } public void scrollLines(int lines_down) { FontMetrics fm= display.getFontMetrics(appBodyFont); int fh= fm.getHeight(); softSetTopLine(top_line + lines_down*fh); } public void scrollPages(int pages_down) { int lines_per_page= bot_line - top_line + 1; int overlap= ((0 < pages_down) ?(-10) :((pages_down < 0) ?(10) :(0))); int new_top_line= top_line + ((lines_per_page+overlap)*pages_down); softSetTopLine(new_top_line); } public boolean handleEvent(Event e) { switch (e.id) { case Event.UP: case Event.SCROLL_LINE_UP: scrollLines(-1); break; case Event.DOWN: case Event.SCROLL_LINE_DOWN: scrollLines( 1); break; case Event.PGUP: case Event.SCROLL_PAGE_UP: scrollPages(-1); break; case Event.PGDN: case Event.SCROLL_PAGE_DOWN: scrollPages( 1); break; case Event.HOME: scrollToLine(0); break; case Event.SCROLL_ABSOLUTE: scrollToLine(((Integer)(e.arg)).intValue()); break; default: return false; } resetScrollbar(); //JppEvent bogus= new JppEvent(); //Jdb.trace("HDAP.handleEvent("+bogus.getEventIdName(e.id)+"=="+e+")"); return false; } public void resetScrollbar() { if (can_read_from_stream()) { scrollbar.setValues( top_line, disp_lines, 0, 2*doc_lines ); } else { scrollbar.setValues( top_line, disp_lines, 0, doc_lines ); } } public boolean insideText(int x, int y) { if (null != display) { //Jdb.trace("area_cache == "+area_cache.jtoString()); return display.inside(x, y); } else { return false; } } public HotItem hotItemAt(int x, int y) { HotItem rv= null; // ###assume graphic hasn't changed int scroll_x= 0; int scroll_y= top_line; HtmlDocumentArea l= findArea(saved_graphics, x+scroll_x, y+scroll_y); resetScrollbar(); if (null != l) { rv= l.getHotItem(); } return rv; } }