Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Using JEditorPane for HTML viewing

Posted on 1999-07-09
14
Medium Priority
?
1,696 Views
Last Modified: 2013-11-23
I need an HTML viewer for my Java application/applet. I was able to use JEditorPane for that purpose with the following code:

        documentText = new JEditorPane();
        documentText.addHyperlinkListener(new Hyperactive());
        documentText.setEditable(false);
        documentText.setEditorKit(new HTMLEditorKit());

The HTML gets constructed in my program on the fly, that is what I have is a String containing some HTML text.

There are two ways to display HTML in the pane, either using setPage(URL) or setText(String) methods.

Since I have a String it is natural to use the second method. When I use it the HTML displays correctly but I am unable to traverse the links in the document. All the links are local, that is they point to some location inside the document. In order to traverse the liks I have the folloing Listener (I've copied it from JDK documentation):

    class Hyperactive implements HyperlinkListener
    {
        public void hyperlinkUpdate(HyperlinkEvent e)
        {
            if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
            {
                JEditorPane pane = (JEditorPane) e.getSource();
               
                if (e instanceof HTMLFrameHyperlinkEvent)
                {
                    HTMLFrameHyperlinkEvent  evt = (HTMLFrameHyperlinkEvent)e;
                   
                    HTMLDocument doc = (HTMLDocument)pane.getDocument();
                   
                   
                   
                    doc.processHTMLFrameHyperlinkEvent(evt);

                   
                }
                else
                {
                    try
                    {
                        pane.setPage(e.getURL());
                    }
                    catch (Throwable t)
                    {
                        t.printStackTrace();
                    }

                }
            }
        }
    }  

What happens is that when I click on a link, the hyperlinkUpdate() method gets invoked and when it reaches the line

       pane.setPage(e.getURL());

it throws an exception since e.getURL() returns null. The reason being (I suppose) the fact that the documtn was created from a strin not from a URL.

The question is how to solve this problem.

One solution would be to store the document in a file and construct a URL for that file or define a new protocol which points to a String in memory but neither of those solutions (they work fine for an application) works for an applet. So I would like to be able to display an HTML string in memory using setText() and be able to traverse the links inside that document.

Thank you.
0
Comment
Question by:msmolyak
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 3
  • 3
  • +3
14 Comments
 
LVL 6

Expert Comment

by:Holger101497
ID: 1245666
Just a wild idea *g*: Have you tried using something like:
<HEAD>
  <BASE HREF="http://www.myvirtualserver.com/myfakedirectory/">
....
</HEAD>
in your string??

This "should" normally work, but of course I have no idea about JEditorPane and how it would react...

Hope it works - Good luck!
0
 
LVL 8

Expert Comment

by:diakov
ID: 1245667
Some time ago heyhey_ has suggested an idea, that actually works in all browsers.

Your applet can install a simple http server on a listening socket. Thus the applet can both use the a http://localhost:port/something.html, and generate the content for it. It turns out that establishing listening socket on ports > 1024 is not 'prosecuted' by the security manager.

This might solve your problem, as your solution about constructin an URL for our document can be exported to an applet.

Cheers,
  Nik
0
 
LVL 5

Author Comment

by:msmolyak
ID: 1245668
Guys, thank you for suggestions. Nik, I will try yours, it does look promising.  What exactly doI do on the "server" side of my applet? Create a ServerSocket and whenever someone connects to it feed the text of a document?

Holger, I am not sure how your idea might work. I can certainly add the "base" URL for my document and it will probably be prepended to the internal links, but when the JEditorPane trys to load the document http://www.myvirtualserver.com/myfakedirectory/#LINK1 what is it going to get? There is no server involved. Or I misunderstand something?


0
The top UI technologies you need to be aware of

An important part of the job as a front-end developer is to stay up to date and in contact with new tools, trends and workflows. That’s why you cannot miss this upcoming webinar to explore the latest trends in UI technologies!

 
LVL 8

Expert Comment

by:diakov
ID: 1245669
I imagine you can do the following:

1. Get sources of an existing web http server in Java (there are examples).

2. Modify, cut, delete the unnecessary parts. Change the listening port number to 1025 or dynamically find a free one. (since your server and client are the applet, you share this number)

3. Act as a servlet :-) if you wish, but you'd rather feed directly the HTML page providing the outpur stream for the incoming request.

Cheers,
  Nik
0
 
LVL 5

Author Comment

by:msmolyak
ID: 1245670
I've done what you suggested, Nik, but the security problem still remains. If I load the applet from a Web server (not from a CLASSPATH), the code is unable to load the URL http://localhost:...

I guess, it stands the reason, if the applet came from a certain server it only allows connections that server and not to anything else including localhost.

I am using Java Plug-In thus the behavior is not dependent on the browser.

The exception I get while trying to load the document is:

