/* * The University of Wales, Cardiff Triana Project Software License (Based * on the Apache Software License Version 1.1) * * Copyright (c) 2007 University of Wales, Cardiff. All rights reserved. * * Redistribution and use of the software in source and binary forms, with * or without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. The end-user documentation included with the redistribution, if any, * must include the following acknowledgment: "This product includes * software developed by the University of Wales, Cardiff for the Triana * Project (http://www.trianacode.org)." Alternately, this * acknowledgment may appear in the software itself, if and wherever * such third-party acknowledgments normally appear. * * 4. The names "Triana" and "University of Wales, Cardiff" must not be * used to endorse or promote products derived from this software * without prior written permission. For written permission, please * contact triana@trianacode.org. * * 5. Products derived from this software may not be called "Triana," nor * may Triana appear in their name, without prior written permission of * the University of Wales, Cardiff. * * 6. This software may not be sold, used or incorporated into any product * for sale to third parties. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL UNIVERSITY OF WALES, CARDIFF OR ITS CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * ------------------------------------------------------------------------ * * This software consists of voluntary contributions made by many * individuals on behalf of the Triana Project. For more information on the * Triana Project, please see. http://www.trianacode.org. * * This license is based on the BSD license as adopted by the Apache * Foundation and is governed by the laws of England and Wales. * */ package org.trianacode.gui.help; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Event; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.InputStream; import java.net.URL; import java.util.Enumeration; import java.util.Vector; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JToolBar; import javax.swing.KeyStroke; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import org.trianacode.gui.hci.GUIEnv; /** * The main window for the Triana Help application. This class contains the entire GUI functionality of TrianaHelp. * * @author Melanie Rhianna Lewis * @version $Revision: 4048 $ * @see HtmlPane */ public class TrianaHelpFrame extends JFrameEx { // The pane which actually contains the HTML document private HtmlPane htmlPane; private JFileChooser fileChooser; private JButton copyButton, backButton, forwardButton; private JMenuItem editCopy, goBack, goForwards; private HistoryDialog historyDialog; // A vector which contains the CloseFrameListeners private Vector closeFrameVector; // A string which contains the path to the images private String imagePath; private TrianaHelpProperties properties; public TrianaHelpFrame(String title, String helpFile) { super(title); addWindowListener(new WindowAdapter() { public void windowClosed(WindowEvent e) { processCloseFrameEvent(new CloseFrameEvent(TrianaHelpFrame.this)); setBounds(properties, "Help.Window"); properties.saveUserSettings(); } }); initFrame(helpFile); setIconImage(getImageResource("/triana/help/images/frame-icon.jpg")); properties = new TrianaHelpProperties(); properties.loadUserSettings(); setBounds(getBounds(properties, "Help.Window")); setCascadeLocation(50, 50); } public TrianaHelpFrame(String helpFile) { this("Triana Help", helpFile); } public TrianaHelpFrame() { this("Triana Help", null); } public void initFrame(String file) { // System.out.println("[Starting TrianaHelp]"); // Initialise the CloseFrameEvent stuff closeFrameVector = new Vector(); addWindowListener(new WindowClosingAction()); // Create a menu bar // System.out.println("[Creating menu]"); JMenuBar menuBar = new JMenuBar(); addMenus(menuBar); setJMenuBar(menuBar); // Create a tool bar // System.out.println("[Creating tool bar]"); JToolBar toolBar = new JToolBar(); addToolBarButtons(toolBar); // Create the HtmlPane and attach our SelectionListener class to it // to keep to copy button and menu item updated. // System.out.println("[Creating html pane]"); if (file != null) { htmlPane = new HtmlPane(file); } else { htmlPane = new HtmlPane(); } htmlPane.getEditorPane().addCaretListener(new SelectionListener()); // Get the history list and add the custom UrlEventListener to it htmlPane.getUrlHistory().addUrlEventListener(new NavigationListener()); // Store the index file if (file != null) { htmlPane.setIndex(file); } // Put all the bits in to a single JPanel and make it the // content pane. // System.out.println("[Creating main frame]"); JPanel contentPane = new JPanel(); contentPane.setLayout(new BorderLayout()); contentPane.add(toolBar, BorderLayout.NORTH); contentPane.add(htmlPane, BorderLayout.CENTER); setContentPane(contentPane); // Create the file chooser dialog fileChooser = new JFileChooser(); fileChooser.setDialogTitle("Open file..."); // Create the history dialog historyDialog = new HistoryDialog(this, "History", true, htmlPane.getUrlHistory()); setSize(new Dimension(600, 400)); } /** * Creates the menus and menu items. It creates instances of the Action classes that contain the functionality of * the menu items. It also gives the menu items appropriate accelerators. * * @param menuBar The menuBar on which to create the menus. */ private void addMenus(JMenuBar menuBar) { JMenuItem menuItem; JMenu menu, subMenu; // Create the File menu // ******************** // First create the menu and then the submenu menu = new JMenu("File"); subMenu = new JMenu("Open"); menuItem = new JMenuItem("File..."); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, Event.CTRL_MASK)); menuItem.addActionListener(new FileOpenAction()); subMenu.add(menuItem); menuItem = new JMenuItem("Location..."); menuItem.addActionListener(new FileOpenURLAction()); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, Event.CTRL_MASK)); subMenu.add(menuItem); menu.add(subMenu); menu.addSeparator(); menuItem = new JMenuItem("Close"); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, Event.META_MASK)); ; menuItem.addActionListener(new FileCloseAction()); menu.add(menuItem); menuBar.add(menu); // Create the Edit menu // ******************** menu = new JMenu("Edit"); // We need to keep this item hence the separate variable editCopy = new JMenuItem("Copy"); editCopy.addActionListener(new EditCopyAction()); editCopy.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, Event.CTRL_MASK)); ; editCopy.setEnabled(false); menu.add(editCopy); menu.addSeparator(); menuItem = new JMenuItem("Select all"); menuItem.addActionListener(new EditSelectAllAction()); menu.add(menuItem); menuBar.add(menu); // Create the Go menu // ****************** menu = new JMenu("Go"); // We need to keep this item hence the separate variable goBack = new JMenuItem("Back"); goBack.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0)); goBack.setEnabled(false); goBack.addActionListener(new GoBackAction()); menu.add(goBack); // We need to keep this item hence the separate variable goForwards = new JMenuItem("Forwards"); goForwards.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0)); goForwards.setEnabled(false); goForwards.addActionListener(new GoForwardsAction()); menu.add(goForwards); menuItem = new JMenuItem("Index"); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, Event.CTRL_MASK)); ; menuItem.addActionListener(new GoIndexAction()); menu.add(menuItem); menu.addSeparator(); menuItem = new JMenuItem("History..."); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, Event.CTRL_MASK)); ; menuItem.addActionListener(new GoHistoryAction()); menu.add(menuItem); menuBar.add(menu); // Create the Help menu // ******************** menu = new JMenu("Help"); menuItem = new JMenuItem("Help"); menuItem.addActionListener(new HelpHelpAction()); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0)); menu.add(menuItem); menu.addSeparator(); menuItem = new JMenuItem("About TrianaHelp..."); menuItem.addActionListener(new HelpAboutAction()); menu.add(menuItem); menuBar.add(menu); // The help menu gets displayed on the right // menuBar.setHelpMenu(menu); } /** * Creates the buttons on a toolbar. It creates instances of the Action classes that contain the functionality of * the tool bar buttons. It also supplies the buttons with an appropriate tool tip message. * * @param toolBar The toolBar on which to create the buttons. */ private void addToolBarButtons(JToolBar toolBar) { JButton button; // The file open button button = new JButton(GUIEnv.getIcon("open.png")); button.setToolTipText("Open a file"); button.addActionListener(new FileOpenAction()); toolBar.add(button); // The location open button button = new JButton(GUIEnv.getIcon("world.png")); button.setToolTipText("Open a URL"); button.addActionListener(new FileOpenURLAction()); toolBar.add(button); toolBar.addSeparator(); // The copy button // We need to keep this item hence the separate variable copyButton = new JButton(GUIEnv.getIcon("copy.png")); copyButton.setToolTipText("Copy selected text"); copyButton.setEnabled(false); copyButton.addActionListener(new EditCopyAction()); toolBar.add(copyButton); toolBar.addSeparator(); // The previous page button backButton = new JButton(GUIEnv.getIcon("left.png")); backButton.setToolTipText("Go back"); backButton.setEnabled(false); backButton.addActionListener(new GoBackAction()); toolBar.add(backButton); // The next page button forwardButton = new JButton(GUIEnv.getIcon("right.png")); forwardButton.setToolTipText("Go forwards"); forwardButton.setEnabled(false); forwardButton.addActionListener(new GoForwardsAction()); toolBar.add(forwardButton); // The index page button button = new JButton(GUIEnv.getIcon("help.png")); button.setToolTipText("Show index"); button.addActionListener(new GoIndexAction()); toolBar.add(button); } private Image getImageResource(String name) { Image image = null; try { int c; InputStream in = this.getClass().getResourceAsStream(name); ByteArrayOutputStream out = new ByteArrayOutputStream(); for (; ;) { if ((c = in.read()) < 0) { break; } out.write(c); } image = this.getToolkit().createImage(out.toByteArray()); } catch (Exception e) { System.err.println("Error trying to load " + name + " from jar file."); e.printStackTrace(); } return image; } /* ********** SUPERCEDED FUNCTIONS ********** The images are now loaded from the resource tree using getImageResouce() as defined above. public void setImagePath(String imagePath) { if (imagePath != null) { if (imagePath.equals("")) { this.imagePath = imagePath + File.pathSeparator; } else { this.imagePath = imagePath; } } else { this.imagePath = ""; } } public String getImagePath() { return imagePath; }*/ /** * Set the instance of the scroll pane which holds the html editor. */ public void setHtmlPane(HtmlPane htmlPane) { this.htmlPane = htmlPane; } /** * Returns the instance of the scroll pane which holds the html editor. */ public HtmlPane getHtmlPane() { return htmlPane; } // A whole bunch of actions which are the functionality of the window /** * */ private class FileOpenAction implements ActionListener { public void actionPerformed(ActionEvent e) { File file; String string; if (fileChooser.showOpenDialog(TrianaHelpFrame.this) == JFileChooser.APPROVE_OPTION) { file = fileChooser.getSelectedFile(); string = "file:" + file.getAbsolutePath(); getHtmlPane().setPage(string); } } } /** * */ private class FileOpenURLAction implements ActionListener { public void actionPerformed(ActionEvent e) { String string = (String) JOptionPane.showInputDialog(TrianaHelpFrame.this, "Enter URL to open", "Open URL...", JOptionPane.QUESTION_MESSAGE, GUIEnv.getTrianaIcon(), null, null); if (string != null) { string.trim(); getHtmlPane().setPage(string); } } } /** * */ private class EditCopyAction implements ActionListener { public void actionPerformed(ActionEvent e) { getHtmlPane().getEditorPane().copy(); } } /** * */ private class EditSelectAllAction implements ActionListener { public void actionPerformed(ActionEvent e) { getHtmlPane().getEditorPane().selectAll(); } } /** * */ private class GoBackAction implements ActionListener { public void actionPerformed(ActionEvent e) { getHtmlPane().goBack(); } } /** * */ private class GoForwardsAction implements ActionListener { public void actionPerformed(ActionEvent e) { getHtmlPane().goForwards(); } } /** * */ private class GoIndexAction implements ActionListener { public void actionPerformed(ActionEvent e) { getHtmlPane().goIndex(); } } /** * */ private class GoHistoryAction implements ActionListener { public void actionPerformed(ActionEvent e) { URL url = historyDialog.showDialog(); if (url != null) { getHtmlPane().setPage(url); } } } public class HelpHelpAction implements ActionListener { public void actionPerformed(ActionEvent e) { try { URL url = this.getClass().getResource("/triana/help/html/index.html"); getHtmlPane().setPage(url); } catch (Exception ex) { System.err.println("Error trying to load index.html from jar file."); ex.printStackTrace(); } } } public class HelpAboutAction implements ActionListener { public void actionPerformed(ActionEvent e) { AboutDialog about = new AboutDialog(TrianaHelpFrame.this); } } /** * A class which listens for a CaretEvent and if a selection has been made it enables the copy menu item and button * on the tool bar. * * @see javax.swing.event.CaretEvent * @see javax.swing.event.CaretListener */ private class SelectionListener implements CaretListener { public void caretUpdate(CaretEvent e) { // Dot is the end of the selection and Mark the start. If they are // the same there isn't a selection. boolean selected = (e.getDot() != e.getMark()); editCopy.setEnabled(selected); copyButton.setEnabled(selected); } } /** * A class which listens for a UrlEvent from the UrlHistory object owned by the HtmlPane. A UrlEvent is a custom * event sent by the UrlHistory class when it is changed in some way. * * @see UrlHistory * @see UrlEvent * @see UrlEventListener */ private class NavigationListener implements UrlEventListener { public void indexChanged(UrlEvent e) { // System.out.println("+++ Catching UrlEvent +++"); // e.getIndex() get the current position within the Url list // e.countUrls() count the total number of Urls in the list int urlIndex = e.getIndex(); boolean backState = (urlIndex > 0); boolean forwardState = (urlIndex < (e.countUrls() - 1)); goBack.setEnabled(backState); backButton.setEnabled(backState); goForwards.setEnabled(forwardState); forwardButton.setEnabled(forwardState); } } // -- Start of CloseFrame methods -- /** * A private class which responds to the close window widget being used by generating a CloseFrameEvent. * * @see CloseFrameEvent */ private class WindowClosingAction extends WindowAdapter { public void windowClosing(WindowEvent e) { processCloseFrameEvent(new CloseFrameEvent(TrianaHelpFrame.this)); } } /** * A private class which is an action which generates a CloseFrameEvent. This is usually used as an ActionListener * for a button or menu item. * * @see CloseFrameEvent */ private class FileCloseAction implements ActionListener { public void actionPerformed(ActionEvent e) { processCloseFrameEvent(new CloseFrameEvent(TrianaHelpFrame.this)); setBounds(properties, "Help.Window"); properties.saveUserSettings(); } } /** * Adds a CloseFrameListener to the Frame * * @param listener The CloseFrameListener to add * @see CloseFrameListener */ public void addCloseFrameListener(CloseFrameListener listener) { closeFrameVector.addElement(listener); } /** * Dispatches a CloseFrameEvent to the CloseFrameListeners registered with the Frame. * * @param event The CloseFrameEvent to dispatch * @see CloseFrameListener * @see CloseFrameEvent */ public void processCloseFrameEvent(CloseFrameEvent event) { CloseFrameListener listener; Enumeration e = closeFrameVector.elements(); while (e.hasMoreElements()) { listener = (CloseFrameListener) e.nextElement(); listener.frameClosing(event); } } // -- End of CloseFrame methods -- }