README CalHTMLPane 2.021 ----------------------------------------------------------------------- CONTENTS - Overview - License for use - Requirements - Using a CalPane - Adding your own components and images - Intercepting events from within a document - Supported tags and attributes - Form components - The Pane's Dialog - The Pane's Focus Manager - Optimize Display - Viewing Web pages - Bug reports - Known problems - Contacting the author ----------------------------------------------------------------------- OVERVIEW ----------------------------------------------------------------------- This is version 2.021 of the CalHTMLPane ('CalPane' or 'Pane'). The CalHTMLPane is a sub-component of a Java development package named Calpa, and was built to provide two main services to the package: -Instantly accessible HTML Help documentation without the need to start up a native Web browser. -The display of HTML documents dynamically authored from online databases. A CalHTMLPane allows Java application builders to incorporate HTML documents into a GUI display. It supports a wide range of HTML3.2 and HTML4.0 tags so that documents can be authored with popular HTML editors and immediately displayed within a Java application. HTML form components can be included in these documents in the normal way, and a programming API is provided to enable the controlling Java application to interact with those components, and to enable programmers to customize the component within their own applications. The Pane also contains caching and history features which remove much of the burden of document management. Keyboard support is provided, including tabbing between and activating hyperlinks via the keyboard. The Pane can be used to display Web pages from within an application, and Web browsing capabilities can be built around it. It can automatically handle basic form submissions, with more complex server interaction being dealt with by the programmer if so desired. However the Pane cannot be expected to handle documents which incorporate inline scripts. That is not the purpose of its design. This document gives the class user a general introduction to the CalHTMLPane's API and discusses certain aspects of its implementation. It is not necessary to read all of the sections below to begin using a CalPane, but following the first five examples will give the reader a good insight into how the calpa.html public classes relate to one another. Additional documentation is also provided: JavaDoc for the CalPane's public classes, and HTML documentation giving examples of tag and attribute usage. The HTML documents need to be viewed within a running CalPane, not a normal Web browser, as they demonstrate aspects of the component's form rendering styles as well as other features specific to a CalPane. 'CalGuide.html' is the main index of this documentation. The rest of these notes presume a certain level of Java programming experience on the part of the reader, and strong familiarity with the Swing package. ----------------------------------------------------------------------- LICENSE FOR USE ----------------------------------------------------------------------- You must read the license that accompanies the calp.html package class files before you may use them. Briefly, however, and without prejudice to the terms of the license, you are permitted to use the class files: -for non-commercial use. -for commercial use, provided that you are only using the class files to show either : (a) Help, Support or Tutorial documentation within your application, and provided that the use of the classes is incidental to the main function of that application. or: (b) Advertising or Promotional material relating to your application or business. For other commercial uses you should email the copyright holder at the following address stating the desired use of the classes, and consideration will be given to the grant of a commercial license. Contact: Andrew J. Moulden offshore@netcomuk.co.uk ----------------------------------------------------------------------- REQUIREMENTS ----------------------------------------------------------------------- Version 2.0 of the CalHTMLPane requires a Java 2 Virtual Machine, and the classes have not been tested against any version of the Java Development Kit before 1.2 Final. This component was built and tested on a Win32 machine running Windows95. It is believed to be written in 100% Java using Sun's JDK tools and should perform identically elsewhere. It is best to give an increased amount of memory to the JVM running a CalPane. The first instantiation of the Pane (including its static support classes) uses 300K - 400K of memory, but it is the HTML documents which take up space. As a general guide (assuming you are caching documents) : -For showing fairly simple Help documentation 2MB of system memory should be sufficient. -For more complex documentation such as the JDK API, 4MB min is recommended if 50+ documents will be viewed and cached. -For viewing the sort of documents found on commercial Web sites consider 8MB+. The images within such pages can consume a great deal of memory. The amount of memory given to the JVM can be set by using the -ms switch when a program is run. To give an application 8MB of RAM the command would be: java -ms8m MyApplication Memory specification is not mandatory however. The VM will allocate memory on an as-needed basis, though this may slow document loading. The caching of documents is programmable, and the CalPane's Manager will start removing the oldest documents from the cache when it gets full. Caching of images is left to the JVM. If the CalHTMLPane is run in conjunction with a Just-In-Time (JIT) compiler, the first two or three documents will load quite slowly and the mouse cursor may not focus hyperlinks for a brief moment. However there should be a significant performance boost thereafter. On many machines parsing matches or even surpasses that of a native Web browser, allowing the disabling of caching if documents are being loaded from a local file system. ----------------------------------------------------------------------- USING A CALPANE ----------------------------------------------------------------------- The CalHTMLPane is a Swing JComponent. Specifically it extends the JLayeredPane class. It is therefore recommended that the component be used in a 'lightweight' Swing environment rather than mixing it with 'heavyweight' AWT components. The JAR file containing the CalPane classes (calpahtml.jar) needs to be in your classpath. The following code should then load and display an HTML document of your choosing: ---------------------------------------- import java.net.*; import java.awt.*; import javax.swing.*; import calpa.html.*; public class MyFirstCalPaneApplication { public static void main(String args[]) { URL url = null; try { //This is an example URL. You need to format your own. //If you use an http URL you'll need an open http connection url = new URL("file:///c:/jdk1.2/docs/api/overview-summary.html"); } catch (MalformedURLException e) { System.err.println("Malformed URL"); System.exit(1); } JFrame f = new JFrame(); CalHTMLPane pane = new CalHTMLPane(); f.getContentPane().add(pane, "Center"); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); f.setSize(new Dimension(Math.min(d.width - 10, 800), Math.min(d.height - 40, 600))); f.setVisible(true); if (url != null) { pane.showHTMLDocument(url); pane.requestFocus(); } } } ---------------------------------------- Assuming the document has displayed correctly you should find that you can navigate any hyperlinks. Any links which can't be followed will result in an error dialog appearing. This dialog will be discussed later. Keyboard navigation should be avaialable within the document. We called requestFocus() for the Pane, and pressing the TAB key should move focus to the next hyperlink or form control if either exist. -SHIFT-TAB will move backwards through the focus cycle. -ENTER will activate a hyperlink if one has focus. -CURSOR-DOWN or SPACE will scroll the Pane downward if the document is long enough. -CURSOR-UP or SHIFT_SPACE will scroll upward. -CURSOR_LEFT, CURSOR_RIGHT scroll left and right. -PAGE_UP and PAGE_DOWN scroll up and down a page at at time If there is a Frameset document on screen it is possible to tab between frames by pressing CTRL-TAB (which also gets the user out of the Pane completely if there are other controls in the application which can accept keyboard focus). * * * The CalPane is a component, not an application, and so it is left to the class user to create customized navigation buttons such as 'back' and 'forward'. However, the Pane has an internal navigation bar which is useful for testing purposes, and in the next example we will make this visible. This introduces another of the calpa.html public classes - CalHTMLPreferences. A CalHTMLPreferences ('CalPref') object controls aspects of a CalPane's behaviour and rendering policy - whether to underline hyperlinks, handle form submission etc. Every Pane has a controlling CalHTMLPreferences object, and when the first example above was run, a default CalPref was used. The programmer can create an instance of CalHTMLPreferences, modify selected values by using its access methods, and then pass it to a CalPane constructor. It is possible to change certain preferences after the Pane has been constructed, but only before construction can *all* preferences be set. Note also that a single CalPref can control any number of CalPanes. So, in the following slightly modified version of the first example we will create a CalHTMLPreferences object and use one of its public methods to get the CalPane's test navigation bar showing: ---------------------------------------- import java.net.*; import java.awt.*; import javax.swing.*; import calpa.html.*; public class MySecondCalPaneApplication { public static void main(String args[]) { URL url = null; try { url = new URL("file:///c:/jdk1.2/docs/api/overview-summary.html"); } catch (MalformedURLException e) { System.err.println("Malformed URL"); System.exit(1); } JFrame f = new JFrame(); //create a Preferences object CalHTMLPreferences pref = new CalHTMLPreferences(); //use one of its methods to enable the test navbar pref.setShowTestNavBar(true); //now pass the pref object to the Pane's constructor CalHTMLPane pane = new CalHTMLPane(pref, null, null); f.getContentPane().add(pane, "Center"); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); f.setSize(new Dimension(Math.min(d.width - 10, 800), Math.min(d.height - 40, 600))); f.setVisible(true); if (url != null) { pane.showHTMLDocument(url); } } } ---------------------------------------- You should see a rather unexciting navigation bar when you run the program, but at least it is now possible to traverse the CalPane's history, reload a document, stop any processes if necessary, navigate by entering a URL in the textfield, and get some status information on document loading. Note that this navbar is actually *within* the Pane and is ignored by the Pane's focus manager. You cannot tab to the controls because they do not exist as far as the Pane is concerned. (The textfield will accept a single name as an argument. If you type 'amazon' for example it will treat this as 'http://www.amazon.com') * * * Designing your own custom controls for a CalHTMLPane is very straightforward, as demonstrated in Example 3. We will create some external buttons ('Back', 'Forward', 'Reload' and 'Stop') to demonstrate how controls can easily be added. [ Dean Jones' icon collection at: http://webart.javalobby.org/jlicons/ contains a number of icons which are well-suited for buttons to control a CalHTMLPane. Dean has generously made these free for use within Java applications. ] ---------------------------------------- import java.net.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import calpa.html.*; public class MyThirdCalPaneApplication { public static void main(String args[]) { URL url = null; try { url = new URL("file:///c:/jdk1.2/docs/api/overview-summary.html"); } catch (MalformedURLException e) { System.err.println("Malformed URL"); System.exit(1); } JFrame f = new JFrame(); CalHTMLPane pane = new CalHTMLPane(); f.getContentPane().add(pane, "Center"); //create a panel, add buttons, and add a listener to the buttons JPanel p = new JPanel(); MyListener ml = new MyListener(pane); String[] s = {"Reload", "Back", "Forward", "Stop"}; JButton b; for (int i=0; i<4; i++) { b = new JButton(s[i]); b.addActionListener(ml); p.add(b); } f.getContentPane().add(p, "South"); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); f.setSize(new Dimension(Math.min(d.width - 10, 800), Math.min(d.height - 40, 600))); f.setVisible(true); if (url != null) { pane.showHTMLDocument(url); } } private static class MyListener implements ActionListener { CalHTMLPane pane; public MyListener(CalHTMLPane pane) { this.pane = pane; } public void actionPerformed(ActionEvent e) { String s = e.getActionCommand(); if (("Reload").equals(s)) { pane.reloadDocument(); } else if (("Back").equals(s)) { pane.goBack(); } else if (("Forward").equals(s)) { pane.goForward(); } else if (("Stop").equals(s)) { pane.stopAll(); } } } } ---------------------------------------- The JavaDoc included in the download gives details regarding the methods which can be used to directly control a CalHTMLPane. The reader may be wondering however how the buttons on the test navbar in example 2 'knew' when to turn on and off. This introduces a third calpa.html public class - CalHTMLObserver ('CalObs' or 'Observer'). In the same way a Pane always has a resident Preferences object, it also always has an Observer. Once again a default CalHTMLObserver is used if one is not passed to the Pane's constructor. CalHTMLObserver is an interface, and an Observer can be created for a CalHTMLPane in one of two ways: -by implementing CalHTMLObserver in a class. This means implementing all methods of the interface. -by extending the public DefaultCalHTMLObserver class. This class implements all the methods of CalHTMLObserver as null-ops, so only those methods of interest need be overridden. The methods of CalHTMLObserver are basically all update methods. When certain events occur within a CalHTMLPane (e.g. a form submit button is pressed, a hyperlink gets focus, a document has finished loading) the Pane will pass information about the event to its resident CalObs, and from these updates the programmer can determine whether buttons should be on or off, what the title of the current document is, and so on. A single CalObs can listen to any number of CalPanes, and centralising events into this single interface is far more efficient than using normal AWT event firing, additionally avoiding potentially dangerous synchronization problems. Event multicasting is not normally required in a component of this type, but if this is necessary the programmer can maintain listener lists within the CalHTMLObserver implementation. In the next example we instantiate a CalHTMLPane as before, and this time add a single label at the bottom in place of the buttons in the previous example. We create our own CalHTMLObserver by extending DefaultCalHTMLObserver, and override a single method which allows us to get updates on focused hyperlinks. We then show the URL of the link in the label. ---------------------------------------- import java.net.*; import java.awt.*; import javax.swing.*; import calpa.html.*; public class MyFourthCalPaneApplication { public static void main(String args[]) { URL url = null; try { url = new URL("file:///c:/jdk1.2/docs/api/overview-summary.html"); } catch (MalformedURLException e) { System.err.println("Malformed URL"); System.exit(1); } JFrame f = new JFrame(); JLabel label = new JLabel("0"); label.setBorder(BorderFactory.createEmptyBorder(2, 8, 2, 8)); label.setPreferredSize(label.getPreferredSize()); label.setText(""); CalHTMLPane pane = new CalHTMLPane(null, new MyCalHTMLObserver(label), null); f.getContentPane().add(pane, "Center"); f.getContentPane().add(label, "South"); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); f.setSize(new Dimension(Math.min(d.width - 10, 800), Math.min(d.height - 40, 600))); f.setVisible(true); if (url != null) { pane.showHTMLDocument(url); } } private static class MyCalHTMLObserver extends DefaultCalHTMLObserver { JLabel label; public MyCalHTMLObserver(JLabel label) { super(); this.label = label; } public void linkFocusedUpdate(CalHTMLPane p, URL url) { label.setText((url == null) ? "" : url.toExternalForm()); } } } ---------------------------------------- When the above example is run, links which get either mouse or keyboard focus should be shown at the bottom of the frame. When no link has focus the label's text will be blank (actually, the label does not clear itself when you go from one document to another, but that would mean using another update method which would complicate the example). The example is in fact a little flawed. In the linkFocusedUpdate() method there is no check made to ensure that the CalHTMLPane sending the update is the one we originally instantiated. Although it seems obvious that the CalHTMLPane sending the updates to the CalObserver *must* be the Pane we created earlier, this is not necessarily so. HTML allows the author to specify a target frame in hyperlinks, and if the target is called '_blank' or is not the name of a currently visible frame, then a new frame should be created to show the linked document. By default a CalHTMLPane will create a new CalPane if it comes across a link like this, and this could have happened when the above example was run. In most cases the programmer will want a customized version of the CalHTMLPane to appear in circumstances such as this, and the automatic opening of new frames can be disabled through a method in CalHTMLPreferences. When so disabled, the CalPane will call an update method in CalHTMLObserver requesting the programmer to create a new CalHTMLPane. ----------------------------------------------------------------------- ADDING YOUR OWN COMPONENTS AND IMAGES TO A CALPANE ----------------------------------------------------------------------- There is just one more public calpa.html class that needs to be discussed - CalHTMLManager ('Manager'). This class consists of a number of static fields and methods and basically acts as a storage point for all the CalPanes running in an application. The Manager caches documents and imagemaps, and performs some other behind-the-scenes housekeeping functions. There are also some public methods in CalHTMLManager which allow the programmer to store JComponents and Images (i.e. instances of java.awt.Image) with the Manager. Once these are cached with the Manager they can be incorporated into HTML documents simply by naming them within a relevant tag. A component or image can be referenced and reused in any number of documents, and shown in any running CalPane (though of course, a component can only be in one place at a time). The ability to add images in this manner was put into the Calpa package because there are times when it is desirable to display an image which the class user can be *sure* is available and fully loaded. A document may for example contain form controls created with the new HTML4.0 <BUTTON> tag (which the CalPane supports) and such buttons can hold almost any type of HTML content, including images. It might look odd however if an image which the programmer wants to display in one of these buttons loads asynchronously. To avoid this the image can be pre-loaded, added to CalHTMLManager, thus ensuring that it will display immediately when shown in a document. For a simple example, try adding this to a test HTML document: <IMG jname="cal_warning"> The 'jname' attribute (which is not HTML) tells the CalPane's parser to use an image that has been cached with CalHTMLManager. Note that there is no need to use the 'src=..." attribute. The example IMG tag above will display an exclamation mark image which is used in the CalPane's error dialog. For JComponents the <OBJECT> tag or the form <INPUT> tag should be used. Here are examples of both: <OBJECT type=jcomponent jname=mycolorchooser name=chooser> <INPUT type=jcomponent jname=mainmenubar name=menubar> If a JComponent has been added to CalHTMLManager with the corresponding name it will be incorporated into the document much like an image or form control (the name of the component is set by calling the AWT Component method setName()). Note that the 'name' attribute is included in the above tags. This is so that they can be used within an HTML form. Normally when a form is submitted the browser will gather values from each component and submit these values as part of the form submission. But how do we find the 'value' of a custom component? What CalPane does with these custom objects is to call their toString() method and transmit this with the form. So, by overriding the toString() method in your custom components you can pass information out of that component and send it with the form. Rather than add JComponents one by one to CalHTMLManager, it is possible to add an *array* of JComponents. A class name needs to be specified for the array, and then this array can be referenced within documents like so: <OBJECT type=jcomponent jclass=mycomps jname=mycolorchooser> Here is some code that will get a JColorChooser showing within an HTML document, and it also demonstrates another aspect of the CalPane - the ability to show HTML from a String argument rather than a URL: ---------------------------------------- import java.net.*; import java.awt.*; import javax.swing.*; import calpa.html.*; public class MyFifthCalPaneApplication { public static void main(String args[]) { String markup = "<H1>Hello World</H1><P align=center><OBJECT type=jcomponent jname=mycolorchooser>"; //create ColorChooser, name it, add it to CalHTMLManager JColorChooser chooser = new JColorChooser(); chooser.setName("mycolorchooser"); CalHTMLManager.addUserComponent(chooser); JFrame f = new JFrame(); CalHTMLPane pane = new CalHTMLPane(); f.getContentPane().add(pane, "Center"); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); f.setSize(new Dimension(Math.min(d.width - 10, 800), Math.min(d.height - 40, 600))); f.setVisible(true); pane.showHTMLDocument(markup); } } ----------------------------------------------------------------------- INTERCEPTING EVENTS FROM WITHIN A DOCUMENT ----------------------------------------------------------------------- The 'jname' attribute used above in the <IMG>, <OBJECT> and <INPUT> tags can also be used within the <A> tag. A CalPane will not try and follow an activated hyperlink which has a jname, but it will pass the information to its resident CalHTMLObserver. This means that the programmer can put links within documents which, when activated, will be sent externally to the CalPane. This is akin to having a hyperlink with an ActionListener attached to it. Note that unlike the <IMG> tag where no 'src' attribute is required, the 'href' attribute must be specified within the <A> tag. This is to avoid null URL errors being thrown inside the CalPane and also so that the hyperlink can still be marked as visited. A real URL should not be specified, but one that Java's URL class will accept as being valid. So, an <A> tag might look like this: <A href="http://www.dummy.com" jname="load_personnel_files"> Click here to load the personnel files </A> There is also one other way for the programmer to receive data from within documents. Normally when the HTML <FORM> tag is used, the 'method' attribute will be given one of two arguments: 'post' or 'get'. Within the CalPane however the value 'jform' can also be used. The Pane will not attempt to handle a 'jform' submission when a 'submit' control is activated. Like the <A> tag above it will simply pass on all the form data to its CalHTMLObserver where it can be handled directly by the programmer. For example, the following might be put: <FORM method=jform action="quit_application"> <INPUT type=submit value="Quit"> </FORM> This will create a single 'Quit' button. There may of course be situations where users need to be able to choose from a range of buttons. Here is one of the ways of doing this: <FORM method=jform action="user_choice"> <INPUT type=submit name=yes value=Yes> <INPUT type=submit name=no value=No> <INPUT type=submit name=cancel value=Cancel> <INPUT type=submit name=help value=Help> </FORM> When a user activates a 'submit' control in an HTML form, the activated control is treated as being successful, and so the form data will include details of which control has been pressed. Thus if a user pressed the Help button in the above example, the form data would include the text: help=Help. ----------------------------------------------------------------------- SUPPORTED HTML TAGS AND ATTRIBUTES ----------------------------------------------------------------------- The CalHTMLPane does not support any particular HTML standard. The aim has simply been to provide a component for the Calpa package which will display *most* HTML documents and display them at a speed which a user of that document will find acceptable. This speed aspect was considered to be of paramount importance, and it is the reason why style sheet support has not yet been integrated into the component. The overhead in parsing style data is simply too great at the current time. However, the CalHTMLPane's structure has been designed to support style sheets, and adding this at a later date will only involve very minor code reauthoring. The second most obvious omission in the CalPane is support for the <APPLET> tag. There is a version of the CalPane which fully supports applets, but this is not being released publicly under free license. Apart from the above, you should find that the CalPane has fairly wide tag and attribute support. More details and some examples of tag/attribute usage can be found in the HTML documentation included in the download. Generally the Pane supports most HTML3.2 tags and a fair number of HTML4.0 ones. In most cases tags have been implemented according to HTML4.0 specification rather than HTML3.2. Here is a brief summary of a CalHTMLPane's tag support: -Tables support the <COLGROUP>, <COL>, <THEAD>, <TBODY> and <TFOOT> tags, and widths can be absolute, percentage or relative. The bgcolor, bordercolor, bordercolorlight and bordercolordark attributes allow almost any color rendering to be specified for tables, groups, rows, columns and individual cells. The new <TABLE> 'frame' and 'rules' attributes are also supported. -A CalPane can handle Frames including the HTML4.0 <IFRAME> tag, allowing the simple inclusion of documents within documents. The <IFRAME> tag has yet to be fully exploited by authors - it is possible for example to run a timer which periodically updates an <IFRAME> with adverts while the rest of the surrounding document stays as normal. The effect is very powerful. -The <FONT> tag will take a 'face=xxx' argument, but this is limited at present. This is due to a major bug in Java 2 relating to system fonts. The code for handling system fonts is already within CalPane but is currently disabled because of this bug. -Client-side image maps are supported, including the 'circle' and 'poly' shapes. Coordinates can also expressed in percentage rather than absolute coordinates, and HTML4.0 recommendation that even Internet Explorer 4 has yet to support. The HTML4.0 specification states that image maps can be sourced from other documents, but this is very difficult to implement. However this is supported to a certain extent - the CalPane will cache any image maps it comes across, and if the map is referenced in another document it will be available from the cache. -Images, tables and form components will 'float' (i.e. text and other objects will wrap around them) if they are given either an 'align=left' or 'align=right' alignment argument. Multiple objects can be floated on the same line (left and right). -Lists should operate much as normal, though Netscape Navigator and Internet Explorer treat the DD/DT tags slightly differently under certain circumstances. The Pane acts much like Explorer. -The <HR> tag will take a color argument -<STRIKE> and <U> (underline) are both implemented, but the <BLINK> tag is not as it has almost universally fallen out of use. -Forms are supported and are the subject of the next section. Form components support the HTML4.0 'accesskey' argument which allows key accelerators to be given to controls . The 'tabindex' attribute is in the CalHTMLPane code but is currently disabled as it creates a very heavy parsing overhead (because it can be used not only with form components, but with hyperlinks too). -Finally, the CalPane supports a number of tag attributes (mainly color-related) which are not officially supposed to exist. A document using these attributes will show as normal in any other HTML renderer. ----------------------------------------------------------------------- FORM COMPONENTS ----------------------------------------------------------------------- As the CalHTMLPane was tested across different Look&Feels it immediately became apparent that there were major problems in simply instantiating form controls and adding them into documents without modification. The various Pluggable Look And Feel (PLAF) styles supported by Swing are designed primarily for application-based programming rather than what might be termed as 'document-based' or 'content-based' GUI displays. These PLAFs assume the presence of a consistent background ('control') color against which components will be rendered, and borders and other style features are incorporated into the components with this control color in mind. It is possible to change the color of certain basic controls with methods such as setBackground() and setForeground(), but on more complex components such as comboboxes these methods have limited effect. In an HTML document however, the control color is essentially the background color of the document itself - which can be any color at all, including black and white. When standard Swing components are rendered against such backgrounds there can be a clash (or over- similarity) of colors which causes carefully programmed style features to completely disappear, leaving a rather odd-looking GUI control sitting on the reader's screen. There are other problems too. Some PLAF controls (Motif buttons for example) are given large borders *outside of the component itself* and it becomes impossible to line such components up properly within an HTML document. Opacity is also an issue, with some components looking bizarre if they are made opaque, and others almost disappearing if their opacity is set to false. In order to try and overcome these difficulties a CalHTMLPane supports two additional rendering styles - THREEDEE and FLUSH. Rendering form controls in these styles ensures that the document will be displayed in exactly the same way without regard for the currently installed LAF. There is an obvious downside to this - the form rendering style incorporated into the document may be out of step with the installed Look&Feel. However, testing has shown that this is not too much of an issue. The document reader is not overly aware of any disparity, particularly if the color of the form control is matched to the document background. The two CalPane form rendering styles give the document author considerable freedom in setting component colors by using attributes within the relevant form tags. The accompanying HTML documentation contains a number of examples which demonstrate how to use the Pane's own form rendering styles. The default rendering style is set through a method in CalHTMLPreferences, but this does not prevent styles being mixed freely within documents. It is possible to put a LOOKANDFEEL checkbox next to a THREEDEE button which is next to a FLUSH textfield. The choice of from component rendering has therefore been left entirely in the hands of the programmer/author. ----------------------------------------------------------------------- THE PANE'S DIALOG ----------------------------------------------------------------------- When an error is thrown within a CalPane (for example when an invalid URL is specified in an activated hyperlink) notification of the failure is sent to the resident CalHTMLObserver. Strictly speaking it is up to the programmer to inform the user that such an error has occured, as the CalPane may only be a small part of a much larger application. However, the CalHTMLPane has a dialog of sorts which at times can be extremely useful, not only for error messages, but for obtaining user-input or displaying a menu on top of HTML documents. By default this dialog will appear when an error occurs, or for example when a form POST submission is made, when a warning is given to the user that the transmission will be unsecure. The showing of these messages can easily be disabled through a method in CalHTMLPreferences. 'Dialog' is perhaps a misnomer. The CalPane's dialog cannot be modal, it is not resizable and there is no bar along its top with a close button on it. It should really be thought of as a blank canvas which is displayed in the JLayeredPane.MODAL_LAYER of the Pane. To display the dialog the programmer calls one of the CalPane's showDialog() methods and pass it a text string. This string is parsed as HTML and the results are displayed in the dialog much as an HTML document would be. (The only reason the display of a URL-based dialog has not been allowed is because fetching the dialog data could itself throw an error and we would have the problem of showing an error dialog for an error dialog.) The dialog can handle all supported HTML tags except for inline frames and framesets. This means form components, images, hyperlinks, tables, lists etc. can all be included within the dialog. With a bit of practice the programmer will see that it is possible to simulate almost any 'normal' dialog by using HTML, with the added bonus that complex dialogs can be created which would be extremely difficult to produce without the power of HTML. The dialog can be shown anywhere within the Pane, at almost any size. Events such as button presses can be picked up in the CalHTMLObserver, and the programmer can add custom Swing components (with listeners attached) to CalHTMLManager and have them displayed in the dialog using the <OBJECT> tag. The following simple program creates a CalHTMLPane with a JTextArea below it and a 'Show Dialog' button. HTML can be enetred into the textarea and when the button is pressed the dialog will appear showing the rendered HTML. The HTML can be edited and another button press will update the dialog display. Here is some example HTML that you might want to try first: <TABLE width=100% bgcolor=navy border=1 rules=none cellspacing=0> <TR><TD> <FONT face=helvetica color=white><B>User Log-on</B></FONT> </TD></TR> </TABLE> <FORM method=jform action=user_logon> <TABLE width=100% cellspacing=0> <COLGROUP align=center></COLGROUP> <TR><TD> Please enter your username: </TD></TR> <TR><TD> <INPUT type=password> </TD></TR> <TR><TD> <BR> <INPUT type=submit value=Log-On name=logon> <INPUT type=submit value=Cancel name=cancel> </TD></TR> </TABLE> </FORM> Some points to note: -The dialog has a marginwidth/marginheight of 0. If you want some insets around your HTML content, wrap the content in a <TABLE> tag with cellspacing or cellpadding set to the desired border. -Because we send a width of -1 to the showDialog() method in the example, the Pane shows the dialog with a default width. This is why the dialog may be wider than the HTML content you enter. -Setting the 'bgcolor' attribute in a <BODY> tag will change the background color of the dialog, and its border colors as well. -When the dialog is displayed it gets keyboard focus. Pressing the ESC key will close the dialog. -The dialog will not display scrollbars. -The dialog's default font sizes are smaller than those used within normal documents. -Try this: <FORM method=jform action=close_dialog> <INPUT type=submit value=Close> </FORM> ---------------------------------------- import java.awt.*; import java.awt.event.*; import javax.swing.*; import calpa.html.*; public class MySixthCalPaneApplication { public static void main(String args[]) { Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); d.width = Math.min(d.width, 800); d.height = Math.min(d.height, 600); JFrame f = new JFrame(); CalHTMLPane pane = new CalHTMLPane(); JPanel p = new JPanel(); JTextArea ta = new JTextArea(); ta.setLineWrap(true); JScrollPane sp = new JScrollPane(ta); sp.setPreferredSize(new Dimension(d.width / 2, d.height / 4)); JButton b = new JButton("Show Dialog"); b.addActionListener(new MyListener(pane, ta)); p.add(sp); p.add(b); f.getContentPane().add(pane, "Center"); f.getContentPane().add(p, "South"); f.setSize(new Dimension(d.width - 10, d.height - 40)); f.setVisible(true); } private static class MyListener implements ActionListener { CalHTMLPane pane; JTextArea ta; public MyListener(CalHTMLPane pane, JTextArea ta) { this.pane = pane; this.ta = ta; } public void actionPerformed(ActionEvent e) { pane.showDialog(ta.getText(), null, -1, -1, -1, -1); } } } ----------------------------------------------------------------------- THE PANE'S FOCUS MANAGER ----------------------------------------------------------------------- When a CalPane is instantiated, it immediately removes the existing Focus Manager (usually Swing's DefaultFocusManager) and installs a CalFocusManager to handle keyboard events. This action can be prevented via a method in CalHTMLManager. Swing's DefaultFocusManager uses a top-down, left-right tabbing order which is not really suitable for HTML documents. The HTML4.0 specification states that the default tab order within documents should be determined by the order in which entities appear in tags, but this will not happen with Swing's Manager. If, for example, a button is put in a document and then a textarea is placed to the right of it, the textarea will most likely receive focus before the button because it is taller and hence has a lower y-coordinate on the screen. Even more importantly, the Swing Manager will only tab between components, whereas in an HTML document we need to be able to tab between hyperlinks as well. Swing only allows a single Focus Manager per thread, so running the CalFocusManager is an all-or-nothing affair. There is a method in the JComponent class which looks as if it could solve the problem of focus management without installing a new Manager: by overriding isManagingFocus() and returning a value of true it is possible for a component to handle its own keyboard events. Unfortunately Swing's DefaultFocusManager will still manage focus for components *within* the CalPane, even when the CalPane is handling its own focus. Nevertheless, we could still solve this if there was a method in JComponent such as: setIsManagingFocus(boolean b) We could then call this method with an argument of 'true' for all the CalPane's children. This would cause the Swing Manager to ignore key events from such components and we could pick these up from a listener. As far as can be seen however, the only way to tell the Swing Manager that we are handling focus is to *extend* the component and override isManagingFocus(). This is totally impractical. Most users need not worry about the above. The CalFocusManager should operate in much the same way as Swing's Manager when keyboard events occur outside the CalPane. Only *inside* the Pane will tabbing be handled differently. ----------------------------------------------------------------------- OPTIMIZE DISPLAY ----------------------------------------------------------------------- 'Optimize display' is a feature of the CalHTMLPane which has yet to be fully implemented. However, programmers may find it useful in certain situations. By default, optimizeDisplay is disabled within the pane. A method in CalHTMLPreferences allows it to be set to one of two levels: CalCons.OPTIMIZE_FONTS CalCons.OPTIMIZE_ALL When OPTIMIZE_FONTS is enabled, the default font size of a document will change depending on the width of its display area. This can be quite useful when displaying help documentation in a frameset. The JDK API documents are a good example. When shown in frames, the index part of the documentation is displayed in two narrow frames at the side of the screen. If these are viewed in a CalPane with OPTIMIZE_FONTS switched on, more of the index is visible because the fonts used are smaller. The fonts used in the main display frame will remain as normal. If the frames are now resized by dragging the mouse it will be seen that OPTIMIZE_FONTS is dynamic - as soon as a frame's width crosses a certain threshold, the document will be reformatted with a new base font size. OPTIMIZE_ALL takes this a step further by trying to alter certain HTML parameters in order to fit the current document into its display area. With HTML tables for example, a table's border, cellspacing and cellpadding will be progressively reduced until they reach their absolute minimum levels. Table preferred widths will be overriden where possible so that column sizes can be reduced. In short, the CalPane will do whatever it can to avoid horizontal scrolling. The optimizeDisplay feature is probably most useful when dealing with technical and support documentation that could be running on any size of display. It is not wise to use it when trying to show the sort of graphically-rich HTML pages found on commercial Web sites. Such pages tend to be formatted by their authors to absolute pixel widths, and any attempt to scale these pages usually upsets the fine balance of their design. ----------------------------------------------------------------------- VIEWING WEB PAGES ----------------------------------------------------------------------- It must be stressed that if this component is used on the Web the user will encounter a number of pages which render incompletely. Inline scripting is becoming very common on the major sites, partcularly for the dynamic creation of form controls (e.g. the checkboxes which give suggested extra search parameters on Excite). The CalHTMLPane simply ignores these scripts. Programmers should also be aware of how the CalPane handles many of today's commercial Web pages. These tend to be constructed in a similar manner: a banner (which often includes an animated GIF) is placed across the top of the page, and the rest of the document consists of one or two large tables which format the content to a 640 or 800 pixel display width. Like the majority of browsers, the CalPane does not support incremental table display, so most of the page will not be shown until all the table data has been received. This is not normally a problem as the CalPane can parse this data as fast as Java can deliver it over the Web. However, a difficulty arises when the page contains images of unspecified width and height. If an author puts the widths and heights of images within <IMG> tags then the document format can be determined before the image has even begun loading. Without this size information however, an HTML renderer can handle the page in two basic ways: -a default size can be given to the image before its true size is known. This means that the page can be displayed immediately, but has the severe disadvantage that the whole document needs to be completely reformatted once the actual image size is determined. If there are many such images within the page, the constant reformatting is extremely irritating to the user, and can considerably lengthen the total time taken to display the page. -we can wait until all image sizes are known and then display the document in a single pass. The downside here is that the user's screen is going to remain blank for some time as the images load. The CalPane takes the latter approach, and the same effect can be seen on many Web browsers. Apart from perhaps the page banner appearing, nothing else is shown until the whole page suddenly appears fully formatted with text and images. Some document authors actually favor this display method because the user gets the full impact of their page design rather than seeing it a piece at a time. If you are monitoring events from within the Pane via the statusUpdate() method in CalHTMLObserver you will receive a WAITING_FOR_IMAGES update when this situation occurs. This message indicates that the document has been fully parsed but the final display format cannot be completed until all image sizes are known. You may also encounter problems with Web pages that contain several animated GIFs. See the 'known problems' section for details. ----------------------------------------------------------------------- BUG REPORTS ----------------------------------------------------------------------- Please report any bugs you encounter with the component. It would be extemely helpful if you could describe exactly the circumstances under which the problem arose. In particular a sample HTML document which trips the bug would be most welcome. Not every apparently incorrect rendering is due to code deficiency. When testing Web pages it immediately becomes apparent that many authors do not check to see how their documents display on different browsers. There are of course only two browsers that really matter, but page designers may be surprised to see how differently the latest versions of Explorer and Navigator handle identical HTML. It is therefore possible that programmers will come across apparent rendering bugs which are accounted for by a differing interpretation of the underlying HTML tags. Send bug reports to: offshore@netcomuk.co.uk ----------------------------------------------------------------------- KNOWN PROBLEMS ----------------------------------------------------------------------- Below are listed the known problems with the CalHTMLPane (in estimated order of seriousness). -There are occasional rendering problems on certain Web pages which appear to be caused by incorrect character conversion within the Java stream classes. Colors sometime display incorrectly and text information disappears. If the Web page is displayed within a browser such as Netscape Navigator and saved to a local file, when that local file is loaded into the CalPane it displays perfectly. If however the character stream sent from Java is saved to a local file, the characters are slightly different to those in the Navigator file. This could be caused by incorrect byte-to-character conversion, or it could be that Netscape's programmers have built in some error correction into their byte converter which fixes what experience has shown to be 'bad' byte sequences. * * * -There can be problems with Web pages which contain 5+ animated GIFs. It does not seem to be documented anywhere, but there appears to be a limit to the number of images Java will load asynchronously. With an animated GIF however, the imageUpdate method never sets the ALLBITS flag because image frames need to be constantly streamed in. We get a FRAMEBITS flag instead. This means that to keep showing the animated image we never return 'false' to imageUpdate, and the image thread is permanently active while the page is loaded. Unfortunately this animated image counts towards the asynchronous limit and once there are 5 (or whatever the limit is) such GIFs running all other image loading becomes blocked. One obvious way to deal with this would be to delay the loading of animated GIFs until all other images had loaded. Unfortunately there is no simple way to tell if an image is a GIF89 until loading has begun. If we then halt the GIF once we have determined its type to allow other images to load, subsequent paint operations on that image later can lead to the throwing of a java.lang.SecurityException from within the Sun classes. This will not halt the program, but the animated GIF sometimes will not display correctly. As a consequence certain pages with a high number of GIF89s will not load all images, and the DOC_LOADED call to CalHTMLObserver will not be made. * * * - A wait cursor ought to be displayed in the period from when a hyperlink is pressed to the opening of the URL connection. This cannot currently be implemented due to a Java bug (which is peculiar to Win32) which stops the cursor changing until the mouse is moved. This can result in the wait cursor continuing to display long after a method call to change it back to the default cursor. Surprisingly JavaSoft engineers refuse to accept the validity of this bug, despite constant complaints from developers. * * * - JScrollPane will sometimes fail to display a horizontal scrollbar when one is needed. This problem has been in Swing since its very early release. Under certain circumstances the calculations which determine whether or not a horizontal scrollbar is required seem to fail to take account of the fact that a *vertical* scrollbar is going to be displayed, narrowing the viewport width. * * * - There is a Java 2 bug which can cause incorrect style rendering of system fonts. This can cause a whole page of text to be rendered in italic for example instead of plain. Java's logical fonts are not affected, so until this bug is fixed the support of system fonts within CalPane has been disabled. * * * - Swing contains a bug which prevents the background of a component being painted when the component dimensions are very large. This can cause some temporarily strange behavior with a loading Web page which has a wallpaper background image. The page should display correctly when it has finished loading. * * * - If a document contains an inline frame (created with the <IFRAME> tag) and a number of documents have been viewed within it, tracking back through the Pane's history will take the user back to those documents as normal.However, if the user has scrolled up or down the document which contains the IFRAME and the IFRAME is no longer in view within the viewport, the history changes will not be visible. The user will be pressing the BACK button and nothing will appear to be happening. In theory the IFRAME should be scrolled into view when history events like this take place, but this is very difficult to implement because of the way frame histories work. Microsoft's programmers have not been able to solve this in Internet Explorer 4. * * * - The setting of percentage widths/heights for images within nested entities (i.e. tables) has been disabled. It is clear from seeing pages authored with such dimensions that there is no consensus as to what the proper rendering should be. HTML4.0 specifies that the %width/height relates not to the image size but to the amount of 'available width' - the space between the current left and right margins. But does this mean the document width or the TD/TH width? The latter seems the obvious answer, but then we find authors using markup such as: <TABLE><TR><TD> <IMG src="pic.jpg" width=20% height=10%> </TD></TR></TABLE> ...which is chicken-and-egg HTML. There's no way the table size can be computed. * * * - The <INPUT type=file> tag has not been implemented because Swing's JFileChooser is still unstable. * * * - There's a minor problem with the Windows L&F. The scrollbar track color in this L&F is gray, but it has no border. If a document is displayed which has an identical background color to the scrollbar track color, the two merge into one and this results in a scrollbar thumb that appears to be floating in mid-air. ----------------------------------------------------------------------- ACKNOWLEDGEMENTS ----------------------------------------------------------------------- Thanks to: -Roedy Green, Elliotte Rusty Harold, and Peter van der Linden for the wealth of Java information they freely supply. -Steve Wilson, co-author of the MetalLookAndFeel, for his patient explanations to Swing developers. ----------------------------------------------------------------------- CONTACTING THE AUTHOR ----------------------------------------------------------------------- Please contact: Andrew Moulden offshore@netcomuk.co.uk Address: 82A Queens Road, Leicester LE2 1TU United Kingdom +44 116 270 5090