View Javadoc

1   /*
2    * $Id$
3    *
4    * The contents of this file are subject to the Mozilla Public License 
5    * Version 1.1 (the "License"); you may not use this file except in 
6    * compliance with the License. You may obtain a copy of the License at 
7    * http://www.mozilla.org/MPL/ 
8    *
9    * Software distributed under the License is distributed on an "AS IS" basis, 
10   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
11   * for the specific language governing rights and limitations under the License.
12   *
13   * The Original Code is XML Hammer code. (org.xmlhammer.*)
14   *
15   * The Initial Developer of the Original Code is Edwin Dankert. Portions created 
16   * by the Initial Developer are Copyright (C) 2005 - 2007 the Initial Developer. 
17   * All Rights Reserved.
18   *
19   * Contributor(s): Edwin Dankert <edankert@gmail.com>
20   */
21  
22  package org.xmlhammer.gui.help;
23  
24  import java.awt.BorderLayout;
25  import java.awt.Dimension;
26  import java.awt.FlowLayout;
27  import java.awt.Font;
28  import java.awt.event.ActionEvent;
29  import java.awt.event.ActionListener;
30  import java.awt.event.MouseEvent;
31  import java.net.URISyntaxException;
32  import java.net.URL;
33  
34  import javax.help.DefaultHelpModel;
35  import javax.help.HelpSet;
36  import javax.help.IndexItem;
37  import javax.help.InvalidHelpSetContextException;
38  import javax.help.JHelpContentViewer;
39  import javax.help.JHelpIndexNavigator;
40  import javax.help.JHelpSearchNavigator;
41  import javax.help.JHelpTOCNavigator;
42  import javax.help.Map;
43  import javax.help.SearchTOCItem;
44  import javax.help.TOCItem;
45  import javax.help.TOCView;
46  import javax.help.Map.ID;
47  import javax.help.event.HelpModelEvent;
48  import javax.help.event.HelpModelListener;
49  import javax.help.plaf.basic.BasicContentViewerUI;
50  import javax.help.plaf.basic.BasicSearchCellRenderer;
51  import javax.help.plaf.basic.BasicTOCCellRenderer;
52  import javax.swing.Box;
53  import javax.swing.DefaultButtonModel;
54  import javax.swing.Icon;
55  import javax.swing.ImageIcon;
56  import javax.swing.JButton;
57  import javax.swing.JComponent;
58  import javax.swing.JLabel;
59  import javax.swing.JPanel;
60  import javax.swing.JToolBar;
61  import javax.swing.JTree;
62  import javax.swing.border.EmptyBorder;
63  import javax.swing.border.EtchedBorder;
64  import javax.swing.event.AncestorEvent;
65  import javax.swing.event.AncestorListener;
66  import javax.swing.tree.DefaultMutableTreeNode;
67  import javax.swing.tree.TreePath;
68  
69  import org.apache.log4j.Logger;
70  import org.bounce.CardPanel;
71  import org.bounce.ResizingFlowLayout;
72  import org.bounce.RunnableAction;
73  import org.bounce.event.DoubleClickListener;
74  import org.bounce.image.ImageLoader;
75  import org.xmlhammer.gui.util.ExternalApplicationLauncher;
76  import org.xmlhammer.gui.util.HistoryList;
77  
78  public class HelpPanel extends JPanel {
79      private static final long serialVersionUID = -2000362072449326907L;
80      
81      private static final ImageIcon CLOSE_ICON = ImageLoader.get().getImage("/org/xmlhammer/gui/icons/etool16/close.gif");
82      private static final ImageIcon CLOSE_OVER_ICON = ImageLoader.get().getImage("/org/xmlhammer/gui/icons/etool16/close_over.gif");
83  
84      private static final ImageIcon TOC_LEAF_ICON = ImageLoader.get().getImage("/org/xmlhammer/gui/icons/obj16/searchhit_obj.gif");
85      private static final ImageIcon TOC_TOPIC_ICON = ImageLoader.get().getImage("/org/xmlhammer/gui/icons/obj16/container_obj.gif");
86  
87      private static final ImageIcon ALL_TOPICS_ICON = ImageLoader.get().getImage("/org/xmlhammer/gui/icons/etool16/alltopics_co.gif");
88      private static final ImageIcon SEARCH_ICON = ImageLoader.get().getImage("/org/xmlhammer/gui/icons/etool16/helpsearch_co.gif");
89      private static final ImageIcon HELP_VIEW_ICON = ImageLoader.get().getImage("/org/xmlhammer/gui/icons/view16/help_view.gif");
90      private static final ImageIcon INDEX_ICON = ImageLoader.get().getImage("/org/xmlhammer/gui/icons/etool16/index_co.gif");
91  
92      private HistoryList<HistoryItem> historyList = null;
93  
94      private HelpSet helpset = null;
95  
96      private JHelpContentViewer contextViewer = null;
97      private JHelpContentViewer basicViewer = null;
98      
99      private JHelpSearchNavigator searchNavigator = null;
100     private JHelpTOCNavigator tocNavigator = null;
101     private JHelpIndexNavigator indexNavigator = null;
102 
103     private CardPanel<JComponent> cardPanel = null;
104         
105     private PreviousAction previousAction = null;
106     private NextAction nextAction = null;
107 
108     private JButton closeButton = null;
109 
110     public HelpPanel() {
111         super(new BorderLayout());
112         
113         setMinimumSize(new Dimension(0, 0));
114         historyList = new HistoryList<HistoryItem>();
115         cardPanel = new CardPanel<JComponent>();
116         JToolBar toolbar = new JToolBar();
117         toolbar.setRollover( true);
118         toolbar.setFloatable( false);
119         JLabel label = new JLabel("Help", HELP_VIEW_ICON, JLabel.HORIZONTAL);
120         label.setFont(label.getFont().deriveFont(Font.PLAIN));
121         toolbar.add(label);
122         toolbar.add(Box.createHorizontalGlue());
123 
124         nextAction = new NextAction();
125         previousAction = new PreviousAction();
126         toolbar.add(new HomeAction());
127         toolbar.addSeparator();
128         toolbar.add(previousAction);
129         toolbar.add(nextAction);
130         toolbar.addSeparator();
131         closeButton = toolbar.add(new CloseAction());
132         closeButton.setRolloverIcon(CLOSE_OVER_ICON);
133         
134         HelpSet set = getHelpSet();
135         
136         if (getHelpSet() != null) {
137             try {
138                 contextViewer = new JHelpContentViewer(set);
139                 contextViewer.setUI(new ContentViewerUI(contextViewer));
140                 contextViewer.getModel().addHelpModelListener(new HelpModelListener() {
141                     public void idChanged(HelpModelEvent event) {
142                         putHistory(event.getID(), contextViewer);
143                     }
144                 });
145                 cardPanel.add(contextViewer);
146                 basicViewer = new JHelpContentViewer(set);
147                 basicViewer.setUI(new ContentViewerUI(basicViewer));
148                 basicViewer.getModel().addHelpModelListener(new HelpModelListener() {
149                     public void idChanged(HelpModelEvent event) {
150                         putHistory(event.getID(), basicViewer);
151                     }
152                 });
153                 cardPanel.add(basicViewer);
154                 
155                 searchNavigator = (JHelpSearchNavigator)set.getNavigatorView("Search").createNavigator(new DefaultHelpModel(set));
156                 searchNavigator.updateUI();
157                 JTree tree = getTree(searchNavigator);
158                 tree.setCellRenderer(new BasicSearchCellRenderer(set.getCombinedMap()));
159                 tree.updateUI();
160                 tree.addMouseListener(new DoubleClickListener() {
161                     public void doubleClicked(MouseEvent event) {
162                         TreePath path = ((JTree)event.getSource()).getSelectionPath();
163                         
164                         if (path != null) {
165                             SearchTOCItem item = (SearchTOCItem)((DefaultMutableTreeNode)path.getLastPathComponent()).getUserObject();
166     
167                             ID id = item.getID();
168     
169                             if (item.getID() == null && item.getURL() != null) {
170                                 Map map = getHelpSet().getLocalMap();
171                                 id = map.getClosestID(item.getURL());
172                             }
173                             
174                             if (id != null) {
175                                 putHistory(id, basicViewer);
176                                 historyList.setEnabled(false);
177     
178                                 try {
179                                     basicViewer.setCurrentID(id);
180                                     cardPanel.show(basicViewer);
181                                 } catch (InvalidHelpSetContextException e) {
182                                     Logger.getLogger(getClass()).debug(null, e);
183                                 } finally {
184                                     historyList.setEnabled(true);
185                                 }
186     
187                                 cardPanel.show(basicViewer);
188                             }
189                         }
190                     }
191                 });
192                 cardPanel.add(searchNavigator);
193                 
194                 indexNavigator = (JHelpIndexNavigator)set.getNavigatorView("Index").createNavigator(new DefaultHelpModel(set));
195                 tree = getTree(indexNavigator);
196                 tree.addMouseListener(new DoubleClickListener() {
197                     public void doubleClicked(MouseEvent event) {
198                         TreePath path = ((JTree)event.getSource()).getSelectionPath();
199                         
200                         if (path != null) {
201                             IndexItem item = (IndexItem)((DefaultMutableTreeNode)path.getLastPathComponent()).getUserObject();
202     
203                             ID id = item.getID();
204     
205                             if (item.getID() == null && item.getURL() != null) {
206                                 Map map = getHelpSet().getLocalMap();
207                                 id = map.getClosestID(item.getURL());
208                             }
209                             
210                             if (id != null) {
211                                 putHistory(id, basicViewer);
212                                 historyList.setEnabled(false);
213     
214                                 try {
215                                     basicViewer.setCurrentID(id);
216                                 } catch (InvalidHelpSetContextException e) {
217                                     Logger.getLogger(getClass()).debug(null, e);
218                                 } finally {
219                                     historyList.setEnabled(true);
220                                 }
221     
222                                 cardPanel.show(basicViewer);
223                             }
224                         }
225                     }
226                 });
227                 cardPanel.add(indexNavigator);
228     
229                 tocNavigator = (JHelpTOCNavigator)set.getNavigatorView("TOC").createNavigator(new DefaultHelpModel(set));
230                 tree = getTree(tocNavigator);
231                 tree.setCellRenderer(new TOCCellRenderer(getHelpSet().getCombinedMap()));
232                 tree.addMouseListener(new DoubleClickListener() {
233                     public void doubleClicked(MouseEvent event) {
234                         TreePath path = ((JTree)event.getSource()).getSelectionPath();
235                         
236                         if (path != null) {
237                             TOCItem item = (TOCItem)((DefaultMutableTreeNode)path.getLastPathComponent()).getUserObject();
238     
239                             putHistory(item.getID(), basicViewer);
240                             historyList.setEnabled(false);
241     
242                             try {
243                                 basicViewer.setCurrentID(item.getID());
244                             } catch (InvalidHelpSetContextException e) {
245                                 Logger.getLogger(getClass()).debug(null, e);
246                             } finally {
247                                 historyList.setEnabled(true);
248                             }
249     
250                             cardPanel.show(basicViewer);
251                         }
252                     }
253                 });
254     
255                 cardPanel.add(tocNavigator);
256     
257     //            JTabbedPane tabs = new JTabbedPane();
258     //            tabs.setFont(tabs.getFont().deriveFont(Font.PLAIN));
259                 
260                 JPanel main = new JPanel(new BorderLayout());
261                 main.setBorder(new EmptyBorder(2, 5, 0, 5));
262                 main.add(cardPanel, BorderLayout.CENTER);
263     
264                 JPanel panel = new JPanel(new BorderLayout());
265                 setBorder(new EtchedBorder());
266     //                    new CompoundBorder(
267     //                            new MatteBorder(0, 0, 1, 1, SystemColor.controlDkShadow),
268     //                            new MatteBorder( 1, 1, 0, 0, SystemColor.controlLtHighlight)));
269     
270                 panel.add(main, BorderLayout.CENTER);
271                 
272                 JPanel buttonPanel = new JPanel();
273                 buttonPanel.setLayout(new ResizingFlowLayout(FlowLayout.LEFT));
274                 
275                 buttonPanel.setBorder(new EmptyBorder(5, 0, 5, 0));
276                 JButton tocButton = new JButton("TOC", ALL_TOPICS_ICON);
277                 tocButton.addActionListener(new ActionListener() {
278                     public void actionPerformed(ActionEvent event) {
279                         showTOC();
280                     }
281                 });
282                 tocButton.setFont(tocButton.getFont().deriveFont(Font.PLAIN));
283                 
284                 buttonPanel.add(tocButton);
285                 JButton searchButton = new JButton("Search", SEARCH_ICON);
286                 searchButton.addActionListener(new ActionListener() {
287                     public void actionPerformed(ActionEvent event) {
288                         showSearch();
289                     }
290                 });
291                 searchButton.setFont(searchButton.getFont().deriveFont(Font.PLAIN));
292                 buttonPanel.add(searchButton);
293     
294                 JButton indexButton = new JButton("Index", INDEX_ICON);
295                 indexButton.addActionListener(new ActionListener() {
296                     public void actionPerformed(ActionEvent event) {
297                         showIndex();
298                     }
299                 });
300                 indexButton.setFont(indexButton.getFont().deriveFont(Font.PLAIN));
301                 buttonPanel.add(indexButton);
302                 panel.add(buttonPanel, BorderLayout.SOUTH);
303                 main.add(toolbar, BorderLayout.NORTH);
304                 
305     //            tabs.addTab("Help", HELP_VIEW_ICON, panel);
306                 
307                 add(panel, BorderLayout.CENTER);
308     
309                 historyList.reset();
310     
311                 // Set the initial item.
312                 putHistory(null, cardPanel.selected());
313             } catch (Exception e) {
314                 Logger.getLogger(getClass()).debug(null, e);
315             }
316         }
317         
318         this.addAncestorListener(new AncestorListener() {
319             public void ancestorAdded(AncestorEvent event) {}
320 
321             public void ancestorMoved(AncestorEvent event) {}
322 
323             public void ancestorRemoved(AncestorEvent event) {
324                 ((DefaultButtonModel)closeButton.getModel()).setRollover(false);
325             }
326         });
327     }
328     
329     public void showID(String id) {
330         showID(id, false);
331     }
332 
333     public void addCloseActionListener(ActionListener listener) {
334         closeButton.addActionListener(listener);
335     }
336 
337     public void removeCloseActionListener(ActionListener listener) {
338         closeButton.removeActionListener(listener);
339     }
340 
341     public void showContext() {
342         if (!contextViewer.isVisible()) {
343             putHistory(contextViewer.getModel().getCurrentID(), contextViewer);
344             cardPanel.show(contextViewer);
345         }
346     }
347     
348     public void showContents() {
349         Map.ID id = getHelpSet().getHomeID();
350 
351         if (basicViewer.getModel().getCurrentID() == null || !basicViewer.getModel().getCurrentID().equals(id)) {
352             putHistory(id, basicViewer);
353             historyList.setEnabled(false);
354 
355             try {
356                 basicViewer.setCurrentID(id);
357             } catch (InvalidHelpSetContextException e) {
358                 Logger.getLogger(getClass()).debug(null, e);
359             } finally {
360                 historyList.setEnabled(true);
361             }
362         }
363         
364         cardPanel.show(basicViewer);
365     }
366     
367     public void showQuickStart() {
368         Map.ID id = Map.ID.create("quick-start", getHelpSet());
369 
370         if (basicViewer.getModel().getCurrentID() == null || !basicViewer.getModel().getCurrentID().equals(id)) {
371             putHistory(id, basicViewer);
372             historyList.setEnabled(false);
373 
374             try {
375                 basicViewer.setCurrentID(id);
376             } catch (InvalidHelpSetContextException e) {
377                 Logger.getLogger(getClass()).debug(null, e);
378             } finally {
379                 historyList.setEnabled(true);
380             }
381         }
382         
383         cardPanel.show(basicViewer);
384     }
385 
386     public void showSearch() {
387         if (cardPanel.selected() != searchNavigator) {
388             putHistory(null, searchNavigator);
389             cardPanel.show(searchNavigator);
390         }
391     }
392     
393     public void showIndex() {
394         if (cardPanel.selected() != indexNavigator) {
395             putHistory(null, indexNavigator);
396             cardPanel.show(indexNavigator);
397         }
398     }
399     
400     public void showTOC() {
401         if (cardPanel.selected() != tocNavigator) {
402             putHistory(null, tocNavigator);
403             cardPanel.show(tocNavigator);
404         }
405     }
406 
407     public void show(HistoryItem item) {
408         cardPanel.show(item.getCard());
409         historyList.setEnabled(false);
410 
411         try {
412             if (item.getCard() == contextViewer) {
413                 contextViewer.setCurrentID(item.getID());
414             } else if (item.getCard() == basicViewer) {
415                 basicViewer.setCurrentID(item.getID());
416             }
417         } catch (InvalidHelpSetContextException e) {
418             Logger.getLogger(getClass()).debug(null, e);
419         } finally {
420             historyList.setEnabled(true);
421         }
422     }
423 
424     private void updateActions() {
425         previousAction.setEnabled(historyList.hasPrevious());
426         nextAction.setEnabled(historyList.hasNext());
427     }
428 
429     /***
430      * @param id the id for the 
431      * @param showViewer
432      */
433     public void showID(String idString, boolean showViewer) {
434         ID id = Map.ID.create(idString, getHelpSet());
435         
436         if (contextViewer != null) {
437             try {
438                 historyList.setEnabled(false);
439                 contextViewer.setCurrentID(id);
440             
441                 if (contextViewer.isVisible() && contextViewer.getModel().getCurrentID().equals(id)) {
442                     putHistory(id, contextViewer);
443                 }
444                 
445                 if (showViewer) {
446                     showContext();
447                 }
448             } catch (InvalidHelpSetContextException e) {
449                 Logger.getLogger(getClass()).debug("Cannot set ID", e);
450             } finally {
451                 historyList.setEnabled(true);
452             }
453         }
454     }
455         
456     private HelpSet getHelpSet() {
457         if (helpset == null) {
458             try {
459                 URL url = getClass().getResource("/help/jhelpset.hs"); 
460                 
461                 Logger.getLogger(getClass()).debug("HelpSet URL: " + url);
462 
463                 if (url != null) {
464                     helpset = new HelpSet(getClass().getClassLoader(), url);
465                 }
466             } catch (Exception e) {
467                 Logger.getLogger(getClass()).debug(null, e);
468             }
469         }
470 
471         return helpset;
472     }
473     
474     private JTree getTree(JComponent comp) {
475         JTree tree = null;
476 
477         if (comp instanceof JTree) {
478             tree = (JTree)comp;
479         }
480         
481         for (int i = 0; i < comp.getComponentCount() && tree == null; i++) {
482             if (comp.getComponent(i) instanceof JComponent) {
483                 tree = getTree((JComponent)comp.getComponent(i));
484             }
485         }
486         
487         return tree;
488     }
489     
490     private void putHistory(ID id, JComponent card) {
491         if (card != null && id != null) {
492             historyList.put(new HistoryItem(id, card));
493             updateActions();
494         }
495     }
496     
497     private class HistoryItem {
498         private ID id = null;
499         private JComponent card = null;
500         
501         public HistoryItem(ID id, JComponent card) {
502             this.id = id;
503             this.card = card;
504         }
505         
506         public ID getID() {
507             return id;
508         }
509         
510         public JComponent getCard() {
511             return card;
512         }
513         
514         public String toString() {
515             return "["+card.getClass().getName()+"] "+id;
516         }
517     }
518     
519     private class NextAction extends RunnableAction {
520         private static final long serialVersionUID = 3258134648029526321L;
521 
522         public NextAction() {
523             super("Next");
524 
525             putValue(SHORT_DESCRIPTION, "Next Help Item");
526             putValue(SMALL_ICON, new ImageIcon( getClass().getResource( "/org/xmlhammer/gui/icons/elcl16/forward_nav.gif")));
527         }
528 
529         public void run() {
530             show(historyList.next());
531             updateActions();
532         }
533     }
534 
535     private class PreviousAction extends RunnableAction {
536         private static final long serialVersionUID = 3258134648029526321L;
537 
538         public PreviousAction() {
539             super("Previous");
540 
541             putValue(SHORT_DESCRIPTION, "Next Help Item");
542             putValue(SMALL_ICON, new ImageIcon( getClass().getResource( "/org/xmlhammer/gui/icons/elcl16/backward_nav.gif")));
543         }
544 
545         public void run() {
546             show(historyList.previous());
547             updateActions();
548         }
549     }
550     
551     private class HomeAction extends RunnableAction {
552         private static final long serialVersionUID = 3258134648029526321L;
553 
554         public HomeAction() {
555             super("Home");
556 
557             putValue(SHORT_DESCRIPTION, "Index Page");
558             putValue(SMALL_ICON, new ImageIcon( getClass().getResource( "/org/xmlhammer/gui/icons/elcl16/home_nav.gif")));
559         }
560 
561         public void run() {
562             showContents();
563         }
564     }
565 
566     private class CloseAction extends RunnableAction {
567         private static final long serialVersionUID = 3258134648029526321L;
568 
569         public CloseAction() {
570             super("Close");
571 
572             putValue(SHORT_DESCRIPTION, "Close Help View");
573             putValue(SMALL_ICON, CLOSE_ICON);
574         }
575 
576         public void run() {
577             // handled by external action listeners ...
578         }
579     }
580 
581     private class TOCCellRenderer extends BasicTOCCellRenderer {
582         private static final long serialVersionUID = 6850877407883209757L;
583 
584         public TOCCellRenderer(Map map1, TOCView tocview) {
585             super(map1, tocview);
586         }
587 
588         public TOCCellRenderer(Map map1) {
589             super(map1);
590         }
591 
592         public Icon getLeafIcon() {
593             return TOC_LEAF_ICON;
594         }
595 
596         public Icon getOpenIcon() {
597             return TOC_TOPIC_ICON;
598         }
599         
600         public Icon getClosedIcon() {
601             return TOC_TOPIC_ICON;
602         }
603     }
604     
605     private class ContentViewerUI extends BasicContentViewerUI {
606         private static final long serialVersionUID = 535503569665566378L;
607 
608         public ContentViewerUI(JHelpContentViewer jhelpcontentviewer) {
609             super(jhelpcontentviewer);
610         }
611         
612         protected void linkActivated(URL url) {
613             Logger.getLogger(getClass()).debug("linkActivated("+url+")");
614             if (url.getProtocol().equals("http")) {
615                 try {
616                     ExternalApplicationLauncher.getInstance().browse(url.toURI());
617                 } catch (URISyntaxException e) {
618                     e.printStackTrace();
619                 }
620             } else {
621                 super.linkActivated(url);
622             }
623         }
624     }
625 }