1 11 package org.eclipse.help.internal.toc; 12 13 import java.util.ArrayList ; 14 import java.util.Arrays ; 15 import java.util.HashMap ; 16 import java.util.HashSet ; 17 import java.util.Iterator ; 18 import java.util.List ; 19 import java.util.Map ; 20 import java.util.Set ; 21 import java.util.StringTokenizer ; 22 23 import org.eclipse.core.runtime.CoreException; 24 import org.eclipse.core.runtime.IConfigurationElement; 25 import org.eclipse.core.runtime.IExtensionRegistry; 26 import org.eclipse.core.runtime.Platform; 27 import org.eclipse.core.runtime.Preferences; 28 import org.eclipse.help.AbstractTocProvider; 29 import org.eclipse.help.IToc; 30 import org.eclipse.help.ITocContribution; 31 import org.eclipse.help.ITopic; 32 import org.eclipse.help.internal.HelpData; 33 import org.eclipse.help.internal.HelpPlugin; 34 import org.eclipse.help.internal.Topic; 35 import org.eclipse.help.internal.UAElement; 36 import org.eclipse.help.internal.UAElementFactory; 37 import org.eclipse.help.internal.util.ProductPreferences; 38 39 43 public class TocManager { 44 45 private static final String EXTENSION_POINT_ID_TOC = HelpPlugin.PLUGIN_ID + ".toc"; private static final String ELEMENT_NAME_TOC_PROVIDER = "tocProvider"; private static final String ATTRIBUTE_NAME_CLASS = "class"; 49 private AbstractTocProvider[] tocProviders; 50 private Map tocContributionsByLocale = new HashMap (); 51 private Map tocsByLocale = new HashMap (); 52 private Map tocsById = new HashMap (); 53 private Map tocsByTopic; 54 55 58 public synchronized Toc[] getTocs(String locale) { 59 Toc[] tocs = (Toc[])tocsByLocale.get(locale); 60 if (tocs == null) { 61 TocContribution[] raw = getRootTocContributions(locale); 62 TocContribution[] filtered = filterTocContributions(raw); 63 TocContribution[] ordered = orderTocContributions(filtered); 64 List orderedTocs = new ArrayList (ordered.length); 65 for (int i=0;i<ordered.length;++i) { 66 try { 67 Toc toc = (Toc)ordered[i].getToc(); 68 orderedTocs.add(toc); 69 tocsById.put(ordered[i].getId(), toc); 70 } 71 catch (Throwable t) { 72 String msg = "Error getting " + Toc.class.getName() + " from " + ITocContribution.class.getName() + ": " + ordered[i]; HelpPlugin.logError(msg, t); 75 } 76 } 77 tocs = (Toc[])orderedTocs.toArray(new Toc[orderedTocs.size()]); 78 tocsByLocale.put(locale, tocs); 79 } 80 return tocs; 81 } 82 83 87 public synchronized Toc getToc(String id, String locale) { 88 getTocs(locale); 89 return (Toc)tocsById.get(id); 90 } 91 92 public synchronized Toc getOwningToc(String href) { 93 if (tocsByTopic == null) { 94 tocsByTopic = new HashMap (); 95 Toc[] tocs = HelpPlugin.getTocManager().getTocs(Platform.getNL()); 96 for (int i=0;i<tocs.length;++i) { 97 ITocContribution contribution = tocs[i].getTocContribution(); 98 String [] extraDocuments = contribution.getExtraDocuments(); 99 for (int j=0;j<extraDocuments.length;++j) { 100 tocsByTopic.put(extraDocuments[j], tocs[i]); 101 } 102 } 103 } 104 return (Toc)tocsByTopic.get(href); 105 } 106 107 public synchronized Topic getTopic(String href) { 108 Toc[] tocs = HelpPlugin.getTocManager().getTocs(Platform.getNL()); 109 for (int i=0;i<tocs.length;++i) { 110 Topic topic = (Topic)tocs[i].getTopic(href); 111 if (topic != null) { 112 return topic; 113 } 114 } 115 int index = href.indexOf('#'); 116 if (index != -1) { 117 return getTopic(href.substring(0, index)); 118 } 119 return null; 120 } 121 122 public synchronized int[] getTopicPath(String href) { 123 Topic topic = getTopic(href); 124 if (topic != null) { 125 List path = new ArrayList (); 126 UAElement element = topic; 127 while (!(element instanceof Toc)) { 128 UAElement parent = element.getParentElement(); 129 path.add(new Integer (indexOf(parent, (Topic)element))); 130 element = parent; 131 } 132 Toc[] tocs = getTocs(Platform.getNL()); 133 for (int i=0;i<tocs.length;++i) { 134 if (tocs[i] == element) { 135 path.add(new Integer (i)); 136 int[] array = new int[path.size()]; 137 for (int j=0;j<array.length;++j) { 138 array[j] = ((Integer )path.get(array.length - 1 - j)).intValue(); 139 } 140 return array; 141 } 142 } 143 } 144 return null; 146 } 147 148 152 private int indexOf(UAElement parent, Topic child) { 153 ITopic[] children; 154 if (parent instanceof Topic) { 155 children = ((Topic)parent).getSubtopics(); 156 } 157 else if (parent instanceof Toc) { 158 children = ((Toc)parent).getTopics(); 159 } 160 else { 161 return -1; 162 } 163 for (int i=0;i<children.length;++i) { 164 if (children[i] == child) { 165 return i; 166 } 167 } 168 return -1; 169 } 170 171 175 public synchronized TocContribution[] getTocContributions(String locale) { 176 TocContribution[] cached = (TocContribution[])tocContributionsByLocale.get(locale); 177 if (cached == null) { 178 List contributions = new ArrayList (); 179 AbstractTocProvider[] providers = getTocProviders(); 180 for (int i=0;i<providers.length;++i) { 181 ITocContribution[] contrib; 182 try { 183 contrib = providers[i].getTocContributions(locale); 184 } 185 catch (Throwable t) { 186 String msg = "Error getting help table of contents data from provider: " + providers[i].getClass().getName() + " (skipping provider)"; HelpPlugin.logError(msg, t); 189 continue; 190 } 191 192 for (int j=0;j<contrib.length;++j) { 193 TocContribution contribution = new TocContribution(); 194 contribution.setCategoryId(contrib[j].getCategoryId()); 195 contribution.setContributorId(contrib[j].getContributorId()); 196 contribution.setExtraDocuments(contrib[j].getExtraDocuments()); 197 contribution.setId(contrib[j].getId()); 198 contribution.setLocale(contrib[j].getLocale()); 199 contribution.setPrimary(contrib[j].isPrimary()); 200 IToc toc = contrib[j].getToc(); 201 contribution.setToc(toc instanceof Toc ? (Toc)toc : (Toc)UAElementFactory.newElement(toc)); 202 contributions.add(contribution); 203 } 204 } 205 cached = (TocContribution[])contributions.toArray(new TocContribution[contributions.size()]); 206 tocContributionsByLocale.put(locale, cached); 207 } 208 return cached; 209 } 210 211 215 public void clearCache() { 216 tocContributionsByLocale.clear(); 217 tocsByLocale.clear(); 218 tocsById.clear(); 219 tocsByTopic = null; 220 } 221 222 225 public AbstractTocProvider[] getTocProviders() { 226 if (tocProviders == null) { 227 List providers = new ArrayList (); 228 IExtensionRegistry registry = Platform.getExtensionRegistry(); 229 IConfigurationElement[] elements = registry.getConfigurationElementsFor(EXTENSION_POINT_ID_TOC); 230 for (int i=0;i<elements.length;++i) { 231 IConfigurationElement elem = elements[i]; 232 if (elem.getName().equals(ELEMENT_NAME_TOC_PROVIDER)) { 233 try { 234 AbstractTocProvider provider = (AbstractTocProvider)elem.createExecutableExtension(ATTRIBUTE_NAME_CLASS); 235 providers.add(provider); 236 } 237 catch (CoreException e) { 238 String msg = "Error instantiating help table of contents provider class \"" + elem.getAttribute(ATTRIBUTE_NAME_CLASS) + '"'; HelpPlugin.logError(msg, e); 241 } 242 } 243 } 244 tocProviders = (AbstractTocProvider[])providers.toArray(new AbstractTocProvider[providers.size()]); 245 } 246 return tocProviders; 247 } 248 249 252 public void setTocProviders(AbstractTocProvider[] tocProviders) { 253 this.tocProviders = tocProviders; 254 } 255 256 261 private TocContribution[] filterTocContributions(TocContribution[] unfiltered) { 262 Set tocsToFilter = getIgnoredTocContributions(); 263 List filtered = new ArrayList (); 264 Set ignoredHrefs = new HashSet (); 265 Set notIgnoredHrefs = new HashSet (); 266 for (int i=0;i<unfiltered.length;++i) { 267 Toc toc = (Toc)unfiltered[i].getToc(); 268 Set hrefs = toc.getHref2TopicMap().keySet(); 269 if (!tocsToFilter.contains(unfiltered[i].getId()) && 270 !tocsToFilter.contains(unfiltered[i].getCategoryId())) { 271 filtered.add(unfiltered[i]); 272 notIgnoredHrefs.addAll(hrefs); 273 } 274 else { 275 ignoredHrefs.addAll(hrefs); 276 } 277 } 278 return (TocContribution[])filtered.toArray(new TocContribution[filtered.size()]); 279 } 280 281 private TocContribution[] getRootTocContributions(String locale) { 282 TocContribution[] contributions = getTocContributions(locale); 283 List unassembled = new ArrayList (Arrays.asList(contributions)); 284 TocAssembler assembler = new TocAssembler(); 285 List assembled = assembler.assemble(unassembled); 286 return (TocContribution[])assembled.toArray(new TocContribution[assembled.size()]); 287 } 288 289 private Set getIgnoredTocContributions() { 290 HelpData helpData = HelpData.getProductHelpData(); 291 if (helpData != null) { 292 return helpData.getHiddenTocs(); 293 } 294 else { 295 HashSet ignored = new HashSet (); 296 Preferences pref = HelpPlugin.getDefault().getPluginPreferences(); 297 String preferredTocs = pref.getString(HelpPlugin.IGNORED_TOCS_KEY); 298 if (preferredTocs.length() > 0) { 299 StringTokenizer suggestdOrderedInfosets = new StringTokenizer (preferredTocs, " ;,"); while (suggestdOrderedInfosets.hasMoreTokens()) { 301 ignored.add(suggestdOrderedInfosets.nextToken()); 302 } 303 } 304 return ignored; 305 } 306 } 307 308 311 private TocContribution[] orderTocContributions(TocContribution[] unorderedTocs) { 312 List itemsToOrder = new ArrayList (); 314 Map categorized = categorizeTocs(Arrays.asList(unorderedTocs), itemsToOrder); 315 316 List orderedItems = ProductPreferences.getTocOrder(itemsToOrder); 318 319 orderedItems = substituteValues(orderedItems, categorized); 321 322 orderedItems = expandCategories(orderedItems); 324 return (TocContribution[])orderedItems.toArray(new TocContribution[orderedItems.size()]); 325 } 326 327 333 private Map categorizeTocs(List tocs, List tocOrder) { 334 Map categorized = new HashMap (); 335 Iterator iter = tocs.iterator(); 336 while (iter.hasNext()) { 337 ITocContribution toc = (ITocContribution)iter.next(); 338 String categoryId; 339 try { 340 categoryId = toc.getCategoryId(); 341 } 342 catch (Throwable t) { 343 String msg = "Error retrieving categoryId from " + ITocContribution.class.getName() + ": " + toc.getClass().getName(); HelpPlugin.logError(msg, t); 346 continue; 347 } 348 if (categoryId != null) { 349 TocCategory category = (TocCategory)categorized.get(categoryId); 351 if (category == null) { 352 category = new TocCategory(categoryId); 354 categorized.put(categoryId, category); 355 tocOrder.add(categoryId); 356 } 357 category.add(toc); 358 } 359 else { 360 String id; 362 try { 363 id = toc.getId(); 364 } 365 catch (Throwable t) { 366 String msg = "Error retrieving id from " + ITocContribution.class.getName() + ": " + toc.getClass().getName(); HelpPlugin.logError(msg, t); 369 continue; 370 } 371 categorized.put(id, toc); 372 tocOrder.add(id); 373 } 374 } 375 return categorized; 376 } 377 378 382 private List expandCategories(List entries) { 383 List expanded = new ArrayList (); 384 Iterator iter = entries.iterator(); 385 while (iter.hasNext()) { 386 Object entry = iter.next(); 387 if (entry instanceof ITocContribution) { 388 expanded.add(entry); 389 } 390 else if (entry instanceof TocCategory) { 391 expanded.addAll((TocCategory)entry); 392 } 393 } 394 return expanded; 395 } 396 397 401 public boolean isTocLoaded(String locale) { 402 return tocsByLocale.get(locale) != null; 403 } 404 405 409 private static List substituteValues(List items, Map map) { 410 if (items != null && map != null) { 411 List result = new ArrayList (items.size()); 412 Iterator iter = items.iterator(); 413 while (iter.hasNext()) { 414 Object key = iter.next(); 415 Object value = map.get(key); 416 if (value != null) { 417 result.add(value); 418 } 419 } 420 return result; 421 } 422 return null; 423 } 424 425 429 private static class TocCategory extends ArrayList { 430 431 private static final long serialVersionUID = 1L; 432 private String id; 433 434 439 public TocCategory(String id) { 440 this.id = id; 441 } 442 443 448 public String getId() { 449 return id; 450 } 451 } 452 } 453 | Popular Tags |