/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: ManualViewer.java
*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.tool.user.help;
import com.sun.electric.Main;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.tool.Client;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.io.FileType;
import com.sun.electric.tool.user.ActivityLogger;
import com.sun.electric.tool.user.Resources;
import com.sun.electric.tool.user.dialogs.EDialog;
import com.sun.electric.tool.user.dialogs.EModelessDialog;
import com.sun.electric.tool.user.dialogs.OpenFile;
import com.sun.electric.tool.user.menus.EMenu;
import com.sun.electric.tool.user.menus.EMenuBar;
import com.sun.electric.tool.user.menus.EMenuItem;
import com.sun.electric.tool.user.ui.WindowFrame;
import com.sun.electric.util.TextUtils;
import com.sun.electric.util.config.Configuration;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.HTMLFrameHyperlinkEvent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
/**
* A Dialog for displaying the Electric users manual.
*
* The html files in the user's manual have special lines that control them:
* <!-- HEADER 1-2: Chapter Title -->
* <!-- COMMAND Menu/Command -->
* <!-- PREFERENCE Section/Panel -->
* <!-- PROJECTSETTING Panel -->
* <!-- NEED 2in -->
* <!-- TRAILER -->
*/
public class ManualViewer extends EModelessDialog
{
private static final String RUSSIANMANUALPATH = "plugins/manualRussian";
/** the menus that are not checked */
public static Set<String> excludeMenu = new HashSet<String>();
static
{
excludeMenu.add("Sun");
excludeMenu.add("Test");
excludeMenu.add("Steve");
excludeMenu.add("Felix");
excludeMenu.add("JonG");
excludeMenu.add("Gilda");
excludeMenu.add("Dima");
excludeMenu.add("Dinesh");
excludeMenu.add("Frankie");
excludeMenu.add("Adam");
}
private static class PageInfo
{
String title;
String fileName;
String chapterName;
String fullChapterNumber;
String outerChapterTitle;
int chapterNumber;
int sectionNumber;
URL url;
int level;
boolean newAtLevel;
};
private Class<?> htmlBaseClass;
private String htmlDirectory;
private JScrollPane rightHalf;
private JEditorPane editorPane;
private JSplitPane splitPane;
private JTextField searchField;
private JTree manualTree;
private DefaultMutableTreeNode rootNode;
private List<PageInfo> pageSequence;
private List<DefaultMutableTreeNode> pageNodeSequence;
private int currentIndex;
private boolean menubarShown = false;
private static int lastPageVisited = 0;
private static HashMap<String,String> menuMap = null;
private static HashMap<String,String> keywordMap = null;
private List<Object> history = new ArrayList<Object>();
private static ManualViewer theManual = null;
private static void setManualViewer(String preference, Class<?> baseClass, String htmlDir, boolean setVisible)
{
if (theManual == null)
{
JFrame jf = null;
jf = (JFrame) Main.getCurrentJFrame();
try{
theManual = new ManualViewer(jf, preference, baseClass, htmlDir);
}
catch (Exception e)
{
System.out.println("Error creating the ManualViewer");
theManual = null;
}
}
if (theManual != null && setVisible)
theManual.setVisible(true);
}
/**
* Method to display the user's manual.
*/
public static void userManualCommand()
{
setManualViewer(null, ManualViewer.class, "helphtml", true);
}
/**
* Method to tell whether there is a Russian user's manual installed.
* @return true if the Russian user's manual is available.
*/
public static boolean hasRussianManual()
{
URL url = Main.class.getResource(RUSSIANMANUALPATH + "/toc.txt");
return url != null;
}
/**
* Method to display the Russian user's manual.
*/
public static void userManualRussianCommand()
{
setManualViewer(null, Main.class, RUSSIANMANUALPATH, true);
}
/**
* Method to show the help page for a particular panel in the "Preferences" dialog.
* @param preference the panel name, of the form "section/panel".
* For example, the "CIF" panel in the "I/O" section will be named "I/O/CIF".
*/
public static void showPreferenceHelp(String preference)
{
showSettingHelp("PREF", preference);
}
/**
* Internal method to show Preferences help.
* @param str the help page requested.
*/
private static void showSettingHelp(String dialog, String str)
{
setManualViewer(dialog+str, ManualViewer.class, "helphtml", false);
if (theManual == null)
return; // error
if (str != null)
{
String prefFileName = keywordMap.get(dialog+str);
if (prefFileName == null)
{
Job.getUserInterface().showErrorMessage("No help for " + str + " settings", "Missing documentation");
} else
{
for(int i=0; i<theManual.pageSequence.size(); i++)
{
PageInfo pi = theManual.pageSequence.get(i);
if (pi.fileName.equals(prefFileName))
{
theManual.loadPage(i, null);
break;
}
}
}
}
theManual.setVisible(true);
}
/**
* Method to open the 2D view of a given layout cell
* @param fileName name of the library where the cell is stored
* @param cellName cell name
* @param menuName name of the menu executing this command
*/
public static Cell open2DSample(String fileName, String cellName, String menuName)
{
Library library = Library.findLibrary(fileName);
if (library == null)
{
System.out.println("Load first the library '" + fileName +
"' (Help -> " + menuName + " -> Load Library)");
return null;
}
Cell cell = library.findNodeProto(cellName);
if (cell == null)
{
System.out.println("Cell '" + cellName + "' not found");
return null;
}
// Open the window frame if not available
if (cell != WindowFrame.getCurrentCell())
WindowFrame.createEditWindow(cell);
return cell;
}
/**
* Method to open the 3D view of a given layout cell
* @param fileName name of the library where the cell is stored
* @param cellName cell name
*/
public static void open3DSample(String fileName, String cellName, String menuName)
{
Cell cell = open2DSample(fileName, cellName, menuName);
if (cell == null) return; // error opening the 2D view
// Making sure all cell instances are expanded
for (Iterator<NodeInst> it = cell.getNodes(); it.hasNext();)
{
NodeInst ni = it.next();
ni.setExpanded(true);
}
// to guarantee the redisplay with extended
Class<?> plugin3D = Resources.get3DClass("ui.J3DMenu");
if (plugin3D != null)
{
// Adding 3D/Demo menu
try {
Method createMethod = plugin3D.getDeclaredMethod("create3DViewCommand", new Class[] {Boolean.class});
createMethod.invoke(plugin3D, new Object[] {Boolean.FALSE});
} catch (Exception e)
{
System.out.println("Can't open 3D view: " + e.getMessage());
ActivityLogger.logException(e);
}
}
}
/**
* Method to animate the 3D view of current layout cell
* @param demoName name of j3d file containing the demo
*/
public static void animate3DSample(String demoName)
{
String fileName = "helphtml/" + demoName;
URL url = ManualViewer.class.getResource(fileName);
if (url == null)
{
System.out.println("Can't open 3D demo file '" + fileName + "'");
return;
}
Class<?> plugin3D = Resources.get3DClass("ui.J3DDemoDialog");
if (plugin3D != null)
{
// Adding 3D/Demo menu
try {
Method createMethod = plugin3D.getDeclaredMethod("create3DDemoDialog",
new Class[] {java.awt.Frame.class, URL.class});
createMethod.invoke(plugin3D, new Object[] {Main.getCurrentJFrame(), url});
} catch (Exception e)
{
System.out.println("Can't open 3D demo dialog: " + e.getMessage());
ActivityLogger.logException(e);
}
}
}
private static boolean j3DAvailable;
private static boolean j3DChecked = false;
public static boolean isJava3DAvailable()
{
// Checking first if j3d is installed
if (!j3DChecked)
{
j3DChecked = true;
j3DAvailable = Resources.get3DClass("utils.J3DUtils") != null;
}
return j3DAvailable;
}
/**
* Create a new user's manual dialog.
* @param parent
*/
private ManualViewer(Frame parent, String preference, Class<?> baseClass, String htmlDir) throws Exception
{
super(parent);
htmlBaseClass = baseClass;
htmlDirectory = htmlDir;
pageSequence = new ArrayList<PageInfo>();
pageNodeSequence = new ArrayList<DefaultMutableTreeNode>();
setTitle("User's Manual");
init();
// load indices
loadPointers();
String prefFileName = null;
if (preference != null)
{
prefFileName = keywordMap.get(preference);
if (prefFileName == null)
Job.getUserInterface().showErrorMessage("No help for " + preference + " settings", "Missing documentation");
}
// load the table of contents
String indexName = htmlDirectory + "/toc.txt";
URL url = htmlBaseClass.getResource(indexName);
InputStream stream = TextUtils.getURLStream(url, null);
if (stream == null)
{
String msg = "Can't open " + indexName + " in " + htmlBaseClass.getPackage();
Job.getUserInterface().showErrorMessage(msg, "Missing documentation");
System.out.println(msg);
return;
}
InputStreamReader is = new InputStreamReader(stream);
DefaultMutableTreeNode [] stack = new DefaultMutableTreeNode[20];
stack[0] = rootNode;
boolean newAtLevel = false;
String chapterName = null;
int chapterNumber = 0;
int [] sectionNumbers = new int[5];
sectionNumbers[0] = -1;
currentIndex = lastPageVisited;
DefaultMutableTreeNode thisNode = null;
String outerTitle = "";
for(;;)
{
String line = getLine(is);
if (line == null) break;
if (line.length() == 0) continue;
int indent = 0;
for(;;)
{
if (indent >= line.length() || line.charAt(indent) != ' ') break;
indent++;
}
int titleStart = indent;
int titleEnd = line.indexOf('=', titleStart);
String fileName = null;
if (titleEnd < 0) titleEnd = line.length();
else
fileName = line.substring(titleEnd+1).trim();
String title = line.substring(titleStart, titleEnd).trim();
if (fileName == null)
{
if (indent == 0)
{
chapterNumber++;
chapterName = chapterNumber + ": " + title;
}
sectionNumbers[indent]++;
stack[indent+1] = new DefaultMutableTreeNode(sectionNumbers[indent] + ": " + title);
stack[indent].add(stack[indent+1]);
sectionNumbers[indent+1] = 0;
newAtLevel = true;
outerTitle = title;
} else
{
PageInfo pi = new PageInfo();
pi.fileName = fileName;
pi.title = title;
pi.chapterName = chapterName;
pi.chapterNumber = chapterNumber;
pi.outerChapterTitle = outerTitle;
pi.sectionNumber = ++sectionNumbers[indent];
pi.fullChapterNumber = "";
for(int i=0; i<indent; i++)
{
pi.fullChapterNumber += sectionNumbers[i] + "-";
}
pi.fullChapterNumber += sectionNumbers[indent];
pi.level = indent;
pi.newAtLevel = newAtLevel;
pi.url = htmlBaseClass.getResource(htmlDirectory + "/" + fileName + ".html");
if (pi.url == null)
System.out.println("NULL URL to "+fileName);
DefaultMutableTreeNode node = new DefaultMutableTreeNode(new Integer(pageSequence.size()));
if (preference != null && pi.fileName.equals(prefFileName))
{
currentIndex = pageSequence.size();
thisNode = node;
}
stack[indent].add(node);
pageSequence.add(pi);
pageNodeSequence.add(node);
newAtLevel = false;
}
}
try
{
stream.close();
} catch (IOException e)
{
System.out.println("Error closing file");
}
// No preference page given
if (preference == null || thisNode != null)
{
// pre-expand the tree
TreePath topPath = manualTree.getPathForRow(0);
manualTree.expandPath(topPath);
topPath = manualTree.getPathForRow(1);
manualTree.expandPath(topPath);
manualTree.setSelectionPath(topPath);
// } else
// {
// TreePath tp = new TreePath(thisNode.getPath());
// manualTree.scrollPathToVisible(tp);
// manualTree.setSelectionPath(tp);
}
// load the title page of the manual
loadPage(currentIndex, null);
finishInitialization();
}
/**
* Method to show the menu bar in the manual dialog.
*/
private void loadMenuBar()
{
if (menubarShown) return;
menubarShown = true;
JMenuBar helpMenuBar = new JMenuBar();
// convert menuBar to tree
Main top = (Main) Main.getCurrentJFrame();
EMenuBar menuBar = top.getEMenuBar();
for (EMenuItem menu: menuBar.getItems())
{
JMenu helpMenu = new JMenu(menu.getText());
helpMenuBar.add(helpMenu);
addMenu((EMenu)menu, helpMenu, menu.getText() + "/");
}
setJMenuBar(helpMenuBar);
pack();
ensureProperSize();
StringBuffer sb = new StringBuffer();
sb.append("<CENTER><H1>HELP MENU ENABLED</H1></CENTER>\n");
sb.append("The menu bar at the top of <I>this</I> window looks the same as the main menu bar in Electric.<BR><BR>\n");
sb.append("Use any entry in this menu bar to see the manual page that explains that menu entry.\n");
editorPane.setText(sb.toString());
editorPane.setCaretPosition(0);
}
/**
* Method to examine the online manual and extract pointers to commands and preferences.
*/
private void loadPointers()
{
// stop if already done
if (keywordMap != null) return;
menuMap = new HashMap<String,String>();
HashMap<String,String> menuMapCheck = null;
keywordMap = new HashMap<String,String>();
if (Job.getDebug())
{
menuMapCheck = new HashMap<String,String>();
}
// scan all manual entries for menu associations
String indexName = htmlDirectory + "/toc.txt";
URL url = htmlBaseClass.getResource(indexName);
InputStream stream = TextUtils.getURLStream(url, null);
if (stream == null)
{
System.out.println("Can't open " + indexName + " in " + htmlBaseClass.getPackage());
return;
}
InputStreamReader is = new InputStreamReader(stream);
for(;;)
{
String line = getLine(is);
if (line == null) break;
if (line.length() == 0) continue;
int indent = 0;
for(;;)
{
if (indent >= line.length() || line.charAt(indent) != ' ') break;
indent++;
}
int titleStart = indent;
int titleEnd = line.indexOf('=', titleStart);
if (titleEnd < 0) continue;
String fileName = line.substring(titleEnd+1).trim();
URL pageURL = htmlBaseClass.getResource(htmlDirectory + "/" + fileName + ".html");
if (pageURL == null)
{
System.out.println("NULL URL to "+fileName);
continue;
}
InputStream pageStream = TextUtils.getURLStream(pageURL, null);
InputStreamReader pageIS = new InputStreamReader(pageStream);
for(;;)
{
String pageLine = getLine(pageIS);
if (pageLine == null) break;
if (pageLine.startsWith("<!-- COMMAND "))
{
int endPt = pageLine.indexOf("-->");
if (endPt < 0)
{
System.out.println("No end comment on line: "+pageLine);
continue;
}
String commandName = pageLine.substring(13, endPt).trim();
for(;;)
{
int backslashPos = commandName.indexOf('\\');
if (backslashPos < 0) break;
commandName = commandName.substring(0, backslashPos) + commandName.substring(backslashPos+1);
}
String already = menuMap.get(commandName);
if (already != null && Job.getDebug())
{
System.out.println("ERROR: command " + commandName + " is keyed to both " + already + " and " + fileName);
}
menuMap.put(commandName, fileName);
if (menuMapCheck != null) menuMapCheck.put(commandName, fileName);
continue;
}
if (pageLine.startsWith("<!-- PREFERENCE "))
{
int endPt = pageLine.indexOf("-->");
if (endPt < 0)
{
System.out.println("No end comment on line: "+pageLine);
continue;
}
String preferenceName = "PREF" + pageLine.substring(16, endPt).trim();
String already = keywordMap.get(preferenceName);
if (already != null && Job.getDebug())
{
System.out.println("ERROR: command " + preferenceName + " is keyed to both " + already + " and " + fileName);
}
keywordMap.put(preferenceName, fileName);
continue;
}
if (pageLine.startsWith("<!-- PROJECTSETTING "))
{
int endPt = pageLine.indexOf("-->");
if (endPt < 0)
{
System.out.println("No end comment on line: "+pageLine);
continue;
}
String projSettingName = "PROJ" + pageLine.substring(20, endPt).trim();
String already = keywordMap.get(projSettingName);
if (already != null && Job.getDebug())
{
System.out.println("ERROR: command " + projSettingName + " is keyed to both " + already + " and " + fileName);
}
keywordMap.put(projSettingName, fileName);
continue;
}
}
try
{
pageStream.close();
} catch (IOException e)
{
System.out.println("Error closing file");
}
}
if (menuMapCheck != null)
{
Main top = (Main) Main.getCurrentJFrame();
EMenuBar menuBar = top.getEMenuBar();
for (EMenuItem menu: menuBar.getItems())
{
if (Job.getDebug() && excludeMenu.contains(menu.getText())) continue;
checkMenu((EMenu)menu, menu.getText() + "/", menuMapCheck);
}
for(String commandName : menuMapCheck.keySet())
{
String fileName = menuMapCheck.get(commandName);
if (Client.isOSWindows() || Client.isOSMac())
{
if (commandName.indexOf("Remember Location of Display") >= 0) continue;
if (commandName.indexOf("Move to Other Display") >= 0) continue;
}
System.out.println("Command " + commandName + " was mentioned in file " + fileName + " but does not exist");
}
menuMapCheck = null;
}
}
private void checkMenu(EMenu menu, String cumulative, HashMap<String,String> menuMapCheck)
{
for (EMenuItem menuItem: menu.getItems())
{
if (menuItem == EMenuItem.SEPARATOR) continue;
if (menuItem instanceof EMenu)
{
EMenu subMenu = (EMenu)menuItem;
checkMenu(subMenu, cumulative + subMenu.getText() + "/", menuMapCheck);
} else
{
String commandName = cumulative + menuItem.getText();
String fileName = menuMap.get(commandName);
if (fileName == null && Job.getDebug())
{
boolean specialCommand = false;
if (commandName.indexOf("Dais") >= 0) specialCommand = true;
if (commandName.indexOf("Skill") >= 0) specialCommand = true;
if (commandName.indexOf("TSMC") >= 0) specialCommand = true;
if (commandName.indexOf("CMOS90") >= 0) specialCommand = true;
if (commandName.indexOf("Sun Lava") >= 0) specialCommand = true;
if (commandName.indexOf("Sun Lava") >= 0) specialCommand = true;
if (!specialCommand) System.out.println("No help for " + commandName);
} else
{
if (menuMapCheck != null) menuMapCheck.remove(commandName);
}
}
}
}
private void addMenu(EMenu menu, JMenu helpMenu, String cumulative)
{
for (EMenuItem menuItem: menu.getItems())
{
if (menuItem == EMenuItem.SEPARATOR)
{
helpMenu.addSeparator();
continue;
}
if (menuItem instanceof EMenu)
{
EMenu subMenu = (EMenu)menuItem;
JMenu helpSubMenu = new JMenu(subMenu.getText());
helpMenu.add(helpSubMenu);
addMenu(subMenu, helpSubMenu, cumulative + subMenu.getText() + "/");
} else
{
JMenuItem helpMenuItem = new JMenuItem(menuItem.getText());
helpMenu.add(helpMenuItem);
String commandName = cumulative + menuItem.getText();
String fileName = menuMap.get(commandName);
helpMenuItem.addActionListener(new HelpMenuActionListener(this, fileName));
}
}
}
private static class HelpMenuActionListener implements ActionListener
{
private ManualViewer dialog;
private String title;
HelpMenuActionListener(ManualViewer dialog, String title)
{
this.dialog = dialog;
this.title = title;
}
public void actionPerformed(ActionEvent e) { doHelpMenu(title); }
private void doHelpMenu(String fileName)
{
if (fileName == null)
{
System.out.println("No help for this command");
return;
}
for(int i=0; i<dialog.pageSequence.size(); i++)
{
PageInfo pi = dialog.pageSequence.get(i);
if (pi.fileName.equals(fileName))
{
dialog.loadPage(i, null);
return;
}
}
}
}
private String getLine(InputStreamReader is)
{
StringBuffer sb = new StringBuffer();
for(;;)
{
int ch = -1;
try
{
ch = is.read();
} catch (IOException e) {}
if (ch == -1) return null;
if (ch == '\n' || ch == '\r') break;
sb.append((char)ch);
}
return sb.toString();
}
private void loadPage(int index, String highlightThis)
{
// add to browsing history
history.add(new Integer(index));
currentIndex = index;
lastPageVisited = index;
PageInfo pi = pageSequence.get(index);
if (pi.url == null) return; // error reading the html file
DefaultMutableTreeNode node = pageNodeSequence.get(index);
EDialog.recursivelyHighlight(manualTree, rootNode, node, manualTree.getPathForRow(0));
InputStream stream = TextUtils.getURLStream(pi.url, null);
InputStreamReader is;
try {
is = new InputStreamReader(stream, "UTF-8");
} catch (UnsupportedEncodingException e) {
System.out.println("UTF-8 is UnsupportedEncodingException");
return;
}
StringBuffer sb = new StringBuffer();
// setup for search
Pattern pattern = null;
if (highlightThis != null) pattern = Pattern.compile(highlightThis, Pattern.CASE_INSENSITIVE);
// emit header HTML
sb.append("<BASE href=\"" + pi.url.toString() + "\">");
int lastIndex = index - 1;
if (lastIndex < 0) lastIndex = pageSequence.size() - 1;
PageInfo lastPi = pageSequence.get(lastIndex);
String lastFileName = lastPi.fileName;
int nextIndex = index + 1;
if (nextIndex >= pageSequence.size()) nextIndex = 0;
PageInfo nextPi = pageSequence.get(nextIndex);
String nextFileName = nextPi.fileName;
boolean pageFound = false;
for(;;)
{
String line = getLine(is);
if (line == null) break;
if (line.startsWith("<!-- HEADER "))
{
int endPt = line.indexOf("-->");
if (endPt < 0)
{
System.out.println("No end comment on line: "+line);
continue;
}
String pageName = line.substring(12, endPt).trim();
setTitle(pageName + " - Electric Manual");
pageFound = true;
sb.append("<HTML><HEAD><TITLE>Using Electric " + pageName + "\"</TITLE></HEAD>\n");
sb.append("<BODY>\n");
sb.append("<CENTER><TABLE WIDTH=\"90%\" BORDER=0><TR>\n");
sb.append("<TD><CENTER><A HREF=\"" + lastFileName + ".html#" + lastFileName +
".html\"><IMG SRC=\"iconplug.png\" ALT=\"plug\" BORDER=0></A></CENTER></TD>\n");
sb.append("<TD><CENTER><H1>" + pageName + "</H1></CENTER></TD>\n");
sb.append("<TD><CENTER><A HREF=\"" + nextFileName + ".html#" + nextFileName +
".html\"><IMG SRC=\"iconplug.png\" ALT=\"plug\" BORDER=0></A></CENTER></TD></TR></TABLE></CENTER>\n");
sb.append("<HR>\n");
sb.append("<BR>\n");
continue;
}
if (line.equals("<!-- TRAILER -->"))
{
sb.append("</BODY>\n");
sb.append("</HTML>\n");
continue;
}
if (pattern != null)
{
StringBuffer oneLine = new StringBuffer();
Matcher matcher = pattern.matcher(line);
while (matcher.find())
matcher.appendReplacement(oneLine, "<FONT style=\"BACKGROUND-COLOR: red\">$0</FONT>");
matcher.appendTail(oneLine);
line = oneLine.toString();
}
sb.append(line);
sb.append("\n");
}
try
{
stream.close();
} catch (IOException e)
{
System.out.println("Error closing file");
}
editorPane.setText(sb.toString());
editorPane.setCaretPosition(0);
if (!pageFound) setTitle("Electric Manual");
}
/**
* Method to go to the previous page that was viewed.
*/
private void back()
{
int len = history.size();
if (len <= 1) return;
Object lastPage = history.get(len-2);
history.remove(len-1);
if (lastPage instanceof Integer)
{
history.remove(len-2);
Integer lpi = (Integer)lastPage;
loadPage(lpi.intValue(), null);
return;
}
if (lastPage instanceof String)
{
editorPane.setText((String)lastPage);
editorPane.setCaretPosition(0);
}
}
/**
* Method to go to the previous page in the manual.
*/
private void prev()
{
int index = currentIndex - 1;
if (index < 0) index = pageSequence.size() - 1;
loadPage(index, null);
}
/**
* Method to go to the next page in the manual.
*/
private void next()
{
int index = currentIndex + 1;
if (index >= pageSequence.size()) index = 0;
loadPage(index, null);
}
private void search()
{
String ret = searchField.getText().trim();
if (ret.length() == 0) return;
Pattern pattern = Pattern.compile(ret, Pattern.CASE_INSENSITIVE);
StringBuffer sbResult = new StringBuffer();
sbResult.append("<CENTER><H1>Search Results for \"" + ret + "\"</H1></CENTER>\n");
int numFound = 0;
for(int index=0; index < pageSequence.size(); index++)
{
PageInfo pi = pageSequence.get(index);
InputStream stream = TextUtils.getURLStream(pi.url, null);
InputStreamReader is = new InputStreamReader(stream);
StringBuffer sb = new StringBuffer();
for(;;)
{
String line = getLine(is);
if (line == null) break;
if (line.length() == 0) continue;
if (line.equals("<!-- TRAILER -->")) continue;
if (line.startsWith("<!-- COMMAND ")) continue;
if (line.startsWith("<!-- NEED ")) continue;
if (line.startsWith("<!-- HEADER ")) line = line.substring(12);
sb.append(line);
}
Matcher matcher = pattern.matcher(sb.toString());
if (!matcher.find()) continue;
sbResult.append("<B><A HREF=\"" + pi.fileName + ".html##" + ret + "\">" + pi.fullChapterNumber + ": " + pi.title + "</A></B><BR>\n");
numFound++;
}
sbResult.append("<P><B>Found " + numFound + " entries</B>\n");
String wholePage = sbResult.toString();
history.add(wholePage);
editorPane.setText(wholePage);
editorPane.setCaretPosition(0);
}
/**
* Method to generate a 1-page HTML file with the entire manual.
* This is an advanced function that is not available to users.
* The purpose of the single-file HTML is to generate an acrobat file (pdf).
*/
private void manual1Page()
{
String manualFileName = OpenFile.chooseOutputFile(FileType.HTML, "Manual file", "electric.html");
if (manualFileName == null) return;
PrintWriter printWriter = null;
try
{
printWriter = new PrintWriter(new BufferedWriter(new FileWriter(manualFileName)));
} catch (IOException e)
{
System.out.println("Error creating " + manualFileName);
return;
}
Set<String> usedFiles = new HashSet<String>();
for(int index=0; index < pageSequence.size(); index++)
{
PageInfo pi = pageSequence.get(index);
usedFiles.add(pi.fileName + ".html");
InputStream stream = TextUtils.getURLStream(pi.url, null);
InputStreamReader is = new InputStreamReader(stream);
int lastIndex = index - 1;
if (lastIndex < 0) lastIndex = pageSequence.size() - 1;
PageInfo lastPi = pageSequence.get(lastIndex);
for(;;)
{
String line = getLine(is);
if (line == null) break;
if (line.length() == 0) continue;
if (line.startsWith("<!-- HEADER "))
{
int endPt = line.indexOf("-->");
if (endPt < 0)
{
System.out.println("No end comment on line: "+line);
continue;
}
String pageName = line.substring(12, endPt).trim();
boolean newSection = false;
if (pi.level < 2 || pi.newAtLevel)
{
newSection = true;
if (pi.chapterNumber > 0 && lastPi.chapterNumber < pi.chapterNumber)
{
printWriter.println("<CENTER><H1>Chapter " + pi.chapterName + "</H1></CENTER>");
} else
{
printWriter.println("<!-- PAGE BREAK -->");
}
int colonPos = pageName.indexOf(':');
if (colonPos > 0)
{
int numDashes = 0;
for(int i=0; i<colonPos; i++)
if (pageName.charAt(i) == '-') numDashes++;
if (numDashes > 1)
{
newSection = false;
int firstDash = pageName.indexOf('-');
int secondDash = pageName.indexOf('-', firstDash+1);
String prefix = pageName.substring(0, secondDash) + ": ";
printWriter.println("<CENTER><H2>" + prefix + pi.outerChapterTitle + "</H2></CENTER>");
printWriter.println("<HR>");
printWriter.println("<BR>");
}
}
}
if (newSection)
{
printWriter.println("<CENTER><H2>" + pageName + "</H2></CENTER>");
printWriter.println("<HR>");
printWriter.println("<BR>");
} else
{
printWriter.println("<H3>" + pageName + "</H3>");
}
continue;
}
if (line.equals("<!-- TRAILER -->")) continue;
printWriter.println(line);
// look for "SRC=" image references
int imgPos = line.indexOf("SRC=\"");
if (imgPos >= 0)
{
int startPos = line.indexOf('"', imgPos);
if (startPos > 0)
{
int endPos = line.indexOf('"', startPos+1);
if (endPos > startPos)
{
String imgFile = line.substring(startPos+1, endPos);
usedFiles.add(imgFile);
}
}
}
// look for "HREF=" hyperlink references
int refPos = line.indexOf("HREF=\"");
if (refPos >= 0)
{
int startPos = line.indexOf('"', refPos);
if (startPos > 0)
{
int endPos1 = line.indexOf('"', startPos+1);
if (endPos1 < 0) endPos1 = line.length();
int endPos2 = line.indexOf('#', startPos+1);
if (endPos2 < 0) endPos2 = line.length();
int endPos = Math.min(endPos1, endPos2);
if (endPos > startPos)
{
String htmlFile = line.substring(startPos+1, endPos);
if (!htmlFile.startsWith("http://") && !htmlFile.startsWith("mailto:"))
usedFiles.add(htmlFile);
}
}
}
}
}
printWriter.println("</BODY>");
printWriter.println("</HTML>");
printWriter.close();
// report on extraneous files and missing files
usedFiles.add("toc.txt");
usedFiles.add("iconbackarrow.png");
usedFiles.add("iconforearrow.png");
usedFiles.add("iconcontarrow.png");
usedFiles.add("samples.jelib");
usedFiles.add("floatingGates.jelib");
usedFiles.add("demoCage.j3d");
String classPath = htmlBaseClass.getPackage().getName() + "." + htmlDirectory;
List<String> manFiles = TextUtils.getAllResources(classPath);
for(String s : manFiles)
{
if (usedFiles.contains(s)) continue;
System.out.println("File " + s + " is not used");
}
for(String s : usedFiles)
{
if (manFiles.contains(s)) continue;
System.out.println("File " + s + " is missing");
}
}
/**
* Method to generate a multi-page HTML files with the entire manual.
* This is an advanced function that is not available to users.
* The output is a single "index" file, and many chapter files that start with the letter "m"
* (i.e. "mchap01-01.html").
* If you copy the "index.html", all of the "mchap" files, and all of the image files,
* it will be a complete manual.
*/
private void manualManyPages()
{
String manualFileName = OpenFile.chooseOutputFile(FileType.HTML, "Manual file", "index.html");
if (manualFileName == null) return;
PrintWriter printWriter = null;
try
{
printWriter = new PrintWriter(new BufferedWriter(new FileWriter(manualFileName)));
} catch (IOException e)
{
System.out.println("Error creating " + manualFileName);
return;
}
System.out.println("Writing 'index.html' and many files starting with 'mchap'");
// gather the table of contents by chapter
int lastChapterNumber = 0;
StringBuffer chapterText = new StringBuffer();
List<String> chapters = new ArrayList<String>();
StringBuffer afterTOC = new StringBuffer();
for(int index=0; index < pageSequence.size(); index++)
{
PageInfo pi = pageSequence.get(index);
if (pi.chapterNumber <= 0)
{
InputStream stream = TextUtils.getURLStream(pi.url, null);
InputStreamReader is = new InputStreamReader(stream);
for(;;)
{
String line = getLine(is);
if (line == null) break;
if (line.length() == 0) continue;
if (line.startsWith("<!-- HEADER ")) continue;
if (line.startsWith("<!-- TRAILER ")) continue;
if (line.equals("<HR>")) break;
printWriter.println(line);
}
for(;;)
{
String line = getLine(is);
if (line == null) break;
if (line.length() == 0) continue;
if (line.startsWith("<!-- HEADER ")) continue;
if (line.startsWith("<!-- TRAILER ")) continue;
afterTOC.append(line);
}
try
{
is.close();
} catch (IOException e) {}
continue;
}
if (pi.chapterNumber != lastChapterNumber)
{
if (lastChapterNumber > 0) chapters.add(chapterText.toString());
lastChapterNumber = pi.chapterNumber;
chapterText = new StringBuffer();
chapterText.append("<B>Chapter " + pi.chapterName.toUpperCase() + "</B><BR>");
}
chapterText.append("<A HREF=\"m" + pi.fileName + ".html\">" + pi.fullChapterNumber + ": " + pi.title + "</A><BR>");
}
chapters.add(chapterText.toString());
// write the table of contents
printWriter.println("<CENTER><H1>Table of Contents</H1></CENTER>");
printWriter.println("<CENTER><TABLE BORDER=\"1\">");
for(int i=0; i<chapters.size(); i += 2)
{
String leftSide = chapters.get(i);
String rightSide = "";
if (i+1 < chapters.size()) rightSide = chapters.get(i+1);
printWriter.println("<TR><TD VALIGN=TOP>" + leftSide + "</TD>");
printWriter.println("<TD VALIGN=TOP>" + rightSide + "</TD></TR>");
}
printWriter.println("</TABLE></CENTER><HR>");
printWriter.print(afterTOC.toString());
printWriter.println("<CENTER><TABLE BORDER=\"0\"><TR>");
printWriter.println("<TD><A HREF=\"mchap01-01.html\">Next</A></TD>");
printWriter.println("<TD><A HREF=\"mchap01-01.html\"><IMG SRC=\"iconforearrow.png\" ALT=\"Next\" BORDER=\"0\"></A></TD>");
printWriter.println("</TR></TABLE></CENTER>");
printWriter.println("</BODY>");
printWriter.println("</HTML>");
printWriter.close();
for(int index=0; index < pageSequence.size(); index++)
{
PageInfo pi = pageSequence.get(index);
if (pi.chapterNumber <= 0) continue;
InputStream stream = TextUtils.getURLStream(pi.url, null);
InputStreamReader is = new InputStreamReader(stream);
String pageFileName = manualFileName;
int lastSep = pageFileName.lastIndexOf('\\');
if (lastSep >= 0) pageFileName = pageFileName.substring(0, lastSep+1);
pageFileName += "m" + pi.fileName + ".html";
try
{
printWriter = new PrintWriter(new BufferedWriter(new FileWriter(pageFileName)));
} catch (IOException e)
{
System.out.println("Error creating " + pageFileName);
break;
}
printWriter.println("<HTML><HEAD>");
printWriter.println("<TITLE>Electric VLSI Design System User's Manual</TITLE></HEAD>");
printWriter.println("<BODY BGCOLOR=\"#FFFFFF\">");
int lastIndex = index - 1;
if (lastIndex < 0) lastIndex = pageSequence.size() - 1;
PageInfo lastPi = pageSequence.get(lastIndex);
String lastFileName = lastPi.fileName;
if (lastFileName.equals("title")) lastFileName = "index"; else lastFileName = "m" + lastFileName;
int nextIndex = index + 1;
if (nextIndex >= pageSequence.size()) nextIndex = 0;
PageInfo nextPi = pageSequence.get(nextIndex);
String nextFileName = nextPi.fileName;
if (nextFileName.equals("title")) nextFileName = "index"; else nextFileName = "m" + nextFileName;
for(;;)
{
String line = getLine(is);
if (line == null) break;
if (line.length() == 0) continue;
if (line.startsWith("<!-- NEED ")) continue;
if (line.startsWith("<!-- HEADER "))
{
int endPt = line.indexOf("-->");
if (endPt < 0)
{
System.out.println("No end comment on line: "+line);
continue;
}
String pageName = line.substring(12, endPt).trim();
// if this is at level 3 or deeper, prepend level 2 title
String intermediateTitle = null;
int colonPos = pageName.indexOf(':');
if (colonPos > 0)
{
int numDashes = 0;
for(int i=0; i<colonPos; i++)
if (pageName.charAt(i) == '-') numDashes++;
if (numDashes > 1)
{
int firstDash = pageName.indexOf('-');
int secondDash = pageName.indexOf('-', firstDash+1);
String prefix = pageName.substring(0, secondDash) + ": ";
intermediateTitle = prefix + pi.outerChapterTitle;
}
}
printWriter.println("<A NAME=\"" + pi.fileName + "\"></A>");
printWriter.println("<CENTER><FONT SIZE=6><B>Chapter " + pi.chapterName + "</B></FONT></CENTER>");
printWriter.println("<CENTER><TABLE WIDTH=\"90%\" BORDER=0><TR>");
printWriter.println("<TD><CENTER><A HREF=\"" + lastFileName + ".html#" + lastFileName +
".html\"><IMG SRC=\"iconplug.png\" ALT=\"plug\" BORDER=0></A></CENTER></TD>");
if (intermediateTitle == null)
{
printWriter.println("<TD><CENTER><FONT SIZE=5><B>" + pageName + "</B></FONT></CENTER></TD>");
} else
{
printWriter.println("<TD><CENTER><FONT SIZE=5><B>" + intermediateTitle + "</B></FONT><BR>");
printWriter.println("<FONT SIZE=4><B>" + pageName + "</B></FONT></CENTER></TD>");
}
printWriter.println("<TD><CENTER><A HREF=\"" + nextFileName + ".html#" + nextFileName +
".html\"><IMG SRC=\"iconplug.png\" ALT=\"plug\" BORDER=0></A></CENTER></TD></TR></TABLE></CENTER>");
printWriter.println("<HR>");
printWriter.println("<BR>");
continue;
}
if (line.equals("<!-- TRAILER -->"))
{
printWriter.println("<P>");
printWriter.println("<HR>");
printWriter.println("<CENTER><TABLE BORDER=0><TR>");
printWriter.println("<TD><A HREF=\"" + lastFileName + ".html#" + lastFileName +".html\"><IMG SRC=\"iconbackarrow.png\" ALT=\"Prev\" BORDER=0></A></TD>");
printWriter.println("<TD><A HREF=\"" + lastFileName + ".html#" + lastFileName +".html\">Previous</A></TD>");
printWriter.println("<TD> </TD>");
printWriter.println("<TD><A HREF=\"index.html\"><IMG SRC=\"iconcontarrow.png\" ALT=\"Contents\" BORDER=0></A></TD>");
printWriter.println("<TD><A HREF=\"index.html\">Table of Contents</A></TD>");
printWriter.println("<TD> </TD>");
printWriter.println("<TD><A HREF=\"" + nextFileName + ".html#" + nextFileName +".html\">Next</A></TD>");
printWriter.println("<TD><A HREF=\"" + nextFileName + ".html#" + nextFileName +".html\"><IMG SRC=\"iconforearrow.png\" ALT=\"Next\" BORDER=0></A></TD>");
printWriter.println("</TR></TABLE></CENTER>");
continue;
}
// convert references to other chapters
for(;;)
{
int x = line.indexOf("\"chap");
if (x >= 0)
{
line = line.substring(0, x+1) + "m" + line.substring(x+1);
continue;
}
x = line.indexOf("#chap");
if (x >= 0)
{
line = line.substring(0, x+1) + "m" + line.substring(x+1);
continue;
}
break;
}
// write the line
printWriter.println(line);
}
printWriter.println("</BODY>");
printWriter.println("</HTML>");
printWriter.close();
}
}
/**
* Method to edit the current page in the manual.
* This is an advanced function that is not available to users.
*/
private void edit()
{
PageInfo pi = pageSequence.get(currentIndex);
JFrame jf = null;
jf = (JFrame) Main.getCurrentJFrame();
EditHTML dialog = new EditHTML(jf, pi.url, this);
dialog.setVisible(true);
}
public static class EditHTML extends EModelessDialog
{
private static final long serialVersionUID = 1L;
private JTextArea textArea;
private URL file;
private ManualViewer world;
private EditHTML(Frame parent, URL file, ManualViewer world)
{
super(parent);
this.file = file;
this.world = world;
getContentPane().setLayout(new GridBagLayout());
setTitle("Edit HTML");
setName("");
Dimension maxScreenSize = Toolkit.getDefaultToolkit().getScreenSize();
setPreferredSize(new Dimension(maxScreenSize.width/2, maxScreenSize.height/2));
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent evt) { closeDialog(evt); }
});
textArea = new JTextArea();
textArea.getDocument().putProperty( DefaultEditorKit.EndOfLineStringProperty, System.getProperty("line.separator") );
JScrollPane scrollPane = new JScrollPane(textArea);
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.weightx = 1;
gridBagConstraints.weighty = 1;
gridBagConstraints.anchor = GridBagConstraints.CENTER;
gridBagConstraints.fill = GridBagConstraints.BOTH;
gridBagConstraints.insets = new Insets(4, 4, 4, 4);
getContentPane().add(scrollPane, gridBagConstraints);
try
{
URLConnection con = file.openConnection();
InputStream stream = con.getInputStream();
InputStreamReader is = new InputStreamReader(stream);
LineNumberReader ln = new LineNumberReader(is);
StringBuffer sb = new StringBuffer();
for(;;)
{
String aLine = ln.readLine();
if (aLine == null) break;
sb.append(aLine);
sb.append('\n');
}
ln.close();
textArea.setText(sb.toString());
textArea.setSelectionStart(0);
textArea.setSelectionEnd(0);
} catch (IOException e)
{
System.out.println("Could not find file: " + file.getFile());
return;
}
pack();
}
private void closeDialog(WindowEvent evt)
{
String fileName = file.getFile();
try
{
PrintWriter printWriter = new PrintWriter(new BufferedWriter(new FileWriter(fileName)));
printWriter.print(textArea.getText());
printWriter.close();
} catch (IOException e)
{
System.out.println("Could not save file: " + fileName);
return;
}
/*
* Because some IDEs keep class files in a separate directory,
* the file that is being displayed is only a cache of the real one.
* The real one is missing the "/bin/" part.
*/
int binPos = fileName.indexOf("/bin/");
if (binPos >= 0)
{
String otherFileName = fileName.substring(0, binPos) + "/srcj" + fileName.substring(binPos+4);
try
{
PrintWriter printWriter = new PrintWriter(new BufferedWriter(new FileWriter(otherFileName)));
printWriter.print(textArea.getText());
printWriter.close();
System.out.println("Also saved to "+otherFileName);
} catch (IOException e)
{
System.out.println("Could not also save file: " + otherFileName);
System.out.println(" but did save: " + fileName);
return;
}
} else
{
// another way to find the original file (using Maven file structures)
binPos = fileName.indexOf("/target/classes/");
if (binPos >= 0)
{
String otherFileName = fileName.substring(0, binPos) + "/src/main/resources" + fileName.substring(binPos+15);
try
{
PrintWriter printWriter = new PrintWriter(new BufferedWriter(new FileWriter(otherFileName)));
printWriter.print(textArea.getText());
printWriter.close();
System.out.println("Also saved to "+otherFileName);
} catch (IOException e)
{
System.out.println("Could not also save file: " + otherFileName);
System.out.println(" but did save: " + fileName);
return;
}
}
}
setVisible(false);
dispose();
world.loadPage(world.currentIndex, null);
}
}
private static class Hyperactive implements HyperlinkListener
{
private ManualViewer dialog;
Hyperactive(ManualViewer dialog) { this.dialog = dialog; }
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
{
URL desiredURL = e.getURL();
// first see if it is one of the manual files, in which case it gets auto-generated
String desiredFile = desiredURL.getFile();
String searchString = desiredURL.getRef();
if (searchString != null && searchString.startsWith("#")) searchString = searchString.substring(1); else
searchString = null;
for(int i=0; i<dialog.pageSequence.size(); i++)
{
PageInfo pi = dialog.pageSequence.get(i);
if (pi.url.getFile().equals(desiredFile))
{
dialog.loadPage(i, searchString);
return;
}
}
// external URL: fetch it
try
{
pane.setPage(desiredURL);
} catch (Throwable t)
{
System.out.println("Cannot find URL "+e.getURL());
}
}
}
}
}
/**
* Initialize list of all ToolTips and initialize components
*/
private void init()
{
// set up dialog
GridBagConstraints gbc;
getContentPane().setLayout(new GridBagLayout());
// setup tree pane for chapter selection (on the left)
rootNode = new DefaultMutableTreeNode("Manual");
DefaultTreeModel treeModel = new DefaultTreeModel(rootNode);
manualTree = new ManualTree(treeModel, this);
TreeHandler handler = new TreeHandler(this);
manualTree.addMouseListener(handler);
JScrollPane scrolledTree = new JScrollPane(manualTree);
// the left side of the options dialog: a tree
JPanel leftHalf = new JPanel();
leftHalf.setLayout(new GridBagLayout());
gbc = new GridBagConstraints();
gbc.gridx = 0; gbc.gridy = 4;
gbc.gridwidth = 2; gbc.gridheight = 1;
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1.0; gbc.weighty = 1.0;
gbc.insets = new Insets(0, 4, 4, 4);
leftHalf.add(scrolledTree, gbc);
// forward and backward buttons
JButton backButton = new JButton("Back");
gbc = new GridBagConstraints();
gbc.gridx = 0; gbc.gridy = 0;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.insets = new Insets(4, 4, 4, 4);
gbc.anchor = GridBagConstraints.CENTER;
leftHalf.add(backButton, gbc);
backButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt) { back(); }
});
JButton menuButton = new JButton("Menu Help");
gbc = new GridBagConstraints();
gbc.gridx = 0; gbc.gridy = 1;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.insets = new Insets(4, 4, 4, 4);
gbc.anchor = GridBagConstraints.CENTER;
leftHalf.add(menuButton, gbc);
menuButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt) { loadMenuBar(); }
});
// Previous and Next buttons
JButton nextButton = new JButton("Next");
gbc = new GridBagConstraints();
gbc.gridx = 1; gbc.gridy = 0;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.insets = new Insets(4, 4, 4, 4);
gbc.anchor = GridBagConstraints.CENTER;
leftHalf.add(nextButton, gbc);
nextButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt) { next(); }
});
JButton prevButton = new JButton("Prev");
gbc = new GridBagConstraints();
gbc.gridx = 1; gbc.gridy = 1;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.insets = new Insets(4, 4, 4, 4);
gbc.anchor = GridBagConstraints.CENTER;
leftHalf.add(prevButton, gbc);
prevButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt) { prev(); }
});
JSeparator sep = new JSeparator();
gbc = new GridBagConstraints();
gbc.gridx = 0; gbc.gridy = 2;
gbc.gridwidth = 2; gbc.gridheight = 1;
gbc.anchor = GridBagConstraints.CENTER;
gbc.fill = GridBagConstraints.HORIZONTAL;
leftHalf.add(sep, gbc);
// forward and backward buttons at the bottom of the left side
searchField = new JTextField();
gbc = new GridBagConstraints();
gbc.gridx = 0; gbc.gridy = 3;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.insets = new Insets(4, 4, 4, 4);
gbc.weightx = 0.5;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.CENTER;
leftHalf.add(searchField, gbc);
JButton searchButton = new JButton("Find");
gbc = new GridBagConstraints();
gbc.gridx = 1; gbc.gridy = 3;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.insets = new Insets(4, 4, 4, 4);
gbc.anchor = GridBagConstraints.CENTER;
leftHalf.add(searchButton, gbc);
searchButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt) { search(); }
});
getRootPane().setDefaultButton(searchButton);
if (Job.getDebug())
{
// manual and edit buttons at the bottom of the left side
JButton manualButton = new JButton("1-Page Man");
gbc = new GridBagConstraints();
gbc.gridx = 1; gbc.gridy = 5;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.insets = new Insets(0, 4, 4, 4);
gbc.anchor = GridBagConstraints.CENTER;
leftHalf.add(manualButton, gbc);
manualButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt) { manual1Page(); }
});
// manual and edit buttons at the bottom of the left side
JButton manualMultiButton = new JButton("Many-Page Man");
gbc = new GridBagConstraints();
gbc.gridx = 0; gbc.gridy = 5;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.insets = new Insets(0, 4, 4, 4);
gbc.anchor = GridBagConstraints.CENTER;
leftHalf.add(manualMultiButton, gbc);
manualMultiButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt) { manualManyPages(); }
});
JButton editButton = new JButton("Edit Page");
gbc = new GridBagConstraints();
gbc.gridx = 0; gbc.gridy = 6;
gbc.gridwidth = 2; gbc.gridheight = 1;
gbc.insets = new Insets(0, 4, 4, 4);
leftHalf.add(editButton, gbc);
editButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt) { edit(); }
});
}
// set up scroll pane for manual (on the right)
editorPane = new JEditorPane();
editorPane.setEditorKit(new HTMLEditorKit());
editorPane.addHyperlinkListener(new Hyperactive(this));
editorPane.setEditable(false);
rightHalf = new JScrollPane(editorPane);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
rightHalf.setPreferredSize(new Dimension(screenSize.width/2, screenSize.height*3/4));
rightHalf.setMinimumSize(new Dimension(screenSize.width/4, screenSize.height/3));
// build split pane with both halves
splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
splitPane.setLeftComponent(leftHalf);
splitPane.setRightComponent(rightHalf);
splitPane.setDividerLocation(200);
gbc = new GridBagConstraints();
gbc.gridx = 0; gbc.gridy = 0;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1.0; gbc.weighty = 1.0;
getContentPane().add(splitPane, gbc);
// close of dialog event
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent evt) { closeDialog(evt); }
});
pack();
}
private static class ManualTree extends JTree
{
private static final long serialVersionUID = 1L;
private ManualViewer dialog;
private ManualTree(DefaultTreeModel treeModel, ManualViewer dialog)
{
super(treeModel);
this.dialog = dialog;
// single selection as default
getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
// do not show top-level
setRootVisible(true);
setShowsRootHandles(true);
}
public String convertValueToText(Object value, boolean selected, boolean expanded, boolean leaf,
int row, boolean hasFocus)
{
Object nodeInfo = ((DefaultMutableTreeNode)value).getUserObject();
if (nodeInfo instanceof Integer)
{
Integer index = (Integer)nodeInfo;
PageInfo pi = dialog.pageSequence.get(index.intValue());
String ret = pi.title;
if (pi.sectionNumber > 0) ret = pi.sectionNumber + ": " + ret;
return ret;
}
return nodeInfo.toString();
}
}
private static class TreeHandler implements MouseListener
{
private ManualViewer dialog;
TreeHandler(ManualViewer dialog) { this.dialog = dialog; }
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mousePressed(MouseEvent e)
{
TreePath currentPath = dialog.manualTree.getPathForLocation(e.getX(), e.getY());
if (currentPath == null) return;
dialog.manualTree.expandPath(currentPath);
dialog.manualTree.setSelectionPath(currentPath);
DefaultMutableTreeNode node = (DefaultMutableTreeNode)currentPath.getLastPathComponent();
Object obj = node.getUserObject();
if (obj instanceof Integer)
{
int index = ((Integer)obj).intValue();
dialog.loadPage(index, null);
}
}
}
private void closeDialog(WindowEvent evt)
{
setVisible(false);
dispose();
theManual = null;
}
}