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.ListIterator ; 20 import java.util.Map ; 21 import java.util.Set ; 22 23 import org.eclipse.help.ITocContribution; 24 import org.eclipse.help.IUAElement; 25 import org.eclipse.help.internal.Anchor; 26 import org.eclipse.help.internal.HelpPlugin; 27 import org.eclipse.help.internal.Topic; 28 import org.eclipse.help.internal.UAElement; 29 import org.eclipse.help.internal.dynamic.DocumentProcessor; 30 import org.eclipse.help.internal.dynamic.DocumentReader; 31 import org.eclipse.help.internal.dynamic.ExtensionHandler; 32 import org.eclipse.help.internal.dynamic.IncludeHandler; 33 import org.eclipse.help.internal.dynamic.ProcessorHandler; 34 import org.eclipse.help.internal.dynamic.ValidationHandler; 35 36 40 public class TocAssembler { 41 42 private DocumentProcessor processor; 43 private ProcessorHandler[] handlers; 44 45 private Map anchorsByContributionId; 46 private List contributions; 47 private Map contributionsById; 48 private Map contributionsByLinkTo; 49 private Set processedContributions; 50 private Map requiredAttributes; 51 52 56 public List assemble(List contributions) { 57 this.contributions = contributions; 58 anchorsByContributionId = null; 59 contributionsById = null; 60 contributionsByLinkTo = null; 61 processedContributions = null; 62 63 List books = getBooks(); 64 Iterator iter = books.iterator(); 65 while (iter.hasNext()) { 66 TocContribution book = (TocContribution)iter.next(); 67 process(book); 68 } 69 return books; 70 } 71 72 82 private List getBooks() { 83 Set linkedContributionIds = getLinkedContributionIds(contributions); 84 List books = new ArrayList (); 85 Iterator iter = contributions.iterator(); 86 while (iter.hasNext()) { 87 TocContribution contrib = (TocContribution)iter.next(); 88 if (contrib.isPrimary() && !hasValidLinkTo(contrib) && !linkedContributionIds.contains(contrib.getId())) { 89 books.add(contrib); 90 } 91 } 92 return books; 93 } 94 95 100 private Set getLinkedContributionIds(List contributions) { 101 if (processor == null) { 102 processor = new DocumentProcessor(); 103 } 104 final Set linkedContributionIds = new HashSet (); 105 ProcessorHandler[] linkFinder = new ProcessorHandler[] { 106 new ValidationHandler(getRequiredAttributes()), 107 new ProcessorHandler() { 108 public short handle(UAElement element, String id) { 109 if (element instanceof Link) { 110 Link link = (Link)element; 111 String toc = link.getToc(); 112 if (toc != null) { 113 TocContribution srcContribution = getContribution(id); 114 linkedContributionIds.add(HrefUtil.normalizeHref(srcContribution.getContributorId(), toc)); 115 } 116 } 117 return UNHANDLED; 118 } 119 } 120 }; 121 processor.setHandlers(linkFinder); 122 ListIterator iter = contributions.listIterator(); 123 while (iter.hasNext()) { 124 TocContribution contrib = (TocContribution)iter.next(); 125 try { 126 processor.process((Toc)contrib.getToc(), contrib.getId()); 127 } 128 catch (Throwable t) { 129 iter.remove(); 130 String msg = "Error processing help table of contents: " + contrib.getId() + " (skipping)"; HelpPlugin.logError(msg, t); 132 } 133 } 134 return linkedContributionIds; 135 } 136 137 141 private boolean hasAnchor(String tocContributionId, String anchorId) { 142 TocContribution contrib = getContribution(tocContributionId); 143 if (contrib != null) { 144 process(contrib); 145 if (anchorsByContributionId != null) { 146 Set anchors = (Set )anchorsByContributionId.get(tocContributionId); 147 if (anchors != null) { 148 return anchors.contains(anchorId); 149 } 150 } 151 } 152 return false; 154 } 155 156 160 private boolean hasValidLinkTo(TocContribution contrib) { 161 String linkTo = contrib.getLinkTo(); 162 if (linkTo != null) { 163 String normalized = HrefUtil.normalizeHref(contrib.getContributorId(), linkTo); 164 int index = normalized.indexOf('#'); 165 if (index != -1) { 166 String id = normalized.substring(0, index); 167 String anchorId = normalized.substring(index + 1); 168 return hasAnchor(id, anchorId); 169 } 170 } 171 return false; 172 } 173 174 185 private void process(ITocContribution contribution) { 186 if (processedContributions == null) { 187 processedContributions = new HashSet (); 188 } 189 if (!processedContributions.contains(contribution)) { 191 if (processor == null) { 192 processor = new DocumentProcessor(); 193 } 194 if (handlers == null) { 195 DocumentReader reader = new DocumentReader(); 196 handlers = new ProcessorHandler[] { 197 new NormalizeHandler(), 198 new LinkHandler(), 199 new AnchorHandler(), 200 new IncludeHandler(reader, contribution.getLocale()), 201 new ExtensionHandler(reader, contribution.getLocale()), 202 }; 203 } 204 processor.setHandlers(handlers); 205 processor.process((Toc)contribution.getToc(), contribution.getId()); 206 processedContributions.add(contribution); 207 } 208 } 209 210 213 private TocContribution getContribution(String id) { 214 if (contributionsById == null) { 215 contributionsById = new HashMap (); 216 Iterator iter = contributions.iterator(); 217 while (iter.hasNext()) { 218 TocContribution contribution = (TocContribution)iter.next(); 219 contributionsById.put(contribution.getId(), contribution); 220 } 221 } 222 return (TocContribution)contributionsById.get(id); 223 } 224 225 230 private TocContribution[] getAnchorContributions(String anchorPath) { 231 if (contributionsByLinkTo == null) { 232 contributionsByLinkTo = new HashMap (); 233 Iterator iter = contributions.iterator(); 234 while (iter.hasNext()) { 235 TocContribution srcContribution = (TocContribution)iter.next(); 236 String linkTo = srcContribution.getLinkTo(); 237 if (linkTo != null) { 238 String destAnchorPath = HrefUtil.normalizeHref(srcContribution.getContributorId(), linkTo); 239 ITocContribution[] array = (ITocContribution[])contributionsByLinkTo.get(destAnchorPath); 240 if (array == null) { 241 array = new TocContribution[] { srcContribution }; 242 } 243 else { 244 TocContribution[] temp = new TocContribution[array.length + 1]; 245 System.arraycopy(array, 0, temp, 0, array.length); 246 temp[array.length] = srcContribution; 247 array = temp; 248 } 249 contributionsByLinkTo.put(destAnchorPath, array); 250 } 251 } 252 } 253 TocContribution[] contributions = (TocContribution[])contributionsByLinkTo.get(anchorPath); 254 if (contributions == null) { 255 contributions = new TocContribution[0]; 256 } 257 return contributions; 258 } 259 260 private Map getRequiredAttributes() { 261 if (requiredAttributes == null) { 262 requiredAttributes = new HashMap (); 263 requiredAttributes.put(Toc.NAME, new String [] { Toc.ATTRIBUTE_LABEL }); 264 requiredAttributes.put(Topic.NAME, new String [] { Topic.ATTRIBUTE_LABEL }); 265 requiredAttributes.put("anchor", new String [] { "id" }); requiredAttributes.put("include", new String [] { "path" }); requiredAttributes.put("link", new String [] { "toc" }); } 269 return requiredAttributes; 270 } 271 272 275 private void addExtraDocuments(TocContribution contribution, String [] extraDocuments) { 276 if (extraDocuments.length > 0) { 277 String [] destExtraDocuments = contribution.getExtraDocuments(); 278 String [] combinedExtraDocuments; 279 if (destExtraDocuments.length == 0) { 280 combinedExtraDocuments = extraDocuments; 281 } 282 else { 283 Set set = new HashSet (); 284 set.addAll(Arrays.asList(destExtraDocuments)); 285 set.addAll(Arrays.asList(extraDocuments)); 286 combinedExtraDocuments = (String [])set.toArray(new String [set.size()]); 287 } 288 contribution.setExtraDocuments(combinedExtraDocuments); 289 } 290 } 291 292 296 private class LinkHandler extends ProcessorHandler { 297 public short handle(UAElement element, String id) { 298 if (element instanceof Link) { 299 Link link = (Link)element; 300 UAElement parent = link.getParentElement(); 301 if (parent != null) { 302 String toc = link.getToc(); 303 if (toc != null) { 304 TocContribution destContribution = getContribution(id); 305 TocContribution srcContribution = getContribution(HrefUtil.normalizeHref(destContribution.getContributorId(), toc)); 306 if (srcContribution != null) { 307 process(srcContribution); 308 IUAElement[] children = srcContribution.getToc().getChildren(); 309 for (int i=0;i<children.length;++i) { 310 parent.insertBefore((UAElement)children[i], link); 311 } 312 addExtraDocuments(destContribution, srcContribution.getExtraDocuments()); 313 } 314 parent.removeChild(link); 315 } 316 } 317 return HANDLED_SKIP; 318 } 319 return UNHANDLED; 320 } 321 } 322 323 327 private class AnchorHandler extends ProcessorHandler { 328 public short handle(UAElement element, String id) { 329 if (element instanceof Anchor) { 330 Anchor anchor = (Anchor)element; 331 UAElement parent = anchor.getParentElement(); 332 if (parent != null) { 333 String anchorId = anchor.getId(); 334 if (anchorId != null) { 335 if (anchorsByContributionId == null) { 337 anchorsByContributionId = new HashMap (); 338 } 339 Set set = (Set )anchorsByContributionId.get(id); 340 if (set == null) { 341 set = new HashSet (); 342 anchorsByContributionId.put(id, set); 343 } 344 set.add(anchorId); 345 346 TocContribution destContribution = getContribution(id); 348 if (destContribution != null) { 349 TocContribution[] srcContributions = getAnchorContributions(destContribution.getId() + '#' + anchorId); 350 for (int i=0;i<srcContributions.length;++i) { 351 process(srcContributions[i]); 352 IUAElement[] children = srcContributions[i].getToc().getChildren(); 353 for (int j=0;j<children.length;++j) { 354 parent.insertBefore((UAElement)children[j], anchor); 355 } 356 addExtraDocuments(destContribution, srcContributions[i].getExtraDocuments()); 357 } 358 } 359 } 360 } 361 } 362 return UNHANDLED; 364 } 365 } 366 367 371 private class NormalizeHandler extends ProcessorHandler { 372 public short handle(UAElement element, String id) { 373 if (element instanceof Topic) { 374 Topic topic = (Topic)element; 375 String href = topic.getHref(); 376 if (href != null) { 377 topic.setHref(normalize(href, id)); 378 } 379 return HANDLED_CONTINUE; 380 } 381 else if (element instanceof Toc) { 382 Toc toc = (Toc)element; 383 toc.setHref(id); 384 String topic = toc.getTopic(); 385 if (topic != null) { 386 toc.setTopic(normalize(topic, id)); 387 } 388 return HANDLED_CONTINUE; 389 } 390 return UNHANDLED; 391 } 392 393 private String normalize(String href, String id) { 394 ITocContribution contribution = getContribution(id); 395 if (contribution != null) { 396 String pluginId = contribution.getContributorId(); 397 return HrefUtil.normalizeHref(pluginId, href); 398 } 399 else { 400 int index = id.indexOf('/', 1); 401 if (index != -1) { 402 String pluginId = id.substring(1, index); 403 return HrefUtil.normalizeHref(pluginId, href); 404 } 405 } 406 return href; 407 } 408 } 409 } 410 | Popular Tags |