Visual Color Imbalance Detector: Reconstructed project directories and files
[VistaCID.git] / org / tjworld / components / xhtmlHelp.java
1 /*\r
2         * xhtmlHelp.java\r
3  *\r
4         * Created on 09 November 2001, 16:13\r
5         * $Header: /VisTA/CID/Components/xhtmlHelp.java 7     12/11/01 3:01 Tj $\r
6         *\r
7         * $History: xhtmlHelp.java $\r
8  * \r
9  * *****************  Version 7  *****************\r
10  * User: Tj           Date: 12/11/01   Time: 3:01\r
11  * Updated in $/VisTA/CID/Components\r
12  * Added History List logic to prevent duplicate titles. Added\r
13  * setLookAndFeel(), added L&F resize control logic\r
14  * \r
15  * *****************  Version 6  *****************\r
16  * User: Tj           Date: 11/11/01   Time: 4:10\r
17  * Updated in $/VisTA/CID/Components\r
18  * Added Back, Forward, Refresh functionality. Added Online button.\r
19  * \r
20  * *****************  Version 5  *****************\r
21  * User: Tj           Date: 11/11/01   Time: 0:07\r
22  * Updated in $/VisTA/CID/Components\r
23  * Added setPage(URL) and detection of local help versus external pages\r
24  * (for locale-sensitive page selection)\r
25  * \r
26  * *****************  Version 4  *****************\r
27  * User: Tj           Date: 10/11/01   Time: 2:20\r
28  * Updated in $/VisTA/CID\r
29  * Added alternate <title> or <el id=title> Document Title detection\r
30  * \r
31  * *****************  Version 3  *****************\r
32  * User: Tj           Date: 10/11/01   Time: 1:37\r
33  * Updated in $/VisTA/CID\r
34  * Added: dynamic Locale-sensitive support, window icon, history-combo\r
35  * lists DocTitle, refresh is locale-sensitive\r
36  * \r
37  * *****************  Version 2  *****************\r
38  * User: Tj           Date: 9/11/01    Time: 21:06\r
39  * Updated in $/VisTA/CID\r
40  * Added support for URL History\r
41  */\r
42 package org.tjworld.components;\r
43 \r
44 import java.awt.Color;\r
45 import java.awt.Component;\r
46 import java.awt.Cursor;\r
47 import java.awt.Dimension;\r
48 import java.awt.Point;\r
49 \r
50 import java.io.IOException;\r
51 import java.net.URL;\r
52 import java.util.Locale;\r
53 import java.util.Vector;\r
54 \r
55 import javax.swing.UIManager;\r
56 import javax.swing.JEditorPane;\r
57 import javax.swing.JTree;\r
58 import javax.swing.ComboBoxModel;\r
59 import javax.swing.ImageIcon;\r
60 import javax.swing.SwingUtilities;\r
61 import javax.swing.UIManager;\r
62 import javax.swing.UnsupportedLookAndFeelException;\r
63 import javax.swing.event.DocumentListener;\r
64 import javax.swing.event.DocumentEvent;\r
65 import javax.swing.event.HyperlinkEvent;\r
66 import javax.swing.event.HyperlinkListener;\r
67 import javax.swing.event.TreeSelectionListener;\r
68 import javax.swing.event.TreeSelectionEvent;\r
69 import javax.swing.text.Document;\r
70 import javax.swing.text.html.HTML;\r
71 import javax.swing.text.html.HTMLDocument;\r
72 import javax.swing.text.html.HTMLFrameHyperlinkEvent;\r
73 import javax.swing.tree.TreeModel;\r
74 import javax.swing.tree.TreeSelectionModel;\r
75 import javax.swing.tree.DefaultMutableTreeNode;\r
76 \r
77 import org.tjworld.vista.cid.VistaFilter;\r
78 \r
79 import java.io.InputStream;\r
80 import java.io.IOException;\r
81 import java.net.HttpURLConnection;\r
82 import java.net.URLConnection;\r
83 import javax.swing.text.html.HTMLEditorKit;\r
84         \r
85 \r
86 /**\r
87         * Hopefully entitled xhtml, unfortunately the standard JTextPane models cannot support more than\r
88         * HTML 3.2 or 4.0, depending on the documentation/source code comments.\r
89         *\r
90         * Provides a Locale-sensitive help service with a toolbar and split-pane window.\r
91         * Toolbar provides common browser buttons and a History ComboBox. To the left of the split pane is\r
92         * a Navigation pane with three tabs: Contents, (searchable) Index, and Search (all text).\r
93         * The right pane contains the current help document.\r
94  *\r
95         * @author  TJ\r
96         * @version 1.0 10 Nov, 2001\r
97  */\r
98 public class xhtmlHelp extends javax.swing.JFrame implements HyperlinkListener, TreeSelectionListener {\r
99         private URL helpBase = null;\r
100         private String defaultLanguage = "en";\r
101         private String language = "en";\r
102         private String country = "GB";\r
103         private boolean pageLoaded = false;\r
104         private boolean manualPosition = false;\r
105         private boolean inExtMove = false;\r
106         private boolean docking = false;\r
107 \r
108         /** default glass pane before being replaced by VisTA filter */\r
109         private Component defaultGlassPane;\r
110 \r
111         /** VisTA colourized transparent filter pane */\r
112         private VistaFilter vfFilter;\r
113 \r
114         private String currentPage = null;\r
115         /** frame's small icon */\r
116         private ImageIcon icHelp;\r
117         \r
118         /** Creates new form xhtmlHelp */\r
119  public xhtmlHelp() {\r
120   this((URL)null, (Locale)null, (String)null);\r
121  }\r
122         \r
123         /** Creates a new xhtml with initial HTML page \r
124                 * @param base The URL where the help files are located\r
125                 * @param loc The Locale used by the help system\r
126                 * @param initialPage The first page to display. A simple filename.extension, no path (unless the\r
127                 * path part is relative to the Locale-specfic directory)\r
128                 *\r
129                 * base might be created using: new URL(myAppURL, "help/")\r
130                 */\r
131         public xhtmlHelp(URL base, Locale loc, String initialPage) {\r
132                 /* don't use the Host window decoration if at all possible\r
133                         * Must do this before the frame becomes Displayable\r
134                         * (by a call to pack() or show() )\r
135                         */\r
136                 if(UIManager.getLookAndFeel().getSupportsWindowDecorations()) {\r
137                 setUndecorated(true);  \r
138    getRootPane().setWindowDecorationStyle(javax.swing.JRootPane.FRAME);\r
139          }\r
140 \r
141                 icHelp = new ImageIcon(getClass().getResource("/org/tjworld/components/media/help.gif"));\r
142                 initComponents();\r
143                 contentsTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);\r
144                 indexTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);\r
145                 \r
146   contentsTree.addTreeSelectionListener(this);\r
147   indexTree.addTreeSelectionListener(this);\r
148 \r
149                 lstHistory.setRenderer(new IconTitledURLItemRenderer());\r
150                 \r
151                 if(loc == null) loc = Locale.getDefault();\r
152                 setPageLocale(loc);\r
153                 try {\r
154                  helpBase = base;\r
155                 } catch(Exception e) {\r
156                         helpBase = null;\r
157                 }\r
158                 setPage(initialPage);\r
159                 helpDoc.addHyperlinkListener(this);\r
160         \r
161                 // configure the VisTA filter\r
162                 vfFilter = new VistaFilter();\r
163                 vfFilter.setAlpha(0.5f); // transparency is a decimal between 0.0 and 1.0\r
164                 vfFilter.setBackground(Color.blue);  //*** might want to have this set from saved Personal Preferences later\r
165 \r
166                 // prepare for taking over the Frame's glass pane too\r
167                 defaultGlassPane = getGlassPane(); // keep track so it can be swapped in and out\r
168         setGlassPane(vfFilter); // replace it with the filter\r
169         }\r
170         \r
171         private boolean vistaFilterOn = false;\r
172         \r
173         public boolean isVista() {\r
174                 return vistaFilterOn;\r
175         }\r
176         \r
177         public void setVista(boolean enable) {\r
178                 vistaFilterOn = enable;\r
179                 vfFilter.setVisible(vistaFilterOn);\r
180         }\r
181         \r
182         public void setVistaColour(Color c, float alpha) {\r
183          if(c != null) vfFilter.setBackground(c);\r
184                 vfFilter.setAlpha(alpha);\r
185         }\r
186         \r
187         public Color getVistaColor(Float alpha) {\r
188                 alpha = new Float(vfFilter.getAlpha());\r
189                 return vfFilter.getBackground();\r
190         }\r
191         \r
192         /** Sets the locale to use in displaying help files\r
193                 *\r
194                 * When a page is already loaded, a change of Locale will cause the the new Locale's version\r
195                 * of this page to be loaded, if there is one.\r
196                 *\r
197                 * For example:\r
198                 * If /help/en/default.html is loaded when setPageLocale(Locale.CANADA_FRENCH) is called, \r
199                 * /help/fr/CA/default.html will be looked for first, if not found, then\r
200                 * /help/fr/default.html will be looked for, if not found then\r
201                 * /help/en/default.html will be looked for, where "en" is the default Locale language\r
202                 * @param loc The new currentLocale\r
203                 */\r
204  public void setPageLocale(Locale loc) {\r
205                 if(loc != null) language = loc.getLanguage(); // get the ISO-639 language code, to make a directory name\r
206                 if(loc != null) country = loc.getCountry(); // get the ISO-3166 2-letter coode, to make a directory name\r
207                 if(isPageLoaded())\r
208                         reloadPage();\r
209         }\r
210         \r
211         /** Determine if a page is currently displayed\r
212                 * @returns true if a page is displayed, false otherwise\r
213                 */\r
214  public boolean isPageLoaded() {\r
215                 return pageLoaded;\r
216         }\r
217         \r
218         /** The simple name of the currently displayed page\r
219                 * @returns the simple page name (filename.extension)\r
220                 */\r
221  public String getCurrentPage() {\r
222                 return currentPage;\r
223         }\r
224 \r
225         /** Reloads the current page\r
226                 *\r
227                 * This is quite a clever method, in that if a change of Locale has occurred since the\r
228                 * last setPage() or reloadPage(), the reloaded page will be looked for in the new\r
229                 * current Locale.\r
230                 */\r
231         public boolean reloadPage() {\r
232                 ComboBoxModel model = lstHistory.getModel();\r
233                 return setPage((HelpIconTitledURLItem)model.getSelectedItem());\r
234         }\r
235         \r
236         /**\r
237          * Called when a hypertext link is updated.\r
238                 *\r
239                 * @param e the event responsible for the update\r
240                 */\r
241         public void hyperlinkUpdate(HyperlinkEvent e) {\r
242   if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {\r
243         JEditorPane pane = (JEditorPane) e.getSource();\r
244         if (e instanceof HTMLFrameHyperlinkEvent) {\r
245          HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent)e;\r
246          HTMLDocument doc = (HTMLDocument)pane.getDocument();\r
247          doc.processHTMLFrameHyperlinkEvent(evt);\r
248         } else {\r
249          try {\r
250           setPage(e.getURL());\r
251          } catch (Throwable t) {\r
252           t.printStackTrace();\r
253                 }\r
254         }\r
255   }             \r
256         }                               \r
257 \r
258         javax.swing.text.html.HTMLEditorKit kit = null;\r
259 \r
260         public void createContents(URL htmlContents) throws IOException {\r
261                 InputStream in = getStream(htmlContents);\r
262                 if(kit == null)\r
263                         kit = new HTMLEditorKit();\r
264                 \r
265         }\r
266         \r
267         public void createIndex(URL htmlIndex) {\r
268         }\r
269         \r
270         protected void buildTree(JTree tree, HTMLDocument htmlDoc, HTML.Tag tag, String id) {\r
271         }\r
272         \r
273         protected InputStream getStream(URL page) throws IOException {\r
274          URLConnection conn = page.openConnection();\r
275          if (conn instanceof HttpURLConnection) {\r
276           HttpURLConnection hconn = (HttpURLConnection) conn;\r
277           hconn.setInstanceFollowRedirects(false);\r
278           int response = hconn.getResponseCode();\r
279         }\r
280          InputStream in = conn.getInputStream();\r
281          return in;\r
282         }\r
283                 \r
284         /**\r
285                 * Change the (HTML) document displayed in the help window\r
286                 * The complete URL will be built from:\r
287                 *  (the previously provided) baseURL + "help/" + language + "/" + country + "/" + page\r
288                 * This mechanism allows locale-specific pages to be provided and used transparently.\r
289                 * When a page in the language of the current Locale is not available, the same page\r
290                 * for the default Locale will be looked for instead.\r
291                 *\r
292                 * Help files are use the following directory structure:\r
293                 *\r
294                 * <helpBase> = baseURL + "/help/"\r
295                 * <currentLocale> = <helpBase> + <ISO-639 code> + <ISO-3166 code>\r
296                 *\r
297                 * in other words:\r
298                 * \r
299                 * myapp/help/ (helpBase)\r
300                 * myapp/help/images/ (optional location for common image files)\r
301                 * myapp/help/en/ (English)\r
302                 * myapp/help/en/US/ (English USA)\r
303                 * myapp/help/fr/ (French)\r
304                 * myapp/help/fr/CA (French Canadian}\r
305                 *\r
306                 * Common supporting image and other files can be placed in the helpBase directory and\r
307                 * it's sub-directories. CSS stylesheets can be organised such that global styles are\r
308                 * stored in helpBase, and language-specific styles in the individual Locale directories.\r
309                 * \r
310                 * @param page simple page name (no path)\r
311                 */\r
312         public boolean setPage(String page) {\r
313   URL url = setPageImpl(page);\r
314                 boolean result = url != null ? true : false;\r
315                 \r
316                 if(result == true) { // loading has begun\r
317                         HTMLDocument docType = (HTMLDocument)helpDoc.getStyledDocument();\r
318    Thread getDoc = new waitForDocTitle(page, url, true);\r
319                         getDoc.run(); // wait for it to complete then add the title to the history list\r
320                 }\r
321                 \r
322                 return result;\r
323         }\r
324         \r
325         public boolean setPage(HelpIconTitledURLItem item) {\r
326                 URL url = setPageImpl(item.getFilename());\r
327                 return url != null ? true : false;\r
328         }\r
329         \r
330         public boolean setPage(URL url) {\r
331                 boolean result = false;\r
332                 String base = helpBase.toString();\r
333                 String next = url.toString();\r
334                 \r
335                 if(next.startsWith(base)) { // page is within local help service\r
336                         int pagePos = next.lastIndexOf('/');\r
337                         String page = next.substring(pagePos+1);\r
338                         result = setPage(page);\r
339                 }\r
340                 else { // external page, use full URL\r
341                         System.out.println("External URLs not permitted just now");\r
342                 }\r
343                 return result;\r
344         }\r
345         \r
346         protected URL setPageImpl(String page) {\r
347                 boolean result = false;\r
348                 URL u = null;\r
349 \r
350                 if(helpBase != null && page != null) {\r
351                 try {\r
352                         u = new URL(helpBase, language + "/" + country + "/" + page); // country-sensitive help\r
353                  helpDoc.setPage(u); // load the page (asynchronously)\r
354                                 result = true;\r
355                 } catch(IOException e) { // eeek! Country-specific page not available\r
356     System.err.println("Page Not Found loading " + page + " for " + language + "_" + country);\r
357                 try {\r
358                         u = new URL(helpBase, language + "/" + page); // language-sensitive help\r
359                  helpDoc.setPage(u); // load the page (asynchronously)\r
360                                 result = true;\r
361      System.err.println("Page Found loading " + page + " for " + language);\r
362                 } catch(IOException f) { // eeek! Language-specific page not available\r
363      System.err.println("Page Not Found loading " + page + " for " + language);\r
364                         try { // maybe the default language page is?\r
365                                         u = new URL(helpBase, defaultLanguage + "/" + page); // locale-insensitive help\r
366                   helpDoc.setPage(u); // load the page (asynchronously)\r
367                                         result = true;\r
368       System.err.println("Page Found loading " + page + " for " + defaultLanguage);\r
369                                 } catch(IOException g) { // nope! Page Not Found\r
370       System.err.println("Page Not Found loading " + page);\r
371                                 }\r
372                                 }\r
373           }\r
374                 }\r
375                 if(result == true) { // loading has begun\r
376                         pageLoaded = true; // not strictly true, but the URL was found to be valid\r
377                         currentPage = page;\r
378                 }\r
379                 else\r
380                         u = null;\r
381                 \r
382                 return u;               \r
383         }\r
384         \r
385         /** \r
386                 * Due to the HTML document being loaded asynchronously into the JTextPane helpDoc, the title tag\r
387                 * of the HTML document will not be available immediately for adding to the History list.\r
388                 *\r
389                 * Therefore this monitor class is started in a new Thread. It waits for a TitleProperty to be\r
390                 * available from the JTextPane.styledDocument HTMLDocument.\r
391                 */\r
392         class waitForDocTitle extends Thread {\r
393                 String page;\r
394                 URL url;\r
395                 boolean local;\r
396                 \r
397                 /** Create the monitor\r
398                         * @param page The simple page name (not locale-specific)\r
399                         * @param url The page's URL (locale-specific)\r
400                         * @param local true if the page is part of the help set, false if it's external\r
401                         */\r
402   waitForDocTitle(String page, URL url, boolean local) {\r
403                  this.page = page;\r
404                         this.url = url;\r
405                         this.local = local;\r
406                 }\r
407                 \r
408                 /**\r
409                         * Wait until the TitleProperty of the document has been parsed and added to the StyledDocument's\r
410                         * Property set.\r
411                         */\r
412   public void run() {\r
413                         int count = 0;\r
414                         String docTitle;\r
415                         HTMLDocument html = (HTMLDocument)helpDoc.getStyledDocument();\r
416                         javax.swing.text.Element obj = null;\r
417                         while((docTitle = (String)html.getProperty(Document.TitleProperty)) == null && (obj = html.getElement("title")) == null) {\r
418                                 System.out.println("Waiting");\r
419     try { \r
420                                         sleep(100);\r
421                                 } catch(InterruptedException e) {}\r
422                                 count++; // count how many times the loop has cycled\r
423                                 if(count > 10) break; // don't get stuck in a race condition\r
424                         };\r
425 \r
426                         // at this point docTitle will be null or contain the HTML <title> element contents\r
427                         // there might also be an element with id="title"\r
428                         if(obj != null) { // if so, it is preferred to the <title> element itself\r
429                                 obj = obj.getElement(0); // get it's first child - it had better be plain text else we're scuppered!\r
430                         try {\r
431                          docTitle = obj.getDocument().getText(obj.getStartOffset(),obj.getEndOffset() - obj.getStartOffset());\r
432                          } catch(Exception e) { \r
433                                         System.err.println("Unable to find text contents of HTML Element with id=title");\r
434                          }\r
435                         }\r
436 \r
437                         // check the title isn't already in the History by counting out all the unequal titles\r
438                         int stop = count = lstHistory.getItemCount();\r
439                         String t = null;\r
440                         for(int i = 0; i < stop; i++) { // compare each one\r
441                                 t = ((HelpIconTitledURLItem)lstHistory.getItemAt(i)).getTitle(); // the title from the ComboBox\r
442                                 if(!t.equals(docTitle)) // not a match\r
443                                         --count; // one down\r
444                                 else // found the same title, so select it\r
445                                         lstHistory.setSelectedIndex(i); // show the current doc in the combobox\r
446                         }\r
447                         \r
448                         if(count == 0) { // found a unique title, so add it to the URL History\r
449                                 HelpIconTitledURLItem item = new HelpIconTitledURLItem(docTitle, url, local);\r
450                          lstHistory.addItem(item);\r
451                          lstHistory.setSelectedItem(item); // select it (it's the latest)\r
452                         }\r
453                 }\r
454         }\r
455         \r
456         /** Help Contents tab */\r
457         public static final int TAB_CONTENTS = 1;\r
458         \r
459         /** Help Index tab */\r
460         public static final int TAB_INDEX = 2;\r
461         \r
462         /** Help Search tab */\r
463         public static final int TAB_SEARCH = 3;\r
464         \r
465         /** Set the active navigator tab\r
466                 * @param tabSelect The tab to receive focus\r
467                 */\r
468  public void setNavigationTab(int tabSelect) {\r
469                 if(tabSelect >= 1 && tabSelect <= helpNavigator.getTabCount())\r
470                  helpNavigator.setSelectedIndex(tabSelect-1); // offset by -1 because zero indicates not to change it\r
471         }\r
472         \r
473         public void setNavigationContentsTreeRoot(TreeModel contentsModel) {\r
474                 contentsTree.setModel(contentsModel);\r
475         }\r
476         \r
477         public void setNavigationIndexTreeRoot(TreeModel indexModel) {\r
478                 indexTree.setModel(indexModel);\r
479         }\r
480         \r
481         \r
482  public void setLocation(Point p, Component source) {\r
483                 inExtMove = true;\r
484                 if(!manualPosition) // only relocate if User hasn't previously positioned the window\r
485                         super.setLocation(p);\r
486         }\r
487         \r
488         public void setSize(Dimension d, Component source) {\r
489                 inExtMove = true;\r
490                 if(!manualPosition) // only resize if User hasn't previously positioned the window\r
491                         super.setSize(d);\r
492         }\r
493         \r
494         public void setDocking(boolean dock) {\r
495                 docking = dock;\r
496                 manualPosition = false;\r
497         }\r
498         \r
499         public boolean isDocking() {\r
500                 return docking;\r
501         }\r
502         \r
503  /** This method is called from within the constructor to\r
504   * initialize the form.\r
505   * WARNING: Do NOT modify this code. The content of this method is\r
506   * always regenerated by the Form Editor.\r
507   */\r
508         private void initComponents() {//GEN-BEGIN:initComponents\r
509                 helpToolbar = new javax.swing.JToolBar();\r
510                 btnBack = new javax.swing.JButton();\r
511                 btnForward = new javax.swing.JButton();\r
512                 btnRefresh = new javax.swing.JButton();\r
513                 btnOnline = new javax.swing.JToggleButton();\r
514                 lstHistory = new javax.swing.JComboBox();\r
515                 helpSplitter = new javax.swing.JSplitPane();\r
516                 helpNavigator = new javax.swing.JTabbedPane();\r
517                 contentsScroller = new javax.swing.JScrollPane();\r
518                 contentsTree = new javax.swing.JTree();\r
519                 indexPanel = new javax.swing.JPanel();\r
520                 indexSearchText = new javax.swing.JTextField();\r
521                 indexTree = new javax.swing.JTree();\r
522                 searchPanel = new javax.swing.JPanel();\r
523                 searchCriteriaText = new javax.swing.JTextField();\r
524                 searchResultsList = new javax.swing.JList();\r
525                 helpDocScroller = new javax.swing.JScrollPane();\r
526                 helpDoc = new javax.swing.JTextPane();\r
527                 \r
528                 setTitle("Help");\r
529                 setIconImage(icHelp.getImage());\r
530                 addComponentListener(new java.awt.event.ComponentAdapter() {\r
531                         public void componentMoved(java.awt.event.ComponentEvent evt) {\r
532                                 formComponentMoved(evt);\r
533                         }\r
534                 });\r
535                 \r
536                 btnBack.setText("Back");\r
537                 btnBack.addActionListener(new java.awt.event.ActionListener() {\r
538                         public void actionPerformed(java.awt.event.ActionEvent evt) {\r
539                                 btnBackActionPerformed(evt);\r
540                         }\r
541                 });\r
542                 \r
543                 helpToolbar.add(btnBack);\r
544                 \r
545                 btnForward.setText("Forward");\r
546                 btnForward.addActionListener(new java.awt.event.ActionListener() {\r
547                         public void actionPerformed(java.awt.event.ActionEvent evt) {\r
548                                 btnForwardActionPerformed(evt);\r
549                         }\r
550                 });\r
551                 \r
552                 helpToolbar.add(btnForward);\r
553                 \r
554                 btnRefresh.setText("Refresh");\r
555                 btnRefresh.addActionListener(new java.awt.event.ActionListener() {\r
556                         public void actionPerformed(java.awt.event.ActionEvent evt) {\r
557                                 btnRefreshActionPerformed(evt);\r
558                         }\r
559                 });\r
560                 \r
561                 helpToolbar.add(btnRefresh);\r
562                 \r
563                 btnOnline.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/tjworld/components/media/vistaOnline.gif")));\r
564                 helpToolbar.add(btnOnline);\r
565                 \r
566                 lstHistory.addActionListener(new java.awt.event.ActionListener() {\r
567                         public void actionPerformed(java.awt.event.ActionEvent evt) {\r
568                                 lstHistoryActionPerformed(evt);\r
569                         }\r
570                 });\r
571                 \r
572                 helpToolbar.add(lstHistory);\r
573                 \r
574                 getContentPane().add(helpToolbar, java.awt.BorderLayout.SOUTH);\r
575                 \r
576                 helpSplitter.setDividerLocation(128);\r
577                 helpSplitter.setOneTouchExpandable(true);\r
578                 helpNavigator.setTabLayoutPolicy(javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT);\r
579                 contentsTree.setBorder(new javax.swing.border.EtchedBorder());\r
580                 contentsTree.setName("Contents");\r
581                 contentsTree.setRootVisible(false);\r
582                 contentsTree.setShowsRootHandles(true);\r
583                 contentsScroller.setViewportView(contentsTree);\r
584                 \r
585                 helpNavigator.addTab("", new javax.swing.ImageIcon(getClass().getResource("/org/tjworld/components/media/help.gif")), contentsScroller);\r
586                 \r
587                 indexPanel.setLayout(new java.awt.BorderLayout());\r
588                 \r
589                 indexPanel.add(indexSearchText, java.awt.BorderLayout.NORTH);\r
590                 \r
591                 indexTree.setBorder(new javax.swing.border.EtchedBorder());\r
592                 indexTree.setRootVisible(false);\r
593                 indexTree.setShowsRootHandles(true);\r
594                 indexPanel.add(indexTree, java.awt.BorderLayout.CENTER);\r
595                 \r
596                 helpNavigator.addTab("", new javax.swing.ImageIcon(getClass().getResource("/org/tjworld/components/media/index.gif")), indexPanel);\r
597                 \r
598                 searchPanel.setLayout(new java.awt.BorderLayout());\r
599                 \r
600                 searchPanel.add(searchCriteriaText, java.awt.BorderLayout.NORTH);\r
601                 \r
602                 searchResultsList.setBorder(new javax.swing.border.EtchedBorder());\r
603                 searchPanel.add(searchResultsList, java.awt.BorderLayout.CENTER);\r
604                 \r
605                 helpNavigator.addTab("", new javax.swing.ImageIcon(getClass().getResource("/org/tjworld/components/media/helpsearch.gif")), searchPanel);\r
606                 \r
607                 helpSplitter.setLeftComponent(helpNavigator);\r
608                 \r
609                 helpDoc.setBorder(null);\r
610                 helpDoc.setEditable(false);\r
611                 helpDocScroller.setViewportView(helpDoc);\r
612                 \r
613                 helpSplitter.setRightComponent(helpDocScroller);\r
614                 \r
615                 getContentPane().add(helpSplitter, java.awt.BorderLayout.CENTER);\r
616                 \r
617                 pack();\r
618         }//GEN-END:initComponents\r
619 \r
620         private void btnRefreshActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRefreshActionPerformed\r
621                 reloadPage();\r
622         }//GEN-LAST:event_btnRefreshActionPerformed\r
623 \r
624         private void btnForwardActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnForwardActionPerformed\r
625   int next = lstHistory.getSelectedIndex()+1;\r
626                 if(next < lstHistory.getItemCount()) {\r
627                  HelpIconTitledURLItem item = (HelpIconTitledURLItem)lstHistory.getItemAt(next);\r
628                         if(currentPage != item.getFilename()) { // don't react if the current page was selected\r
629                                 lstHistory.setSelectedIndex(next);\r
630                   setPage(item);\r
631                         }\r
632                 }\r
633         }//GEN-LAST:event_btnForwardActionPerformed\r
634 \r
635         private void btnBackActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnBackActionPerformed\r
636   int last = lstHistory.getSelectedIndex()-1;\r
637                 if(last >= 0) {\r
638                  HelpIconTitledURLItem item = (HelpIconTitledURLItem)lstHistory.getItemAt(last);\r
639                         if(currentPage != item.getFilename()) { // don't react if the current page was selected\r
640                                 lstHistory.setSelectedIndex(last);\r
641                   setPage(item);\r
642                         }\r
643                 }\r
644         }//GEN-LAST:event_btnBackActionPerformed\r
645 \r
646         private void formComponentMoved(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_formComponentMoved\r
647   if(!docking) {\r
648                 if(!inExtMove) manualPosition = true;\r
649                 }\r
650                 inExtMove = false;\r
651         }//GEN-LAST:event_formComponentMoved\r
652 \r
653         private void lstHistoryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_lstHistoryActionPerformed\r
654   HelpIconTitledURLItem item = (HelpIconTitledURLItem)lstHistory.getSelectedItem();\r
655                 if(currentPage != item.getFilename()) // don't react if the current page was selected\r
656                  setPage(item);\r
657         }//GEN-LAST:event_lstHistoryActionPerformed\r
658 \r
659  /** Tree Selection Listener for Content and Index trees.\r
660                 * Doesn't matter whether the source is the Content or Index tree\r
661                 */\r
662  public void valueChanged(TreeSelectionEvent e) {\r
663   DefaultMutableTreeNode node = (DefaultMutableTreeNode)((JTree)e.getSource()).getLastSelectedPathComponent();\r
664                 if (node != null) {\r
665    Object nodeInfo = node.getUserObject();\r
666    if (node.isLeaf() && (nodeInfo instanceof HelpIconTitledURLItem))\r
667     setPage((HelpIconTitledURLItem)nodeInfo);\r
668   }\r
669  }\r
670         \r
671                 /** Choose the Java Look & Feel\r
672                         * @param lf The L&F name\r
673                         */              \r
674  public void setLookAndFeel(String lf) {\r
675   Cursor curCursor = getCursor(); // save the existing cursor\r
676   setCursor(new Cursor(Cursor.WAIT_CURSOR)); // let the user know this might take a while\r
677    \r
678   try { \r
679    UIManager.setLookAndFeel(lf);\r
680                                 \r
681                         // now adjust the frame decoration depending on whether the L&F supports painting it\r
682                         setVisible(false); // hide the frame while the decoration is changed\r
683                         dispose(); // detatch all of the native windowing resources\r
684 \r
685                         if(UIManager.getLookAndFeel().getSupportsWindowDecorations()) {\r
686                 setUndecorated(true);  // don't use the Host window decoration\r
687     getRootPane().setWindowDecorationStyle(javax.swing.JRootPane.FRAME);\r
688                         } else {\r
689                                 setUndecorated(false); // L&F doesn't support decorating the frame\r
690     getRootPane().setWindowDecorationStyle(javax.swing.JRootPane.NONE);\r
691                         }                                       \r
692   } catch(UnsupportedLookAndFeelException e) { // uh-oh, a problem\r
693    try {\r
694     System.err.println("Couldn't switch to " + lf + ", selecting Cross Platform instead");\r
695     UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); // try to recover gracefully\r
696    } catch(Exception g) { // major problem!\r
697     System.err.println("Couldn't return to Cross Platform L&F - eeek!");\r
698                                 g.printStackTrace();\r
699    } \r
700   } catch(Exception f) { // oh pooey, what do I do now?\r
701    System.err.println("Couldn't load " + lf);\r
702                         f.printStackTrace();\r
703   } finally { // do this in any case\r
704    SwingUtilities.updateComponentTreeUI(this); // update the view\r
705                         \r
706    /* one problem is that the JTextPane has long lines of HTML paragraph text which pack()\r
707                                 * allows to extend very wide! So here I take a note of the existing width of the JTextPane\r
708                                 * and explictly set it after pack()\r
709                         */\r
710                 Dimension dim = getSize();\r
711    pack(); // make sure to adjust for potentially altered component sizes\r
712                 setSize(dim);\r
713                         setVisible(true);\r
714   }\r
715    \r
716   setCursor(curCursor);  // restore the cursor\r
717  }\r
718         \r
719  /** Exit the Application \r
720   * @param args the command line arguments\r
721   */\r
722  public static void main(String args[]) {\r
723                 new xhtmlHelp().show();\r
724  }\r
725 \r
726         // Variables declaration - do not modify//GEN-BEGIN:variables\r
727         private javax.swing.JToolBar helpToolbar;\r
728         private javax.swing.JButton btnBack;\r
729         private javax.swing.JButton btnForward;\r
730         private javax.swing.JButton btnRefresh;\r
731         private javax.swing.JToggleButton btnOnline;\r
732         private javax.swing.JComboBox lstHistory;\r
733         private javax.swing.JSplitPane helpSplitter;\r
734         private javax.swing.JTabbedPane helpNavigator;\r
735         private javax.swing.JScrollPane contentsScroller;\r
736         private javax.swing.JTree contentsTree;\r
737         private javax.swing.JPanel indexPanel;\r
738         private javax.swing.JTextField indexSearchText;\r
739         private javax.swing.JTree indexTree;\r
740         private javax.swing.JPanel searchPanel;\r
741         private javax.swing.JTextField searchCriteriaText;\r
742         private javax.swing.JList searchResultsList;\r
743         private javax.swing.JScrollPane helpDocScroller;\r
744         private javax.swing.JTextPane helpDoc;\r
745         // End of variables declaration//GEN-END:variables\r
746 }\r