1 /* 2 * @(#)HelpSet.java 1.108 06/10/30 3 * 4 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. 5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 * 7 * This code is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 only, as 9 * published by the Free Software Foundation. Sun designates this 10 * particular file as subject to the "Classpath" exception as provided 11 * by Sun in the LICENSE file that accompanied this code. 12 * 13 * This code is distributed in the hope that it will be useful, but WITHOUT 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 * version 2 for more details (a copy is included in the LICENSE file that 17 * accompanied this code). 18 * 19 * You should have received a copy of the GNU General Public License version 20 * 2 along with this work; if not, write to the Free Software Foundation, 21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 24 * CA 95054 USA or visit www.sun.com if you need additional information or 25 * have any questions. 26 */ 27 28 package javax.help; 29 30 import java.net.URL; 31 import java.net.URLConnection; 32 import java.net.MalformedURLException; 33 import java.util.*; 34 import java.io.*; 35 import java.awt.Dimension; 36 import java.awt.Point; 37 import javax.help.event.EventListenerList; 38 import javax.help.DefaultHelpBroker; 39 import javax.help.event.HelpSetListener; 40 import javax.help.event.HelpSetEvent; 41 import javax.help.Map.ID; 42 43 // implementation-specific 44 import com.sun.java.help.impl.Parser; 45 import com.sun.java.help.impl.ParserListener; 46 import com.sun.java.help.impl.ParserEvent; 47 import com.sun.java.help.impl.Tag; 48 import com.sun.java.help.impl.TagProperties; 49 import com.sun.java.help.impl.XmlReader; 50 import com.sun.java.help.impl.LangElement; 51 import javax.help.Map.ID; 52 import java.beans.PropertyChangeSupport; 53 import java.lang.reflect.Constructor; 54 /** 55 * A HelpSet is a collection of help information consisting of a HelpSet 56 * file, table of contents (TOC), index, topic files, and Map file. 57 * The HelpSet file is the portal to the HelpSet. 58 * 59 * @author Roger D. Brinkley 60 * @author Eduardo Pelegri-Llopart 61 * @author Stepan Marek 62 * @version 1.108 10/30/06 63 */ 64 65 public class HelpSet implements Serializable{ 66 private static String errorMsg = null; 67 /* 68 * Event listeners for adding to the HelpSet 69 */ 70 71 protected EventListenerList listenerList = new EventListenerList(); 72 73 /** 74 * PublicID (known to this XML processor) to the DTD for version 1.0 of the HelpSet 75 */ 76 public static final String publicIDString = 77 "-//Sun Microsystems Inc.//DTD JavaHelp HelpSet Version 1.0//EN"; 78 79 /** 80 * PublicID (known to this XML processor) to the DTD for version 2.0 of the HelpSet 81 */ 82 public static final String publicIDString_V2 = 83 "-//Sun Microsystems Inc.//DTD JavaHelp HelpSet Version 2.0//EN"; 84 85 /** 86 * Information for implementation customization. 87 * 88 * helpBroker/class is used to locate the class for a HelpBroker. 89 * helpBroker/loader is used to determine the ClassLoader to use. 90 */ 91 92 public static final Object implRegistry = 93 new StringBuffer("HelpSet.implRegistry"); 94 public static final String helpBrokerClass = "helpBroker/class"; 95 public static final String helpBrokerLoader = "helpBroker/loader"; 96 97 /** 98 * HelpSet context information. 99 * 100 * A HelpSet can map between keys (String) and values (Strings). 101 * There is a per-HelpSet value and a default value. 102 * The per-HelpSet value is specified in the appropriate section of the 103 * HelpSet file. 104 * The default value is global and only specified at class initialization time. 105 */ 106 107 public static final Object kitTypeRegistry = 108 new StringBuffer("JHelpViewer.kitTypeRegistry"); 109 public static final Object kitLoaderRegistry = 110 new StringBuffer("JHelpViewer.kitLoaderRegistry"); 111 112 /** 113 * Creates an empty HelpSet that one can parse into. 114 * @param loader The ClassLoader to use. If loader is null, the default 115 * ClassLoader is used. 116 */ HelpSet(ClassLoader loader)117 public HelpSet(ClassLoader loader) { 118 this.helpsets = new Vector(); 119 this.loader = loader; 120 } 121 122 /** 123 * Creates an empty HelpSet. Uses the default ClassLoader 124 */ HelpSet()125 public HelpSet() { 126 this.helpsets = new Vector(); 127 this.loader = null; 128 } 129 130 /** 131 * Creates a HelpSet. The locale for the data is either that indicated in 132 * the <tt>lang</tt> attribute of the <tt>helpset</tt> tag, or 133 * <tt>Locale.getDefault()</tt> if the <tt>lang</tt> attribute is not present. 134 * 135 * @param loader The class loader to use to locate any classes 136 * required by the navigators in the Helpset 137 * If loader is null, the default ClassLoader is used. 138 * @param helpset The URL to the HelpSet "file" 139 * 140 * @exception HelpSetException if there are problems parsing the helpset 141 */ HelpSet(ClassLoader loader, URL helpset)142 public HelpSet(ClassLoader loader, URL helpset) throws HelpSetException { 143 this(loader); 144 this.helpset = helpset; // so it can be used in parseInto() 145 146 HelpSetFactory factory = new DefaultHelpSetFactory(); 147 148 parseInto(helpset, factory); 149 HelpSet x = factory.parsingEnded(this); // use the error reporting 150 151 if (x == null) { 152 // We had trouble parsing 153 // May need to revisit this... 154 throw new HelpSetException("Could not parse\n"+errorMsg); 155 } 156 } 157 158 159 /** 160 * Locates a HelpSet file and return its URL. 161 * Applies localization conventions. 162 * 163 * @param cl The classloader to use when searching for the resource 164 * with the appropriate name. If cl is null the default 165 * ClassLoader is used. 166 * @param shortName The shortname of the resource. 167 * @param extension The extension of the resource. 168 * @param locale The desired Locale 169 * @see javax.help.HelpUtilities 170 */ 171 findHelpSet(ClassLoader cl, String shortName, String extension, Locale locale)172 public static URL findHelpSet(ClassLoader cl, 173 String shortName, 174 String extension, 175 Locale locale) { 176 // Test for whether URL can be opened! - workaround Browser bugs 177 return HelpUtilities.getLocalizedResource(cl, 178 shortName, 179 extension, 180 locale, 181 true); 182 } 183 184 /** 185 * Locates a HelpSet file and return its URL. 186 * 187 * If the name does not end with the ".hs" extension, the 188 * ".hs" extension is appended and localization rules 189 * are applied to it. 190 * 191 * @param cl The classloader to use. If cl is null the default 192 * ClassLoader is used. 193 * @param name The name of the resource. 194 * @param locale The desired locale. 195 */ findHelpSet(ClassLoader cl, String name, Locale locale)196 public static URL findHelpSet(ClassLoader cl, 197 String name, 198 Locale locale) { 199 String shortName; 200 String extension; 201 if (name.endsWith(".hs")) { 202 shortName = name.substring(0, name.length()-3); 203 extension = ".hs"; 204 } else { 205 shortName = name; 206 extension = ".hs"; 207 } 208 return findHelpSet(cl, shortName, extension, locale); 209 } 210 211 /** 212 * As above but default on locale to Locale.getDefault() 213 * 214 * @param cl The ClassLoader to use. If cl is null the default 215 * ClassLoader is used. 216 * @param name The name of the resource. 217 * @return Null if not found. 218 */ findHelpSet(ClassLoader cl, String name)219 public static URL findHelpSet(ClassLoader cl, 220 String name) { 221 return findHelpSet(cl, name, Locale.getDefault()); 222 } 223 224 225 /** 226 * Creates a presentation object for this HelpSet. 227 * Consults the <tt>implRegistry</tt> of <tt>KeyData</tt> for 228 * the class name (as helpBrokerClass) and for the ClassLoader 229 * instance (as helpBrokerLoader) and then tries to instantiate 230 * that class. It then invokes <tt>setHelpSet()</tt> with 231 * this instance of HelpSet as the argument. The resulting object is 232 * returned. 233 * @see createHelpBroker(String) 234 */ createHelpBroker()235 public HelpBroker createHelpBroker() { 236 return createHelpBroker(null); 237 } 238 239 /** 240 * Creates a presentation object for this HelpSet. 241 * Consults the <tt>implRegistry</tt> of <tt>KeyData</tt> for 242 * the class name (as helpBrokerClass) and for the ClassLoader 243 * instance (as helpBrokerLoader) and then tries to instantiate 244 * that class. It then invokes <tt>setHelpSet()</tt> with 245 * this instance of HelpSet as the argument. The resulting object is 246 * returned. 247 * @param presenationName A presentation name defined in the HelpSet 248 * that will dictate the presentation. 249 * @return HelpBroker The created HelpBroker 250 * @since 2.0 251 * @see createHelpBroker() 252 */ createHelpBroker(String presentationName)253 public HelpBroker createHelpBroker(String presentationName) { 254 HelpBroker back = null; 255 256 String classname = 257 (String) getKeyData(implRegistry, helpBrokerClass); 258 ClassLoader loader = 259 (ClassLoader) getKeyData(implRegistry, helpBrokerLoader); 260 261 if (loader == null) { 262 loader = getLoader(); 263 } 264 try { 265 Class c; 266 if (loader != null) { 267 c = loader.loadClass(classname); 268 } else { 269 c = Class.forName(classname); 270 } 271 back = (HelpBroker) c.newInstance(); 272 } catch (Throwable e) { 273 back = null; 274 } 275 276 if (back != null) { 277 back.setHelpSet(this); 278 HelpSet.Presentation hsPres = null; 279 // If there is a presentation name find it otherwise get the 280 // default if one exists. 281 if (presentationName != null) { 282 hsPres = getPresentation(presentationName); 283 } else { 284 hsPres = getDefaultPresentation(); 285 } 286 if (hsPres != null) { 287 back.setHelpSetPresentation(hsPres); 288 } 289 } 290 return back; 291 } 292 293 /** 294 * Adds a HelpSet, HelpSetEvents are generated. 295 * Adding a composed HelpSet to another is equivalent to 296 * adding all the HelpSets individually. 297 * 298 * @param hs The HelpSet to add. 299 */ add(HelpSet hs)300 public void add(HelpSet hs) { 301 debug("add("+hs+")"); 302 helpsets.addElement(hs); 303 fireHelpSetAdded(this, hs); 304 combinedMap = null; // invalidate the map 305 } 306 307 /** 308 * Removes a HelpSet from this HelpSet; HelpSetEvents are generated 309 * Return True if it is found, otherwise false. 310 * 311 * @param hs The HelpSet to remove. 312 * @return False if the hs is null or was not in this HelpSet 313 */ remove(HelpSet hs)314 public boolean remove(HelpSet hs) { 315 if (helpsets.removeElement(hs)) { 316 fireHelpSetRemoved(this, hs); 317 combinedMap = null; // HERE - invalidate it - epll 318 return true; 319 } else { 320 return false; 321 } 322 } 323 324 /** 325 * Enumerates all the HelpSets that have been added to this one. 326 * 327 * @return An enumeration of the HelpSets that have been added to 328 * this HelpSet. 329 */ getHelpSets()330 public Enumeration getHelpSets() { 331 return helpsets.elements(); 332 } 333 334 /** 335 * Determines if a HelpSet is a sub-HelpSet of this object. 336 * 337 * @param hs The HelpSet to check 338 * @return true If <tt>hs</tt> is contained in this HelpSet or in one of its children. 339 */ contains(HelpSet hs)340 public boolean contains(HelpSet hs) { 341 if (hs == this) { 342 return true; 343 } 344 for (Enumeration e = helpsets.elements(); 345 e.hasMoreElements();) { 346 HelpSet child = (HelpSet) e.nextElement(); 347 if (child.contains(hs)) { 348 return true; 349 } 350 } 351 return false; 352 } 353 354 /** 355 * Adds a listener for the HelpSetEvent posted after the model has 356 * changed. 357 * 358 * @param l - The listener to add. 359 * @see javax.help.HelpSet#removeHelpSetListener. 360 * @throws IllegalArgumentException if l is null. 361 */ addHelpSetListener(HelpSetListener l)362 public void addHelpSetListener(HelpSetListener l) { 363 debug("addHelpSetListener("+l+")"); 364 listenerList.add(HelpSetListener.class, l); 365 } 366 367 /** 368 * Removes a listener previously added with <tt>addHelpSetListener</tt> 369 * 370 * @param l - The listener to remove. 371 * @see javax.help.HelpSet#addHelpSetListener. 372 * @throws IllegalArgumentException if l is null. 373 */ removeHelpSetListener(HelpSetListener l)374 public void removeHelpSetListener(HelpSetListener l) { 375 listenerList.remove(HelpSetListener.class, l); 376 } 377 378 /** 379 * Fires a helpSetAdded event. 380 */ fireHelpSetAdded(Object source, HelpSet helpset)381 protected void fireHelpSetAdded(Object source, HelpSet helpset){ 382 Object[] listeners = listenerList.getListenerList(); 383 HelpSetEvent e = null; 384 385 for (int i = listeners.length - 2; i >= 0; i -= 2) { 386 if (listeners[i] == HelpSetListener.class) { 387 if (e == null) { 388 e = new HelpSetEvent(this, helpset, 389 HelpSetEvent.HELPSET_ADDED); 390 } 391 ((HelpSetListener)listeners[i+1]).helpSetAdded(e); 392 } 393 } 394 } 395 396 /** 397 * Fires a helpSetRemoved event. 398 */ fireHelpSetRemoved(Object source, HelpSet helpset)399 protected void fireHelpSetRemoved(Object source, HelpSet helpset){ 400 Object[] listeners = listenerList.getListenerList(); 401 HelpSetEvent e = null; 402 403 for (int i = listeners.length - 2; i >= 0; i -= 2) { 404 if (listeners[i] == HelpSetListener.class) { 405 if (e == null) { 406 e = new HelpSetEvent(this, helpset, 407 HelpSetEvent.HELPSET_REMOVED); 408 } 409 ((HelpSetListener)listeners[i+1]).helpSetRemoved(e); 410 } 411 } 412 } 413 414 // ======= Labels, etc ======= 415 /** 416 * Gets the title of this HelpSet. 417 * 418 * @return the title 419 */ getTitle()420 public String getTitle() { 421 if (title == null) { 422 return ""; 423 } else { 424 return title; 425 } 426 } 427 428 /** 429 * Sest the title for this HelpSet. This is a bound property. 430 * 431 * @param title The title to set. 432 */ 433 setTitle(String title)434 public void setTitle(String title) { 435 String oldTitle = this.title; 436 this.title = title; 437 changes.firePropertyChange("title", oldTitle, title); 438 } 439 440 /** 441 * Gets the locale for this HelpSet. 442 * 443 * @return The locale. 444 */ getLocale()445 public Locale getLocale() { 446 return locale; 447 } 448 449 /** 450 * Sets the locale for this HelpSet. 451 * Strictly a private routine but the read-only property is bound. 452 * 453 * @param locale The locale to set. 454 */ setLocale(Locale l)455 private void setLocale(Locale l) { 456 Locale oldLocale = locale; 457 locale = l; 458 changes.firePropertyChange("locale", oldLocale, locale); 459 } 460 461 /** 462 * Returns 463 * the ID to visit when the user makes a "go home" gesture. 464 * This can be identified in the project file, but may also be changed 465 * programmatically or (possibly) via the UI. 466 * 467 * @return The ID of home. A null is returned if homeID is null 468 * or if an ID cannot be created for the homeID. 469 */ getHomeID()470 public ID getHomeID() { 471 if (homeID == null) { 472 return null; 473 } else { 474 try { 475 return ID.create(homeID, this); 476 } catch (Exception ex) { 477 return null; 478 } 479 } 480 } 481 482 /** 483 * Sets the Home ID for a HelpSet. This is a bound property. 484 * 485 * @param The ID (in the Map) that identifies the default topic for this HelpSet. Null is valid homeID. 486 */ setHomeID(String homeID)487 public void setHomeID(String homeID) { 488 String oldID = homeID; 489 this.homeID = homeID; 490 changes.firePropertyChange("homeID", oldID, homeID); 491 } 492 493 // WARNING/HERE: In this implementation, the Map is not updated automatically 494 // so you need to come get a new one - epll 495 496 // Warning. This is not handling recursive aggregation 497 498 /** 499 * The map for this HelpSet. This map involves the closure of 500 * this HelpSet's children HelpSets. 501 * 502 * @return The map 503 */ getCombinedMap()504 public Map getCombinedMap() { 505 if (combinedMap == null) { 506 combinedMap = new TryMap(); 507 if (map != null) { 508 combinedMap.add(map); // the local map 509 } 510 for (Enumeration e = helpsets.elements(); 511 e.hasMoreElements(); ) { 512 HelpSet hs = (HelpSet) e.nextElement(); 513 combinedMap.add(hs.getCombinedMap()); 514 } 515 } 516 return combinedMap; 517 } 518 519 /** 520 * Get the local (i.e.<!-- --> non-recursive) Map for this HelpSet. 521 * This Map does not include the Maps for its children. 522 * 523 * @return The Map object that associates ID->URL. A null map is valid. 524 */ getLocalMap()525 public Map getLocalMap() { 526 return this.map; 527 } 528 529 /** 530 * Set the Map for this HelpSet. This Map object is not recursive; for example, 531 * it does not include the Maps for its children. 532 * 533 * @param The Map object that associates ID->URL. A null map is a valid. 534 */ setLocalMap(Map map)535 public void setLocalMap(Map map) { 536 this.map = map; 537 } 538 539 /** 540 * The URL that is the base for this HelpSet. 541 * 542 * @return The URL that is base to this HelpSet. 543 */ getHelpSetURL()544 public URL getHelpSetURL() { 545 return helpset; 546 } 547 548 /** 549 * A classloader to use when locating classes. 550 * 551 * @return The ClassLoader to use when locating classes mentioned 552 * in this HelpSet. 553 */ 554 getLoader()555 public ClassLoader getLoader() { 556 return loader; 557 } 558 559 /** 560 * NavigatorView describes the navigator views that are requested 561 * by this HelpSet. 562 * 563 * @return The array of NavigatorView. 564 */ 565 getNavigatorViews()566 public NavigatorView[] getNavigatorViews() { 567 NavigatorView back[] = new NavigatorView[views.size()]; 568 views.copyInto(back); 569 return back; 570 } 571 572 /** 573 * Gets the NavigatorView with a specific name. 574 * 575 * @param The name of the desired navigator view. 576 */ getNavigatorView(String name)577 public NavigatorView getNavigatorView(String name) { 578 debug("getNavigatorView("+name+")"); 579 for (int i=0; i<views.size(); i++) { 580 NavigatorView view = (NavigatorView) views.elementAt(i); 581 if (view.getName().equals(name)) { 582 debug(" = "+view); 583 return view; 584 } 585 } 586 debug(" = null"); 587 return null; 588 } 589 590 /** 591 * HelpSet.Presentation describes the presentations that are defined 592 * by this HelpSet. 593 * 594 * @return The array of HelpSet.Presentations. 595 */ 596 getPresentations()597 public HelpSet.Presentation [] getPresentations() { 598 HelpSet.Presentation back[] = new HelpSet.Presentation[presentations.size()]; 599 presentations.copyInto(back); 600 return back; 601 } 602 603 /** 604 * Gets the HelpSet.Presentation with a specific name. 605 * 606 * @param The name of the desired HelpSet.Presentation. 607 */ getPresentation(String name)608 public HelpSet.Presentation getPresentation(String name) { 609 debug("getPresentation("+name+")"); 610 for (int i=0; i<presentations.size(); i++) { 611 HelpSet.Presentation pres = (HelpSet.Presentation) presentations.elementAt(i); 612 if (pres.getName().equals(name)) { 613 debug(" = "+pres); 614 return pres; 615 } 616 } 617 debug(" = null"); 618 return null; 619 } 620 getDefaultPresentation()621 public HelpSet.Presentation getDefaultPresentation() { 622 return defaultPresentation; 623 } 624 625 /** 626 * Prints Name for this HelpSet. 627 */ toString()628 public String toString() { 629 return getTitle(); 630 } 631 632 // ===== Public interfaces to parsing 633 634 /** 635 * Parsed a HelpSet file. 636 */ parse(URL url, ClassLoader loader, HelpSetFactory factory)637 public static HelpSet parse(URL url, 638 ClassLoader loader, 639 HelpSetFactory factory) { 640 HelpSet hs = new HelpSet(loader); // an empty HelpSet 641 hs.helpset = url; 642 hs.parseInto(url, factory); 643 return factory.parsingEnded(hs); 644 } 645 646 /** 647 * Parses into this HelpSet. 648 */ parseInto(URL url, HelpSetFactory factory)649 public void parseInto(URL url, 650 HelpSetFactory factory) { 651 Reader src; 652 try { 653 URLConnection uc = url.openConnection(); 654 src = XmlReader.createReader(uc); 655 factory.parsingStarted(url); 656 (new HelpSetParser(factory)).parseInto(src, this); 657 src.close(); 658 } catch (Exception ex) { 659 factory.reportMessage("Got an IOException ("+ 660 ex.getMessage()+ 661 ")", false); 662 if(debug) 663 ex.printStackTrace(); 664 } 665 666 // Now add any subhelpsets 667 for (int i=0; i<subHelpSets.size(); i++) { 668 HelpSet subHS = (HelpSet) subHelpSets.elementAt(i); 669 add(subHS); 670 } 671 } 672 673 /** 674 * The default HelpSetFactory that processes HelpSets. 675 */ 676 677 public static class DefaultHelpSetFactory implements HelpSetFactory { 678 private Vector messages = new Vector(); 679 private URL source; 680 private boolean validParse = true; 681 682 /** 683 * Parsing starts. 684 */ parsingStarted(URL source)685 public void parsingStarted(URL source) { 686 if (source == null) { 687 throw new NullPointerException("source"); 688 } 689 this.source = source; 690 } 691 692 /** 693 * Process a DOCTYPE 694 * @param publicID the document. If null or is not valid a parsingError 695 * will be generated. 696 */ processDOCTYPE(String root, String publicID, String systemID)697 public void processDOCTYPE(String root, 698 String publicID, 699 String systemID) { 700 if (publicID == null || 701 (publicID.compareTo(publicIDString) != 0 && 702 publicID.compareTo(publicIDString_V2) != 0)) { 703 parsingError("helpset.wrongPublicID", publicID); 704 } 705 } 706 707 /** 708 * Processes a PI 709 */ processPI(HelpSet hs, String target, String data)710 public void processPI(HelpSet hs, 711 String target, 712 String data) { 713 // ignore for now 714 } 715 716 /** 717 * A title is found 718 */ processTitle(HelpSet hs, String value)719 public void processTitle(HelpSet hs, 720 String value) { 721 String title = hs.getTitle(); 722 if ((title != null) && !title.equals("")) { 723 parsingWarning("helpset.wrongTitle", value, title); 724 } 725 hs.setTitle(value); 726 } 727 728 /** 729 * A HomeID is found. 730 */ 731 processHomeID(HelpSet hs, String value)732 public void processHomeID(HelpSet hs, 733 String value) { 734 ID homeID = hs.getHomeID(); 735 if ((homeID == null) || homeID.equals("")) { 736 //parsingError("helpset.wrongHomeID", value, homeID.id); 737 hs.setHomeID(value); 738 }else{ 739 parsingError("helpset.wrongHomeID", value, homeID.id); 740 } 741 742 } 743 744 /** 745 * process a <mapref> 746 * 747 * @param Spec to the URL 748 * @param Attributes for the tag 749 */ processMapRef(HelpSet hs, Hashtable attributes)750 public void processMapRef(HelpSet hs, 751 Hashtable attributes) { 752 String spec = (String) attributes.get("location"); 753 URL hsURL = hs.getHelpSetURL(); 754 try { 755 Map map = new FlatMap(new URL(hsURL, spec), hs); 756 Map omap = hs.getLocalMap(); 757 if (omap == null) { 758 debug("map is null"); 759 hs.setLocalMap(map); 760 } else { 761 // to implement multiple Maps add this code: 762 // 763 if (omap instanceof TryMap) { 764 debug("map is TryMap"); 765 ((TryMap)omap).add(map); 766 /// 767 ///what about hs.setLocalMap//// 768 /// 769 hs.setLocalMap(omap); 770 } else { 771 debug("map is not TryMap"); 772 TryMap tmap = new TryMap(); 773 tmap.add(omap); 774 tmap.add(map); 775 hs.setLocalMap(tmap); 776 } 777 778 } 779 } catch (MalformedURLException ee) { 780 parsingError("helpset.malformedURL", spec); 781 } catch (IOException ee) { 782 parsingError("helpset.incorrectURL", spec); 783 } catch (Exception ex) { 784 // parsing error... 785 } 786 } 787 788 /* 789 * Called per <view> 790 */ processView(HelpSet hs, String name, String label, String type, Hashtable viewAttributes, String data, Hashtable dataAttributes, Locale locale)791 public void processView(HelpSet hs, 792 String name, 793 String label, 794 String type, 795 Hashtable viewAttributes, 796 String data, 797 Hashtable dataAttributes, 798 Locale locale) { 799 800 try { 801 NavigatorView view; 802 if (data != null) { 803 if (dataAttributes == null) { 804 dataAttributes = new Hashtable(); 805 } 806 dataAttributes.put("data", data); 807 808 } 809 810 view = NavigatorView.create(hs, 811 name, label, 812 locale, 813 type, 814 dataAttributes); 815 816 if (view == null) { 817 // ignore ?? 818 } else { 819 820 hs.addView(view); 821 } 822 } catch (Exception ex) { 823 // ignore this view... 824 } 825 } 826 827 /* 828 * Called per <presentation> 829 */ processPresentation(HelpSet hs, String name, boolean defaultPresentation, boolean displayViews, boolean displayViewImages, Dimension size, Point location, String title, String imageID, boolean toolbar, Vector helpActions)830 public void processPresentation(HelpSet hs, 831 String name, 832 boolean defaultPresentation, 833 boolean displayViews, 834 boolean displayViewImages, 835 Dimension size, 836 Point location, 837 String title, 838 String imageID, 839 boolean toolbar, 840 Vector helpActions) { 841 842 Map.ID imageMapID = null; 843 try { 844 imageMapID = ID.create(imageID, hs); 845 } catch (BadIDException bex2) { 846 } 847 try { 848 HelpSet.Presentation presentation = 849 new HelpSet.Presentation(name, displayViews, 850 displayViewImages, size, 851 location, title, imageMapID, 852 toolbar, helpActions); 853 854 if (presentation == null) { 855 // ignore ?? 856 } else { 857 hs.addPresentation(presentation, defaultPresentation); 858 } 859 } catch (Exception ex) { 860 // ignore this presentation... 861 } 862 } 863 864 /** 865 * Called when a sub-HelpSet is found. 866 */ processSubHelpSet(HelpSet hs, Hashtable attributes)867 public void processSubHelpSet(HelpSet hs, 868 Hashtable attributes) { 869 debug("createSubHelpSet"); 870 871 String spec = (String) attributes.get("location"); 872 URL base = hs.getHelpSetURL(); 873 874 debug(" location: "+spec); 875 debug(" base helpset: "+base); 876 877 URL u = null; 878 HelpSet subHS = null; 879 try { 880 u = new URL(base, spec); 881 // test and see if the file is there 882 // if it doesnt' through an exception all is ok 883 InputStream is = u.openStream(); 884 if (is != null) { 885 subHS = new HelpSet(hs.getLoader(), u); 886 if (subHS != null) { 887 hs.addSubHelpSet(subHS); 888 } 889 } 890 } catch (MalformedURLException ex) { 891 // ignore a malformed URL 892 // The subhelpset is just ignored 893 } catch (IOException ex) { 894 // ignore an IOException 895 // The subhelpset is just ignored 896 } catch (HelpSetException ex) { 897 parsingError("helpset.subHelpSetTrouble", spec); 898 } 899 } 900 901 /** 902 * Reports an error message. 903 */ reportMessage(String msg, boolean validParse)904 public void reportMessage(String msg, boolean validParse) { 905 messages.addElement(msg); 906 this.validParse = this.validParse && validParse; 907 } 908 909 /** 910 * Enumerates all the error messages. 911 */ listMessages()912 public Enumeration listMessages() { 913 return messages.elements(); 914 } 915 916 /** 917 * Parsing has ended. Last chance to do something 918 * to the HelpSet. 919 * @param hs The HelpSet the parsing ended on. A null hs is valid. 920 */ parsingEnded(HelpSet hs)921 public HelpSet parsingEnded(HelpSet hs) { 922 HelpSet back = hs; 923 if (! validParse) { 924 // A parse with problems... 925 back = null; 926 927 String errMsg = "Parsing failed for "+source; 928 //System.err.println(errMsg); 929 messages.addElement(errMsg); 930 931 for (Enumeration e = messages.elements(); 932 e.hasMoreElements();) { 933 String msg = (String) e.nextElement(); 934 if(debug) 935 System.err.println(msg); 936 if(HelpSet.errorMsg == null) 937 HelpSet.errorMsg = msg; 938 else{ 939 HelpSet.errorMsg = HelpSet.errorMsg+"\n"; 940 HelpSet.errorMsg = HelpSet.errorMsg + msg; 941 } 942 943 } 944 } 945 return back; 946 } 947 948 // Convenience methods parsingError(String key)949 private void parsingError(String key) { 950 String s = HelpUtilities.getText(key); 951 reportMessage(s, false); // tree will be wrong 952 } 953 954 /** 955 * @throws Error if key is invalid. 956 */ parsingError(String key, String s)957 private void parsingError(String key, String s) { 958 String msg = HelpUtilities.getText(key, s); 959 reportMessage(msg, false); // tree will be wrong 960 } 961 962 /** 963 * @throws Error if key is invalid. 964 */ parsingError(String key, String s1, String s2)965 private void parsingError(String key, String s1, String s2) { 966 String msg = HelpUtilities.getText(key, s1, s2); 967 reportMessage(msg, false); // tree will be wrong 968 } 969 parsingWarning(String key, String s1, String s2)970 private void parsingWarning(String key, String s1, String s2) { 971 String msg = HelpUtilities.getText(key, s1, s2); 972 reportMessage(msg, true); // warning only 973 } 974 975 } // End of DefaultHelpSetFactory 976 977 978 /** 979 * HelpSet Presentation class. Contains information concerning a 980 * presentation in a HelpSet file 981 * @since 2.0 982 */ 983 public static class Presentation { 984 985 private String name; 986 private boolean displayViews; 987 private boolean displayViewImages; 988 private Dimension size; 989 private Point location; 990 private String title; 991 private boolean toolbar; 992 private Vector helpActions; 993 private Map.ID imageID; 994 Presentation(String name, boolean displayViews, boolean displayViewImages, Dimension size, Point location, String title, Map.ID imageID, boolean toolbar, Vector helpActions)995 public Presentation (String name, 996 boolean displayViews, 997 boolean displayViewImages, 998 Dimension size, 999 Point location, 1000 String title, 1001 Map.ID imageID, 1002 boolean toolbar, 1003 Vector helpActions) { 1004 this.name = name; 1005 this.displayViews = displayViews; 1006 this.displayViewImages = displayViewImages; 1007 this.size = size; 1008 this.location = location; 1009 this.title = title; 1010 this.imageID = imageID; 1011 this.toolbar = toolbar; 1012 this.helpActions = helpActions; 1013 } 1014 getName()1015 public String getName() { 1016 return name; 1017 } 1018 getTitle()1019 public String getTitle() { 1020 return title; 1021 } 1022 getImageID()1023 public Map.ID getImageID() { 1024 return imageID; 1025 } 1026 isViewDisplayed()1027 public boolean isViewDisplayed() { 1028 return displayViews; 1029 } 1030 isViewImagesDisplayed()1031 public boolean isViewImagesDisplayed() { 1032 return displayViewImages; 1033 } 1034 getSize()1035 public Dimension getSize() { 1036 return size; 1037 } 1038 getLocation()1039 public Point getLocation() { 1040 return location; 1041 } 1042 isToolbar()1043 public boolean isToolbar() { 1044 return toolbar; 1045 } 1046 1047 /** 1048 * Returns an Enumeration HelpActions created from the 1049 * list of Actions in the Presentation. 1050 * 1051 * @see HelpAction 1052 */ getHelpActions(HelpSet hs, Object control)1053 public Enumeration getHelpActions(HelpSet hs, Object control) { 1054 Vector actions = new Vector(); 1055 ClassLoader loader = hs.getLoader(); 1056 Class klass; 1057 Constructor konstructor; 1058 HelpAction action; 1059 1060 if (helpActions == null) { 1061 // got a nutziod who didn't check the isToolbar 1062 // just return back the empty vector elements 1063 return actions.elements(); 1064 } 1065 Enumeration actionEnum = helpActions.elements(); 1066 while (actionEnum.hasMoreElements()) { 1067 HelpSetFactory.HelpAction act = 1068 (HelpSetFactory.HelpAction)actionEnum.nextElement(); 1069 1070 try { 1071 Class types[] = { Object.class }; 1072 Object args[] = { control }; 1073 if (loader == null) { 1074 klass = Class.forName(act.className); 1075 } else { 1076 klass = loader.loadClass(act.className); 1077 } 1078 konstructor = klass.getConstructor(types); 1079 action = (HelpAction) konstructor.newInstance(args); 1080 1081 // The HelpAction has been added now add any known 1082 // attributes 1083 if (act.attr.containsKey("image")) { 1084 String imageID = (String) act.attr.get("image"); 1085 try { 1086 Map.ID id = Map.ID.create(imageID, hs); 1087 javax.swing.ImageIcon icon = null; 1088 Map map = hs.getCombinedMap(); 1089 URL url = map.getURLFromID(id); 1090 icon = new javax.swing.ImageIcon(url); 1091 action.putValue("icon", icon); 1092 } catch (Exception ex) { 1093 } 1094 } 1095 actions.add(action); 1096 } catch (Exception ex) { 1097 throw new RuntimeException("Could not create HelpAction " + 1098 act.className); 1099 } 1100 } 1101 1102 return actions.elements(); 1103 } 1104 1105 } 1106 1107 // =========== Protected Methods for use by subclasses ========== 1108 1109 /** 1110 * Adds a NavigatorView to the current list. 1111 */ addView(NavigatorView view)1112 protected void addView(NavigatorView view) { 1113 views.addElement(view); 1114 } 1115 1116 /** 1117 * Adds a SubHelpSet to the current list. 1118 */ 1119 addSubHelpSet(HelpSet hs)1120 protected void addSubHelpSet(HelpSet hs) { 1121 subHelpSets.addElement(hs); 1122 } 1123 1124 /** 1125 * Adds a HelpSet.Presentation to the current list. 1126 */ addPresentation(HelpSet.Presentation presentation, boolean defaultPres)1127 protected void addPresentation(HelpSet.Presentation presentation, 1128 boolean defaultPres) { 1129 presentations.addElement(presentation); 1130 if (defaultPres) { 1131 defaultPresentation = presentation; 1132 } 1133 } 1134 1135 // ============= Simple registry ============ 1136 1137 /** 1138 * Gets some Data for a Key in a given context. 1139 * Local (per HelpSet instance) data is searched first, then defaults. 1140 */ 1141 getKeyData(Object context, String key)1142 public Object getKeyData(Object context, 1143 String key) { 1144 Object back = null; 1145 Hashtable h = (Hashtable) localKeys.get(context); 1146 if (h != null) { 1147 back = h.get(key); 1148 } 1149 if (back == null) { 1150 h = (Hashtable) defaultKeys.get(context); 1151 if (h != null) { 1152 back = h.get(key); 1153 } 1154 } 1155 return back; 1156 } 1157 1158 /** 1159 * Sets some local KeyData on a given context. The information is set on 1160 * a per-HelpSet basis. 1161 */ setKeyData(Object context, String key, Object data)1162 public void setKeyData(Object context, 1163 String key, 1164 Object data) { 1165 Hashtable h = (Hashtable) localKeys.get(context); 1166 if (h == null) { 1167 h = new Hashtable(); 1168 localKeys.put(context, h); 1169 } 1170 h.put(key, data); 1171 } 1172 1173 /** 1174 * Default initialization. This can only be done from within this class. 1175 */ setDefaultKeyData(Object context, String key, Object data)1176 private static void setDefaultKeyData(Object context, 1177 String key, 1178 Object data) { 1179 if (defaultKeys == null) { 1180 defaultKeys = new Hashtable(); 1181 } 1182 Hashtable h = (Hashtable) defaultKeys.get(context); 1183 if (h == null) { 1184 h = new Hashtable(); 1185 defaultKeys.put(context, h); 1186 } 1187 h.put(key, data); 1188 } 1189 1190 1191 /** 1192 * Initializes the default registries. 1193 */ 1194 static { setDefaultKeyData(implRegistry, helpBrokerClass, R)1195 setDefaultKeyData(implRegistry, 1196 helpBrokerClass, "javax.help.DefaultHelpBroker"); setDefaultKeyData(kitTypeRegistry, R, R)1197 setDefaultKeyData(kitTypeRegistry, 1198 "text/html", "com.sun.java.help.impl.CustomKit"); 1199 1200 ClassLoader cl = HelpSet.class.getClassLoader(); 1201 if (cl != null) { setDefaultKeyData(implRegistry, helpBrokerLoader, cl)1202 setDefaultKeyData(implRegistry, 1203 helpBrokerLoader, cl); setDefaultKeyData(kitLoaderRegistry, R, cl)1204 setDefaultKeyData(kitLoaderRegistry, 1205 "text/html", cl); 1206 } 1207 } 1208 1209 //======== Private members ========= 1210 1211 private String title; // the title for this helpset 1212 private Map map; // the local map 1213 private TryMap combinedMap; // the combined ID<->URL map 1214 private URL helpset; // the HelpSet from where to search 1215 private String homeID; 1216 private Locale locale = Locale.getDefault(); 1217 1218 private transient ClassLoader loader; // encapsulates loading... 1219 1220 private Vector views = new Vector(); 1221 1222 private Vector presentations = new Vector(); 1223 1224 private HelpSet.Presentation defaultPresentation = null; 1225 1226 private Vector helpsets; // All the helpsets added to this one 1227 1228 private static HelpBroker defaultHelpBroker = null; // the default HelpBroker 1229 1230 private Vector subHelpSets = new Vector(); 1231 1232 // Default and Local Hashtables for keys 1233 1234 private static Hashtable defaultKeys; 1235 private Hashtable localKeys = new Hashtable(); 1236 1237 private PropertyChangeSupport changes = new PropertyChangeSupport(this); 1238 1239 // ============= PRIVATE Parsing Class ======== 1240 1241 /** 1242 * Inner class for parsing a TOC stream. 1243 * 1244 * WARNING!! This class is an interim solution until when we move to a 1245 * real XML parser. This is not a public class. Clients should only use 1246 * the parse method in the enclosing class. 1247 */ 1248 1249 private static class HelpSetParser implements ParserListener { 1250 private Stack tagStack; // the collection of active Parse tags 1251 private Locale defaultLocale; 1252 private Locale lastLocale; 1253 private HelpSet myHS; // my HelpSet 1254 private Locale myHSLocale; // its locale 1255 private HelpSetFactory factory; // the factory 1256 1257 1258 private String tagName; // genericly used for views and presentation 1259 private String viewLabel; 1260 private String viewType; 1261 private String viewEngine; 1262 private String tagImage; 1263 private String helpActionImage; 1264 private String viewData; 1265 private String viewMergeType; 1266 private Hashtable htData; 1267 1268 private boolean defaultPresentation = false; 1269 private boolean displayViews = true; 1270 private boolean displayViewImages = true; 1271 private Dimension size; 1272 private Point location; 1273 private String presentationTitle; 1274 private boolean toolbar; 1275 private Vector helpActions; 1276 private String helpAction; 1277 1278 /** 1279 * Creates a Parser (Listener) instance. 1280 */ HelpSetParser(HelpSetFactory factory)1281 HelpSetParser (HelpSetFactory factory) { 1282 this.factory = factory; 1283 } 1284 1285 /** 1286 * Parses a reader into a HelpSet. 1287 */ parseInto(Reader src, HelpSet hs)1288 synchronized void parseInto(Reader src, 1289 HelpSet hs) 1290 throws IOException 1291 { 1292 tagStack = new Stack(); 1293 defaultLocale = hs.getLocale(); 1294 lastLocale = defaultLocale; 1295 myHS = hs; 1296 myHSLocale = hs.getLocale(); 1297 Parser parser = new Parser(src); // the XML parser instance 1298 parser.addParserListener(this); 1299 parser.parse(); 1300 } 1301 tagFound(ParserEvent e)1302 public void tagFound(ParserEvent e) { 1303 debug("tagFound " + e.getTag().name); 1304 Locale locale = null; 1305 LangElement le; 1306 Tag tag = e.getTag(); 1307 String name = tag.name; 1308 int x=0, y=0, width=0, height=0; 1309 TagProperties attr = tag.atts; 1310 Hashtable ht = (attr == null) ? null : attr.getHashtable(); 1311 1312 if (attr != null) { 1313 String lang = attr.getProperty("xml:lang"); 1314 locale = HelpUtilities.localeFromLang(lang); 1315 viewMergeType = attr.getProperty("mergetype"); 1316 helpActionImage = attr.getProperty("image"); 1317 String value = null; 1318 value = attr.getProperty("width"); 1319 if (value != null) { 1320 width = Integer.parseInt(value); 1321 } 1322 value = null; 1323 value = attr.getProperty("height"); 1324 if (value != null) { 1325 height = Integer.parseInt(value); 1326 } 1327 value = null; 1328 value = attr.getProperty("x"); 1329 if (value != null) { 1330 x = Integer.parseInt(value); 1331 } 1332 value = null; 1333 value = attr.getProperty("y"); 1334 if (value != null) { 1335 y = Integer.parseInt(value); 1336 } 1337 value = null; 1338 value = attr.getProperty("default"); 1339 if (value != null && value.equals("true")) { 1340 defaultPresentation = true; 1341 } 1342 value = null; 1343 value = attr.getProperty("displayviews"); 1344 if (value != null && value.equals("false")) { 1345 displayViews = false; 1346 } 1347 value = null; 1348 value = attr.getProperty("displayviewimages"); 1349 if (value != null && value.equals("false")) { 1350 displayViewImages = false; 1351 } 1352 } 1353 if (locale == null) { 1354 locale = lastLocale; 1355 } 1356 1357 if (name.equals("helpset")) { 1358 if (tag.isEnd) { 1359 removeTag(tag); 1360 } else { 1361 // Check and see if the locale is different from the 1362 // defaultLocale. If it is then reset the locale. 1363 if (! locale.equals(defaultLocale) && 1364 ! locale.equals(myHSLocale)) { 1365 if (locale != null) { 1366 myHS.setLocale(locale); 1367 defaultLocale = locale; 1368 } 1369 } 1370 if (attr != null) { 1371 String version = attr.getProperty("version"); 1372 if (version != null && 1373 (version.compareTo("1.0") != 0 && 1374 version.compareTo("2.0") != 0)) { 1375 parsingError("helpset.unknownVersion", version); 1376 } 1377 } 1378 addTag(tag, locale); 1379 } 1380 return; 1381 } 1382 1383 if (tagStack.empty()) { 1384 parsingError("helpset.wrongTopLevel", name); 1385 } 1386 1387 // Get the parents name 1388 le = (LangElement) tagStack.peek(); 1389 String pname = ((Tag) le.getTag()).name; // the parent 1390 1391 if (name.equals("title")) { 1392 // TITLE tag 1393 if (tag.isEnd) { 1394 removeTag(tag); // processing was done in textFound() 1395 } else { 1396 if ((! pname.equals("helpset")) && 1397 (! pname.equals("presentation"))){ 1398 wrongParent(name, pname); 1399 } 1400 if (! locale.equals(defaultLocale) && 1401 ! locale.equals(myHSLocale)) { 1402 wrongLocale(locale, defaultLocale, myHSLocale); 1403 } 1404 addTag(tag, locale); 1405 } 1406 } else if (name.equals("homeID")) { 1407 // HOMEID tags 1408 if (tag.isEnd) { 1409 removeTag(tag); // processing was done in textFound() 1410 } else { 1411 if (! pname.equals("maps")) { 1412 wrongParent(name, pname); 1413 } 1414 addTag(tag, locale); 1415 } 1416 } else if (name.equals("mapref")) { 1417 // MAPREF tags 1418 1419 // Remove from stack if an empty tag 1420 if (tag.isEnd && !tag.isEmpty) { 1421 removeTag(tag); 1422 } else { 1423 if (! pname.equals("maps")) { 1424 wrongParent(name, pname); 1425 } 1426 // add the tag if not an empty tag 1427 if (! tag.isEmpty) { 1428 addTag(tag, locale); 1429 } 1430 // Process the tag 1431 factory.processMapRef(myHS, 1432 ht); 1433 } 1434 } else if (name.equals("data")) { 1435 // DATA tag 1436 if (tag.isEnd) { 1437 removeTag(tag); 1438 } else { 1439 if (! pname.equals("view")) { 1440 wrongParent(name, pname); 1441 } else { 1442 addTag(tag, locale); 1443 } 1444 htData = ht; 1445 } 1446 } else if (name.equals("name") || 1447 name.equals("type") || 1448 name.equals("image")){ 1449 // NAME, TYPE, IMAGE tag 1450 if (tag.isEnd) { 1451 removeTag(tag); 1452 } else { 1453 if ((! pname.equals("view")) && 1454 (! pname.equals("presentation"))) { 1455 wrongParent(name, pname); 1456 } else { 1457 addTag(tag, locale); 1458 } 1459 } 1460 } else if (name.equals("label")) { 1461 // LABEL tag 1462 // Special processing to check the locale attribute. 1463 if (tag.isEnd) { 1464 removeTag(tag); 1465 } else { 1466 if (! pname.equals("view")) { 1467 wrongParent(name, pname); 1468 } else { 1469 if (! locale.equals(defaultLocale) && 1470 ! locale.equals(myHSLocale)) { 1471 wrongLocale(locale, defaultLocale, myHSLocale); 1472 } 1473 addTag(tag, locale); 1474 } 1475 } 1476 } else if (name.equals("view")) { 1477 // VIEW tag 1478 if (tag.isEnd) { 1479 removeTag(tag); 1480 1481 if (tagImage != null) { 1482 if (htData == null) { 1483 htData = new Hashtable(); 1484 } 1485 htData.put("imageID", tagImage); 1486 } 1487 1488 if (viewMergeType != null) { 1489 if(htData == null) { 1490 htData = new Hashtable(); 1491 } 1492 htData.put("mergetype",viewMergeType); 1493 } 1494 1495 factory.processView(myHS, 1496 tagName, 1497 viewLabel, 1498 viewType, 1499 ht, 1500 viewData, 1501 htData, 1502 locale); 1503 tagName = null; 1504 viewLabel = null; 1505 viewType = null; 1506 tagImage = null; 1507 viewData = null; 1508 htData = null; 1509 viewMergeType = null; 1510 1511 } else { 1512 if (! pname.equals("helpset")) { 1513 wrongParent(name, pname); 1514 } else { 1515 addTag(tag, locale); 1516 } 1517 } 1518 } else if (name.equals("presentation")) { 1519 // Presentation tag 1520 if (tag.isEnd) { 1521 removeTag(tag); 1522 1523 factory.processPresentation(myHS, 1524 tagName, 1525 defaultPresentation, 1526 displayViews, 1527 displayViewImages, 1528 size, 1529 location, 1530 presentationTitle, 1531 tagImage, 1532 toolbar, 1533 helpActions); 1534 1535 tagName = null; 1536 defaultPresentation = false; 1537 displayViews = true; 1538 displayViewImages = true; 1539 size = null; 1540 location = null; 1541 presentationTitle = null; 1542 tagImage = null; 1543 toolbar = false; 1544 helpActions = null; 1545 1546 } else { 1547 if (! pname.equals("helpset")) { 1548 wrongParent(name, pname); 1549 } else { 1550 addTag(tag, locale); 1551 } 1552 } 1553 } else if (name.equals("size")) { 1554 // DATA tag 1555 if (tag.isEnd) { 1556 if (size == null) { 1557 size = new Dimension(width, height); 1558 } else { 1559 size.setSize(width, height); 1560 } 1561 width = 0; 1562 height = 0; 1563 if (!tag.isEmpty) { 1564 removeTag(tag); 1565 } 1566 } else { 1567 if (! pname.equals("presentation")) { 1568 wrongParent(name, pname); 1569 } else { 1570 addTag(tag, locale); 1571 size = new Dimension(); 1572 } 1573 } 1574 } else if (name.equals("location")) { 1575 // DATA tag 1576 if (tag.isEnd) { 1577 if (location == null) { 1578 location = new Point(x, y); 1579 } else { 1580 location.setLocation(x, y); 1581 } 1582 x = 0; 1583 y = 0; 1584 if (!tag.isEmpty) { 1585 removeTag(tag); 1586 } 1587 } else { 1588 if (! pname.equals("presentation")) { 1589 wrongParent(name, pname); 1590 } else { 1591 addTag(tag, locale); 1592 location = new Point(); 1593 } 1594 } 1595 } else if (name.equals("toolbar")) { 1596 // DATA tag 1597 if (tag.isEnd) { 1598 removeTag(tag); 1599 } else { 1600 if (! pname.equals("presentation")) { 1601 wrongParent(name, pname); 1602 } else { 1603 addTag(tag, locale); 1604 helpActions = new Vector(); 1605 toolbar = true; 1606 } 1607 } 1608 } else if (name.equals("helpaction")) { 1609 // DATA tag 1610 if (tag.isEnd) { 1611 removeTag(tag); 1612 if (helpAction != null) { 1613 Hashtable tmp = new Hashtable(); 1614 helpActions.add(new HelpSetFactory.HelpAction(helpAction, tmp)); 1615 if (helpActionImage != null) { 1616 tmp.put("image", helpActionImage); 1617 helpActionImage = null; 1618 } 1619 helpAction = null; 1620 } 1621 } else { 1622 if (! pname.equals("toolbar")) { 1623 wrongParent(name, pname); 1624 } else { 1625 addTag(tag, locale); 1626 } 1627 } 1628 } else if (name.equals("maps")) { 1629 // MAPS tag 1630 if (tag.isEnd) { 1631 removeTag(tag); 1632 } else { 1633 if (! pname.equals("helpset")) { 1634 wrongParent(name, pname); 1635 } else { 1636 addTag(tag, locale); 1637 } 1638 } 1639 } else if (name.equals("subhelpset")) { 1640 // SUBHELPSET tag 1641 1642 // Remove from stack if an empty tag 1643 if (tag.isEnd && !tag.isEmpty) { 1644 removeTag(tag); 1645 } else { 1646 // Add the tag if it isn't an inline tag 1647 if (!tag.isEmpty) { 1648 addTag(tag, locale); 1649 } 1650 // Process the tag 1651 factory.processSubHelpSet(myHS, ht); 1652 } 1653 } else if (name.equals("impl")) { 1654 // Presentation tag 1655 if (tag.isEnd) { 1656 removeTag(tag); 1657 // Nothing to do here. Everything is done while 1658 // processing the sub tags 1659 } else { 1660 if (! pname.equals("helpset")) { 1661 wrongParent(name, pname); 1662 } else { 1663 addTag(tag, locale); 1664 } 1665 } 1666 } else if (name.equals("helpsetregistry")) { 1667 if (tag.isEnd && !tag.isEmpty) { 1668 removeTag(tag); 1669 } else { 1670 if (! pname.equals("impl")) { 1671 wrongParent(name, pname); 1672 } else { 1673 if (!tag.isEnd) { 1674 addTag(tag, locale); 1675 } 1676 if (attr != null) { 1677 String hbClass = attr.getProperty("helpbrokerclass"); 1678 if (hbClass != null) { 1679 myHS.setKeyData(implRegistry, 1680 helpBrokerClass, 1681 hbClass); 1682 } 1683 } 1684 } 1685 } 1686 } else if (name.equals("viewerregistry")) { 1687 if (tag.isEnd && !tag.isEmpty) { 1688 removeTag(tag); 1689 } else { 1690 if (! pname.equals("impl")) { 1691 wrongParent(name, pname); 1692 } else { 1693 if (!tag.isEnd) { 1694 addTag(tag, locale); 1695 } 1696 if (attr != null) { 1697 String viewerType = attr.getProperty("viewertype"); 1698 String viewerClass = attr.getProperty("viewerclass"); 1699 if (viewerType != null && viewerClass != null) { 1700 ClassLoader cl = HelpSet.class.getClassLoader(); 1701 myHS.setKeyData(kitTypeRegistry, 1702 viewerType, viewerClass); 1703 myHS.setKeyData(kitLoaderRegistry, 1704 viewerType, cl); 1705 } 1706 } 1707 } 1708 } 1709 } 1710 } 1711 piFound(ParserEvent e)1712 public void piFound(ParserEvent e) { 1713 factory.processPI(myHS, e.getTarget(), e.getData()); 1714 } 1715 doctypeFound(ParserEvent e)1716 public void doctypeFound(ParserEvent e) { 1717 factory.processDOCTYPE(e.getRoot(), e.getPublicId(), e.getSystemId()); 1718 } 1719 checkNull(String name, String t)1720 private void checkNull(String name, String t) { 1721 if (! t.equals("")) { 1722 parsingError("helpset.wrongText", name, t); 1723 } 1724 } 1725 textFound(ParserEvent e)1726 public void textFound(ParserEvent e) { 1727 debug("textFound: "); 1728 debug(" text: "+e.getText()); 1729 1730 if (tagStack.empty()) { 1731 return; // ignore 1732 } 1733 LangElement le = (LangElement) tagStack.peek(); 1734 Tag tag = le.getTag(); 1735 TagProperties attr = tag.atts; 1736 Hashtable ht = (attr == null) ? null : attr.getHashtable(); 1737 String text = e.getText().trim(); 1738 String name = tag.name; 1739 1740 if (name.equals("helpset")) { 1741 // HELPSET tag 1742 checkNull("helpset", text); 1743 return; 1744 } 1745 int depth = tagStack.size(); 1746 String pname = ""; 1747 if (depth >= 2) { 1748 le = (LangElement) tagStack.elementAt(depth-2); 1749 pname = ((Tag) le.getTag()).name; // the parent 1750 } 1751 1752 if (name.equals("title")) { 1753 // TITLE tag 1754 if (pname.equals("helpset")) { 1755 factory.processTitle(myHS, text); 1756 } else { 1757 presentationTitle = text.trim(); 1758 } 1759 } else if (name.equals("homeID")) { 1760 // HOMEID tag 1761 factory.processHomeID(myHS, text); 1762 } else if (name.equals("mapref")) { 1763 checkNull("mapref", text); 1764 } else if (name.equals("subhelpset")) { 1765 checkNull("subhelpset", text); 1766 } else if (name.equals("data")) { 1767 // DATA tag -- this is in a view 1768 viewData = text.trim(); 1769 } else if (name.equals("label")) { 1770 // LABEL tag -- this is in a view 1771 viewLabel = text.trim(); 1772 } else if (name.equals("name")) { 1773 // NAME tag -- this is in a view 1774 tagName = text.trim(); 1775 } else if (name.equals("helpaction")) { 1776 // NAME tag -- this is in a view 1777 helpAction = text.trim(); 1778 } else if (name.equals("type")) { 1779 // TYPE tag -- this is in a view 1780 viewType = text.trim(); 1781 } else if (name.equals("image")) { 1782 // IMAGE tag -- this is in the view 1783 tagImage = text.trim(); 1784 } else if (name.equals("view")) { 1785 // VIEW tag 1786 checkNull("view", text); 1787 } else if (name.equals("maps")) { 1788 // MAP tag 1789 checkNull("maps", text); 1790 } else if (name.equals("mergetype")) { 1791 checkNull("mergetype",text); 1792 } 1793 } 1794 1795 /** 1796 * Method used to parse a HelpSet. 1797 */ errorFound(ParserEvent e)1798 public void errorFound(ParserEvent e) { 1799 // Ignore it for now 1800 } 1801 1802 /** 1803 * Method used to parse a HelpSet. 1804 */ commentFound(ParserEvent e)1805 public void commentFound(ParserEvent e) { 1806 // Ignore it for now 1807 } 1808 1809 /** 1810 * addTag keeps track of tags and their locale attributes. 1811 */ addTag(Tag tag, Locale locale)1812 protected void addTag(Tag tag, Locale locale) { 1813 LangElement el = new LangElement(tag, locale); 1814 tagStack.push(el); 1815 // It's possible for lastLocale not be specified ergo null. 1816 // If it is then set lastLocale to null even if locale is null. 1817 // It is impossible for locale to be null 1818 if (lastLocale == null) { 1819 lastLocale = locale; 1820 return; 1821 } 1822 if (locale == null) { 1823 lastLocale = locale; 1824 return; 1825 } 1826 if (! lastLocale.equals(locale)) { 1827 lastLocale = locale; 1828 } 1829 } 1830 1831 /** 1832 * removeTag removes a tag from the tagStack. The tagStack is 1833 * used to keep track of tags and locales. 1834 */ removeTag(Tag tag)1835 protected void removeTag(Tag tag) { 1836 LangElement el; 1837 String name = tag.name; 1838 Locale newLocale = null; 1839 1840 for (;;) { 1841 if (tagStack.empty()) 1842 unbalanced(name); 1843 el = (LangElement) tagStack.pop(); 1844 if (el.getTag().name.equals(name)) { 1845 if (tagStack.empty()) { 1846 newLocale = defaultLocale; 1847 } else { 1848 el = (LangElement) tagStack.peek(); 1849 newLocale = el.getLocale(); 1850 } 1851 break; 1852 } 1853 } 1854 // It's possible for lastLocale not be specified ergo null. 1855 // If it is then set lastLocale to null even if locale is null. 1856 // It also possible for locale to be null so if lastLocale is set 1857 // then reset lastLocale to null; 1858 // Otherwise if lastLocale doesn't equal locale reset lastLocale to locale 1859 if (lastLocale == null) { 1860 lastLocale = newLocale; 1861 return; 1862 } 1863 if (newLocale == null) { 1864 lastLocale = newLocale; 1865 return; 1866 } 1867 if (! lastLocale.equals(newLocale)) { 1868 lastLocale = newLocale; 1869 } 1870 } 1871 1872 /** 1873 * Handy error message methods. 1874 */ 1875 parsingError(String key)1876 private void parsingError(String key) { 1877 String s = HelpUtilities.getText(key); 1878 factory.reportMessage(s, false); // tree will be wrong 1879 } 1880 parsingError(String key, String s)1881 private void parsingError(String key, String s) { 1882 String msg = HelpUtilities.getText(key, s); 1883 factory.reportMessage(msg, false); // tree will be wrong 1884 } 1885 parsingError(String key, String s1, String s2)1886 private void parsingError(String key, String s1, String s2) { 1887 String msg = HelpUtilities.getText(key, s1, s2); 1888 factory.reportMessage(msg, false); // tree will be wrong 1889 } 1890 wrongParent(String name, String pname)1891 private void wrongParent(String name, String pname) { 1892 parsingError("helpset.wrongParent", name, pname); 1893 } 1894 unbalanced(String name)1895 private void unbalanced(String name) { 1896 parsingError("helpset.unbalanced", name); 1897 } 1898 wrongLocale(Locale found, Locale l1, Locale l2)1899 private void wrongLocale(Locale found, Locale l1, Locale l2) { 1900 String msg = HelpUtilities.getText("helpset.wrongLocale", 1901 found.toString(), 1902 l1.toString(), 1903 l2.toString()); 1904 factory.reportMessage(msg, true); // will continue 1905 } 1906 } // End of HelpSetParser 1907 1908 /** 1909 * For printf debugging. 1910 */ 1911 private final static boolean debug = false; debug(String str)1912 private static void debug(String str) { 1913 if (debug) { 1914 System.out.println("HelpSet: " + str); 1915 } 1916 } 1917 } 1918