Opening http://localhost:1025/931812000747 no proxy
java.security.AccessControlException: access denied (java.net.SocketPermission localhost:1025 connect,resolve)
      at java.security.AccessControlContext.checkPermission(AccessControlContext.java:195)
      at java.security.AccessController.checkPermission(AccessController.java:403)
      at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
      at java.lang.SecurityManager.checkConnect(SecurityManager.java:1006)
      at sun.plugin.protocol.jdk12.http.HttpURLConnection.connect(HttpURLConnection.java:163)
      at sun.plugin.protocol.jdk12.http.HttpURLConnection.getInputStream(HttpURLConnection.java:191)
      at sun.net.www.protocol.http.HttpURLConnection.getHeaderField(HttpURLConnection.java:775)
      at java.net.URLConnection.getContentType(URLConnection.java:367)
      at javax.swing.JEditorPane.getStream(JEditorPane.java:481)
      at javax.swing.JEditorPane.setPage(JEditorPane.java:309)

The application works fine.

Any suggestions?

Michael
0
 
LVL 8

Expert Comment

by:diakov
ID: 1245671
1. Did the listening socket open correctly? To make an independent test you can probably run a separate simple application (not another applet) and connect to your applet.

2. Try using the 127.0.0.1 instead of localhost.

I'm sorry but because of limited time I cannot run some test myself.

Cheers,
  Nik
0
 
LVL 16

Expert Comment

by:heyhey_
ID: 1245672
you want to load another generated web page inside the same JEditorPane ?

than this suggestion won't work. I've suggested it for a slightly different situation when you want to open generated web pages inside another browser window.
your browser is alloed to access 127.0.0.1 to render the page, but you applet / JEditorPane is not.
0
 
LVL 5

Author Comment

by:msmolyak
ID: 1245673
No such luck.

I've tried heyhey's suggestion by attempting to display the page in the browser window. I've got a Security exception in the HTTP server code in the accept() call of a ServerSocket. By the way I am using Java Plug-In to use Swing in my applet.

Isn't Java security great? It slaps your wrist each time you are trying to do something meaningful.

Any other ideas? Is it possible to resolve the local references in JEditorPane if I use setString() instead of setPage()?
0
 
LVL 16

Expert Comment

by:heyhey_
ID: 1245674
>> in the accept() call of a ServerSocket.

it's strange ....
please try again with bigger port number (bigger than 1024) - 3000 for example.
0
 
LVL 5

Author Comment

by:msmolyak
ID: 1245675
I was trying port 1025. Switching to 3000 did not change anything. Here is the exception:

java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:2012 accept,resolve)
      at java.security.AccessControlContext.checkPermission(AccessControlContext.java:195)
      at java.security.AccessController.checkPermission(AccessController.java:403)
      at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
      at java.lang.SecurityManager.checkAccept(SecurityManager.java:1117)
      at java.net.ServerSocket.implAccept(ServerSocket.java:245)
      at java.net.ServerSocket.accept(ServerSocket.java:224)
      at QueryClient.JavaQuery.Webster.run(Webster.java:96)

Port 2012 is not the port the server was listening on. It is probably the port chose for communicating with the client.
0
 
LVL 16

Expert Comment

by:heyhey_
ID: 1245676
I don't have Java Plug-In1.2 / JDK 1.2 installed, but can you take a look at these lines yourself ?
(new Java versions - new problems... )

at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.SecurityManager.checkAccept(SecurityManager.java:1117)
0
 

Accepted Solution

by:
Jdoit earned 800 total points
ID: 1245677
Hi,
i'll send u the entire code. Comile all the files and execute TestBrowser

/*
 * TestBrowser.java
 * A test bed for the JEditorPane and a custom editor kit.
 * This extremely simple browser has a text field for typing in
 * new urls, a JEditorPane to display the HTML page, and a status
 * bar to display the contents of hyperlinks the mouse passes over.
 */

import javax.swing.*;
import javax.swing.text.*;
import java.awt.event.*;
import java.awt.*;

public class TestBrowser extends JFrame {

