KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > help > internal > toc > TocManager


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.help.internal.toc;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.Map JavaDoc;
20 import java.util.Set JavaDoc;
21 import java.util.StringTokenizer JavaDoc;
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 /*
40  * Manages toc contributions (TocContribution) supplied by the various toc
41  * providers (AbstractTocProvider).
42  */

43 public class TocManager {
44     
45     private static final String JavaDoc EXTENSION_POINT_ID_TOC = HelpPlugin.PLUGIN_ID + ".toc"; //$NON-NLS-1$
46
private static final String JavaDoc ELEMENT_NAME_TOC_PROVIDER = "tocProvider"; //$NON-NLS-1$
47
private static final String JavaDoc ATTRIBUTE_NAME_CLASS = "class"; //$NON-NLS-1$
48

49     private AbstractTocProvider[] tocProviders;
50     private Map JavaDoc tocContributionsByLocale = new HashMap JavaDoc();
51     private Map JavaDoc tocsByLocale = new HashMap JavaDoc();
52     private Map JavaDoc tocsById = new HashMap JavaDoc();
53     private Map JavaDoc tocsByTopic;
54     
55     /*
56      * Returns all toc entries (complete books) for the given locale.
57      */

58     public synchronized Toc[] getTocs(String JavaDoc 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 JavaDoc orderedTocs = new ArrayList JavaDoc(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 JavaDoc t) {
72                     // log and skip
73
String JavaDoc msg = "Error getting " + Toc.class.getName() + " from " + ITocContribution.class.getName() + ": " + ordered[i]; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
74
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     /*
84      * Returns the toc whose toc contribution has the given id, for the
85      * given locale.
86      */

87     public synchronized Toc getToc(String JavaDoc id, String JavaDoc locale) {
88         getTocs(locale);
89         return (Toc)tocsById.get(id);
90     }
91     
92     public synchronized Toc getOwningToc(String JavaDoc href) {
93         if (tocsByTopic == null) {
94             tocsByTopic = new HashMap JavaDoc();
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 JavaDoc[] 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 JavaDoc 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 JavaDoc href) {
123         Topic topic = getTopic(href);
124         if (topic != null) {
125             List JavaDoc path = new ArrayList JavaDoc();
126             UAElement element = topic;
127             while (!(element instanceof Toc)) {
128                 UAElement parent = element.getParentElement();
129                 path.add(new Integer JavaDoc(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 JavaDoc(i));
136                     int[] array = new int[path.size()];
137                     for (int j=0;j<array.length;++j) {
138                         array[j] = ((Integer JavaDoc)path.get(array.length - 1 - j)).intValue();
139                     }
140                     return array;
141                 }
142             }
143         }
144         // no path; not in toc
145
return null;
146     }
147     
148     /*
149      * Returns the zero-based index at which the child topic is located under
150      * the parent topic/toc.
151      */

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     /*
172      * Returns all toc contributions for the given locale, from all toc
173      * providers.
174      */

175     public synchronized TocContribution[] getTocContributions(String JavaDoc locale) {
176         TocContribution[] cached = (TocContribution[])tocContributionsByLocale.get(locale);
177         if (cached == null) {
178             List JavaDoc contributions = new ArrayList JavaDoc();
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 JavaDoc t) {
186                     // log, and skip the offending provider
187
String JavaDoc msg = "Error getting help table of contents data from provider: " + providers[i].getClass().getName() + " (skipping provider)"; //$NON-NLS-1$ //$NON-NLS-2$
188
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     /*
212      * Clears all cached contributions, forcing the manager to query the
213      * providers again next time a request is made.
214      */

215     public void clearCache() {
216         tocContributionsByLocale.clear();
217         tocsByLocale.clear();
218         tocsById.clear();
219         tocsByTopic = null;
220     }
221
222     /*
223      * Internal hook for unit testing.
224      */

225     public AbstractTocProvider[] getTocProviders() {
226         if (tocProviders == null) {
227             List JavaDoc providers = new ArrayList JavaDoc();
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                         // log and skip
239
String JavaDoc msg = "Error instantiating help table of contents provider class \"" + elem.getAttribute(ATTRIBUTE_NAME_CLASS) + '"'; //$NON-NLS-1$
240
HelpPlugin.logError(msg, e);
241                     }
242                 }
243             }
244             tocProviders = (AbstractTocProvider[])providers.toArray(new AbstractTocProvider[providers.size()]);
245         }
246         return tocProviders;
247     }
248
249     /*
250      * Internal hook for unit testing.
251      */

252     public void setTocProviders(AbstractTocProvider[] tocProviders) {
253         this.tocProviders = tocProviders;
254     }
255
256     /*
257      * Filters the given contributions according to product preferences. If
258      * either the contribution's id or its category's id is listed in the
259      * ignoredTocs, filter the contribution.
260      */

261     private TocContribution[] filterTocContributions(TocContribution[] unfiltered) {
262         Set JavaDoc tocsToFilter = getIgnoredTocContributions();
263         List JavaDoc filtered = new ArrayList JavaDoc();
264         Set JavaDoc ignoredHrefs = new HashSet JavaDoc();
265         Set JavaDoc notIgnoredHrefs = new HashSet JavaDoc();
266         for (int i=0;i<unfiltered.length;++i) {
267             Toc toc = (Toc)unfiltered[i].getToc();
268             Set JavaDoc 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 JavaDoc locale) {
282         TocContribution[] contributions = getTocContributions(locale);
283         List JavaDoc unassembled = new ArrayList JavaDoc(Arrays.asList(contributions));
284         TocAssembler assembler = new TocAssembler();
285         List JavaDoc assembled = assembler.assemble(unassembled);
286         return (TocContribution[])assembled.toArray(new TocContribution[assembled.size()]);
287     }
288     
289     private Set JavaDoc getIgnoredTocContributions() {
290         HelpData helpData = HelpData.getProductHelpData();
291         if (helpData != null) {
292             return helpData.getHiddenTocs();
293         }
294         else {
295             HashSet JavaDoc ignored = new HashSet JavaDoc();
296             Preferences pref = HelpPlugin.getDefault().getPluginPreferences();
297             String JavaDoc preferredTocs = pref.getString(HelpPlugin.IGNORED_TOCS_KEY);
298             if (preferredTocs.length() > 0) {
299                 StringTokenizer JavaDoc suggestdOrderedInfosets = new StringTokenizer JavaDoc(preferredTocs, " ;,"); //$NON-NLS-1$
300
while (suggestdOrderedInfosets.hasMoreTokens()) {
301                     ignored.add(suggestdOrderedInfosets.nextToken());
302                 }
303             }
304             return ignored;
305         }
306     }
307
308     /*
309      * Orders the given toc contributions by category and product preference.
310      */

311     private TocContribution[] orderTocContributions(TocContribution[] unorderedTocs) {
312         // first categorize the TOCs
313
List JavaDoc itemsToOrder = new ArrayList JavaDoc();
314         Map JavaDoc categorized = categorizeTocs(Arrays.asList(unorderedTocs), itemsToOrder);
315             
316         // order them
317
List JavaDoc orderedItems = ProductPreferences.getTocOrder(itemsToOrder);
318             
319         // replace with actual TocContribution or category
320
orderedItems = substituteValues(orderedItems, categorized);
321             
322         // expand the categories
323
orderedItems = expandCategories(orderedItems);
324         return (TocContribution[])orderedItems.toArray(new TocContribution[orderedItems.size()]);
325     }
326     
327     /*
328      * Categorizes the given toc contributions into categories, or individual
329      * toc contributions if no category (treated as a category of one). Returns
330      * mapping from category id/toc id to category/toc. Order of categories/
331      * tocs is returned via tocOrder.
332      */

333     private Map JavaDoc categorizeTocs(List JavaDoc tocs, List JavaDoc tocOrder) {
334         Map JavaDoc categorized = new HashMap JavaDoc();
335         Iterator JavaDoc iter = tocs.iterator();
336         while (iter.hasNext()) {
337             ITocContribution toc = (ITocContribution)iter.next();
338             String JavaDoc categoryId;
339             try {
340                 categoryId = toc.getCategoryId();
341             }
342             catch (Throwable JavaDoc t) {
343                 // log and skip
344
String JavaDoc msg = "Error retrieving categoryId from " + ITocContribution.class.getName() + ": " + toc.getClass().getName(); //$NON-NLS-1$ //$NON-NLS-2$
345
HelpPlugin.logError(msg, t);
346                 continue;
347             }
348             if (categoryId != null) {
349                 // it has a category, add it to the appropriate TocCategory
350
TocCategory category = (TocCategory)categorized.get(categoryId);
351                 if (category == null) {
352                     // create categories as needed
353
category = new TocCategory(categoryId);
354                     categorized.put(categoryId, category);
355                     tocOrder.add(categoryId);
356                 }
357                 category.add(toc);
358             }
359             else {
360                 // doesn't have a category; insert the TOC directly
361
String JavaDoc id;
362                 try {
363                     id = toc.getId();
364                 }
365                 catch (Throwable JavaDoc t) {
366                     // log and skip
367
String JavaDoc msg = "Error retrieving id from " + ITocContribution.class.getName() + ": " + toc.getClass().getName(); //$NON-NLS-1$ //$NON-NLS-2$
368
HelpPlugin.logError(msg, t);
369                     continue;
370                 }
371                 categorized.put(id, toc);
372                 tocOrder.add(id);
373             }
374         }
375         return categorized;
376     }
377     
378     /*
379      * Expands all categories in the given list to actual toc contributions
380      * organized by category.
381      */

382     private List JavaDoc expandCategories(List JavaDoc entries) {
383         List JavaDoc expanded = new ArrayList JavaDoc();
384         Iterator JavaDoc iter = entries.iterator();
385         while (iter.hasNext()) {
386             Object JavaDoc 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     /*
398      * Returns whether or not the toc for the given locale has been completely
399      * loaded yet or not.
400      */

401     public boolean isTocLoaded(String JavaDoc locale) {
402         return tocsByLocale.get(locale) != null;
403     }
404     
405     /*
406      * Substitutes each item with it's corresponding mapping from the map.
407      * Original List is not modified.
408      */

409     private static List JavaDoc substituteValues(List JavaDoc items, Map JavaDoc map) {
410         if (items != null && map != null) {
411             List JavaDoc result = new ArrayList JavaDoc(items.size());
412             Iterator JavaDoc iter = items.iterator();
413             while (iter.hasNext()) {
414                 Object JavaDoc key = iter.next();
415                 Object JavaDoc value = map.get(key);
416                 if (value != null) {
417                     result.add(value);
418                 }
419             }
420             return result;
421         }
422         return null;
423     }
424         
425     /*
426      * A category of tocs. A category has an id and a list of contained
427      * tocs.
428      */

429     private static class TocCategory extends ArrayList JavaDoc {
430         
431         private static final long serialVersionUID = 1L;
432         private String JavaDoc id;
433         
434         /**
435          * Constructs a new empty TOC category with the given id.
436          *
437          * @param id the category's id
438          */

439         public TocCategory(String JavaDoc id) {
440             this.id = id;
441         }
442         
443         /**
444          * Returns the category's id.
445          *
446          * @return the id of the category
447          */

448         public String JavaDoc getId() {
449             return id;
450         }
451     }
452 }
453
Popular Tags