/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package pdfdb.gui.frames;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkEvent.EventType;
import javax.swing.event.HyperlinkListener;
import pdfdb.app.EventController;
import pdfdb.gui.customcomponents.BrowserMenu;
/** A simple implementation of an internal help browser. This frame builds on
* top of a basic JEditorPane and is therefore only capable of displaying and
* rendering limited HTML 3.2 and a subset of CSS 1. This means that help pages
* must be simple and could be extended in the future using a library such as
* Lobo.
*
* The help frame makes several additions to the standard JEditorPane including
* saving the history state and adding backwards and forwards buttons to the
* frame. (This is managed by the EventController but could be moved into this
* class if reused in another project - trivial alteration.)
*
* This class is more of a quick and dirty implementation of a help system.
* Alterations to this class could include:-
*
* - Usage of an xhtml based help file system.
* - Tree view displaying section headers on the left hand side.
* - Allowing semantically correct help files.
*
* @author ug22cmg */
public class HelpFrame extends AppDialog implements HyperlinkListener
{
private JEditorPane browser;
private ArrayList<String> history;
private BrowserMenu menu;
private int now = 0;
/** Initializes the frame and moves the web browser to the specified
* URL.
* @param url The starting URL.
* @throws java.io.IOException If an error occurs. */
public HelpFrame(URL url) throws IOException
{
super(MainFrame.getMainFrame());
visit(url, true);
}
/** Initializes GUI components. */
@Override
protected void initializeComponents()
{
JPanel pane = (JPanel) super.getContentPane();
browser =new JEditorPane();
menu = new BrowserMenu();
history = new ArrayList<String>();
JScrollPane scrollPane = new JScrollPane(browser);
Dimension dim = new Dimension(700, 400);
Dimension minDim = new Dimension(400, 400);
String backCmd = String.valueOf(EventController.OP_HELP_BACK);
String nextCmd = String.valueOf(EventController.OP_HELP_NEXT);
browser.addHyperlinkListener(this);
browser.setEditable(false);
scrollPane.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
menu.getBackButton().setActionCommand(backCmd);
menu.getForwardButton().setActionCommand(nextCmd);
menu.getBackButton().addActionListener(EventController.getActionListener());
menu.getForwardButton().addActionListener(EventController.getActionListener());
pane.setLayout(new BorderLayout());
pane.add(menu, BorderLayout.NORTH);
pane.add(scrollPane, BorderLayout.CENTER);
super.setTitle("Online Help");
super.setMinimumSize(minDim);
super.setSize(dim);
super.setPreferredSize(dim);
}
/** Sets the current location to the specified URL and adds to the
* history records if record is true. The menu is also updated.
* @param url The new url to visit.
* @param record Whether to record as a new destination.
* @throws java.io.IOException If an error occurs. */
private void visit(URL url, boolean record) throws IOException
{
if (record) history.add(url.toExternalForm());
browser.setPage(url);
recheckButtons();
}
/** Updates the state of the buttons to either disabled or enabled. */
private void recheckButtons()
{
boolean canGoBack = now > 0;
boolean canGoForward = now < (history.size() - 1);
Cursor activeCurs = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
Cursor inactiveCurs = Cursor.getDefaultCursor();
menu.getBackButton().setEnabled(canGoBack);
menu.getBackButton().setCursor(canGoBack ? activeCurs : inactiveCurs);
menu.getBackButton().repaint();
menu.getForwardButton().setEnabled(canGoForward);
menu.getForwardButton().setCursor(
canGoForward ? activeCurs : inactiveCurs);
menu.getForwardButton().repaint();
}
/** Removes entries in the history that are no longer valid then
* calls the visit method.
* @param event The hyperlink event. */
@Override
public void hyperlinkUpdate(HyperlinkEvent event)
{
try
{
if (event.getEventType() == EventType.ACTIVATED)
{
while (now != history.size() - 1)
{
history.remove(history.size() - 1);
}
now++;
visit(event.getURL(), true);
}
}
catch (IOException ioe)
{
}
}
/** Progresses backwards through the history.
* @throws java.io.IOException If an error occurs. */
public void back() throws IOException
{
if (now != 0)
{
now--;
visit(new URL(history.get(now)), false);
}
}
/** Progresses forwards through the history.
* @throws java.io.IOException If an error occurs. */
public void forward() throws IOException
{
if (now != history.size() - 1)
{
now++;
visit(new URL(history.get(now)), false);
}
}
/** Removes action listeners to avoid memory leaks. */
@Override
public void finalize()
{
ActionListener a = EventController.getActionListener();
if (this.menu != null && a != null)
{
this.menu.getForwardButton().removeActionListener(a);
this.menu.getBackButton().removeActionListener(a);
}
}
/** Test method.
* @param args Program arguments
* @throws java.io.IOException If an error occurs.*/
public static void main(String[] args) throws IOException
{
new HelpFrame(new URL("http://www.google.com")).setVisible(true);
}
}