  public TestBrowser(String startingUrl) {
    // Ok, first just get a screen up and visible, with an appropriate
    // handler in place for the kill window command
    super("Test Pane");
    setSize(400,300);
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent we) {
      we.getWindow().setVisible(false);
      System.exit(0);
      }
    });

    // Now set up our basic screen components, the editor pane, the
    // text field for URLs, and the label for status and link information
    JPanel urlPanel = new JPanel();
    urlPanel.setLayout(new BorderLayout());
    JTextField urlField = new JTextField(startingUrl);
    urlPanel.add(new JLabel("Site: "), BorderLayout.WEST);
    urlPanel.add(urlField, BorderLayout.CENTER);
    final JLabel statusBar = new JLabel(" ");

    // Here's the editor pane configuration.  It's important to make
    // the "setEditable(false)" call, otherwise our hyperlinks won't
    // work.  (If the text is editable, then clicking on a hyperlink
    // simply means that you want to change the text...not follow the
    // link.)
    final JEditorPane jep = new JEditorPane();
    jep.setEditable(false);

    // Here's where we force the pane to use our new editor kit
    jep.setEditorKitForContentType("text/html", new PatchedHTMLEditorKit());
    try {
      jep.setPage(startingUrl);
    }
    catch(Exception e) {
      statusBar.setText("Could not open starting page.  Using a blank.");
    }
    JScrollPane jsp = new JScrollPane(jep);

    // and get the GUI components onto our content pane
    getContentPane().add(jsp, BorderLayout.CENTER);
    getContentPane().add(urlPanel, BorderLayout.NORTH);
    getContentPane().add(statusBar, BorderLayout.SOUTH);

    // and last but not least, hook up our event handlers
    urlField.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
      try {
        jep.setPage(ae.getActionCommand());
      }
      catch(Exception e) {
        statusBar.setText("Could not open starting page.  Using a blank.");
      }
      }
    });
    jep.addHyperlinkListener(new SimpleLinkListener(jep, urlField, statusBar));
  }

  public static void main(String args[]) {
    (new TestBrowser(args.length > 0
                 ? args[0]
                 : "file:///c:/tmp/test.html")).setVisible(true);
  }
}



/*
 * SimpleLinkListener.java
 * A hyperlink listener for use with JEditorPane.  This
 * listener will change the cursor over hotspots based on enter/exit
 * events and also load a new page when a valid hyperlink is clicked.
 */

import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;

public class SimpleLinkListener implements HyperlinkListener {

  private JEditorPane pane;       // The pane we're using to display HTML

  private JTextField  urlField;   // An optional textfield for showing
                                  // the current URL being displayed

  private JLabel statusBar;       // An option label for showing where
                                  // a link would take you

  public SimpleLinkListener(JEditorPane jep, JTextField jtf, JLabel jl) {
    pane = jep;
    urlField = jtf;
    statusBar = jl;
  }

  public SimpleLinkListener(JEditorPane jep) {
    this(jep, null, null);
  }

  public void hyperlinkUpdate(HyperlinkEvent he) {
    // We'll keep some basic debuggin information in here so you can
    // verify our new editor kit is working.
    System.out.print("Hyperlink event started...");

    HyperlinkEvent.EventType type = he.getEventType();
    // Ok.  Decide which event we got...
    if (type == HyperlinkEvent.EventType.ENTERED) {
      // Enter event.  Go the the "hand" cursor and fill in the status bar
      System.out.println("entered");
      pane.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
      statusBar.setText(he.getURL().toString());
    }
    else if (type == HyperlinkEvent.EventType.EXITED) {
      // Exit event.  Go back to the default cursor and clear the status bar
      System.out.println("exited");
      pane.setCursor(Cursor.getDefaultCursor());
      statusBar.setText(" ");
    }
    else {
      // Jump event.  Get the url, and if it's not null, switch to that
      // page in the main editor pane and update the "site url" label.
      System.out.println("activated");
      try {
      pane.setPage(he.getURL());
      if (urlField != null) {
        urlField.setText(he.getURL().toString());
      }
      }
      catch (Exception e) {
      e.printStackTrace();
      }
    }
  }
}




/*
 * PatchedHTMLEditorKit.java
 * A simple extension of the HTMLEditor kit that fires Enter/Exit
 * hyperlink events.
 */

import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
import javax.swing.event.*;
import java.awt.event.*;
import java.awt.*;
import java.io.Serializable;
import java.net.*;

public class PatchedHTMLEditorKit extends HTMLEditorKit {

  // Since we only have two mouse events to listen to, we'll use the same
  // method to generate the appropriate hyperlinks and distinguish
  // between them when we react to the mouse events.
  public static final int JUMP = 0;
  public static final int MOVE = 1;

  LinkController myController = new LinkController();

  public void install(JEditorPane c) {
    c.addMouseListener(myController);
    c.addMouseMotionListener(myController);
  }

  public static class LinkController extends MouseInputAdapter
  implements Serializable {

    URL currentUrl = null;

    // here's the mouseClicked event similar to the one in
    // the regular HTMLEditorKit, updated to indicate this is
    // a "jump" event
    public void mouseClicked(MouseEvent e) {
      JEditorPane editor = (JEditorPane) e.getSource();

      if (! editor.isEditable()) {
      Point pt = new Point(e.getX(), e.getY());
      int pos = editor.viewToModel(pt);
      if (pos >= 0) {
        activateLink(pos, editor, JUMP);
      }
      }
    }

    // And here's our addition.  Now the mouseMove events will
    // also call activateLink, but with a "move" type
    public void mouseMoved(MouseEvent e) {
      JEditorPane editor = (JEditorPane) e.getSource();

      if (! editor.isEditable()) {
      Point pt = new Point(e.getX(), e.getY());
      int pos = editor.viewToModel(pt);
      if (pos >= 0) {
        activateLink(pos, editor, MOVE);
      }
      }
    }

    // activateLink has now been updated to decide which hyperlink
    // event to generate, based on the event type and status of the
    // currentUrl field.  Rather than have two handlers (one for
    // enter/exit, one for active) we do all the work here.  This
    // saves us the effort of duplicating the href location code.
    // But that's really minor point.  You could certainly provide
    // two handlers if that makes more sense to you.
    protected void activateLink(int pos, JEditorPane html, int type) {
      Document doc = html.getDocument();
      if (doc instanceof HTMLDocument) {
      HTMLDocument hdoc = (HTMLDocument) doc;
      Element e = hdoc.getCharacterElement(pos);
      AttributeSet a = e.getAttributes();
      AttributeSet anchor = (AttributeSet) a.getAttribute(HTML.Tag.A);
      String href = (anchor != null) ?
        (String) anchor.getAttribute(HTML.Attribute.HREF) : null;
      
      System.out.println("this is the string rep " +anchor.toString());
      
      boolean shouldExit = false;

      HyperlinkEvent linkEvent = null;
      if (href != null) {
        URL u;
        try
              {
          u = new URL(hdoc.getBase(), href);
              }
        catch (MalformedURLException m)
        {
          u = null;
        }

        if ((type == MOVE) && (!u.equals(currentUrl))) {
          linkEvent = new HyperlinkEvent(html,
                      HyperlinkEvent.EventType.ENTERED, u, href);
          currentUrl = u;
        }
        else if (type == JUMP) {
          linkEvent = new HyperlinkEvent(html,
                          HyperlinkEvent.EventType.ACTIVATED, u, href);
          shouldExit = true;
        }
        else {
          return;
        }
        html.fireHyperlinkUpdate(linkEvent);
      }
      else if (currentUrl != null) {
        shouldExit = true;
      }
      if (shouldExit)
      {
        linkEvent = new HyperlinkEvent(html,
                               HyperlinkEvent.EventType.EXITED,
                               currentUrl, null);
        html.fireHyperlinkUpdate(linkEvent);
        currentUrl = null;
      }
      }
    }
  }
}






/*
 * LauchTestBrowser.java
 * A simple starting point for kicking off the test browser
 * in a real browser like Netscape.
 */

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class LaunchTestBrowser extends Applet {

  TestBrowser browser;

  public void init() {
    browser = new TestBrowser("http://www.javaworld.com/");
    browser.setSize(400,500);
    Button b = new Button("Launch TestBrowser");
    add(b);
    b.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
      browser.setVisible(true);
      }
    });
  }
}

0
 
LVL 5

Author Comment

by:msmolyak
ID: 1245678
Jdoit,

Thank you for the posting.  You did not say however whether your code addresses my problem. I do not have a problem of displaying HTML or following links in general. My problem is displaying HTML which comes from a string, not a URL and then following internal links (like <A NAME=HIT0000 HREF=#BESTHIT>[Go To Best Hit]</A>).

Please let me know if your code solves this problem.

Michael
0
 
LVL 1

Expert Comment

by:Moondancer
ID: 6827881
This question was awarded, but never cleared due to the JSP-500 errors of that time.  It was "stuck" against userID -1 versus the intended expert whom you awarded.  This corrects the problem and the expert will now receive these points; points verified.

Please click on your Member Profile and select "View Question History" to navigate through any open or locked questions you may have to update and finalize them.  Or if you are an EE Pro user, click the link below to select open items for your Member ID using Power Search:
http://www.experts-exchange.com/jsp/qPowerSearch.jsp.

This is the Community Support link, if help is needed, along with the link to All Topics which reflects many TAs recently added.

http://www.experts-exchange.com/jsp/qList.jsp?ta=commspt
http://www.experts-exchange.com/jsp/zonesAll.jsp
 
Thank you,
Moondancer
Moderator @ Experts Exchange
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Java contains several comparison operators (e.g., <, <=, >, >=, ==, !=) that allow you to compare primitive values. However, these operators cannot be used to compare the contents of objects. Interface Comparable is used to allow objects of a cl…
Java had always been an easily readable and understandable language.  Some relatively recent changes in the language seem to be changing this pretty fast, and anyone that had not seen any Java code for the last 5 years will possibly have issues unde…
Viewers learn how to read error messages and identify possible mistakes that could cause hours of frustration. Coding is as much about debugging your code as it is about writing it. Define Error Message: Line Numbers: Type of Error: Break Down…
This theoretical tutorial explains exceptions, reasons for exceptions, different categories of exception and exception hierarchy.
Suggested Courses

670 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question