Package org.eclipse.help.internal.toc

Source Code of org.eclipse.help.internal.toc.TocManager

/*******************************************************************************
* Copyright (c) 2000, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.help.internal.toc;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Preferences;
import org.eclipse.help.AbstractTocProvider;
import org.eclipse.help.IToc;
import org.eclipse.help.ITocContribution;
import org.eclipse.help.ITopic;
import org.eclipse.help.internal.HelpData;
import org.eclipse.help.internal.HelpPlugin;
import org.eclipse.help.internal.Topic;
import org.eclipse.help.internal.UAElement;
import org.eclipse.help.internal.UAElementFactory;
import org.eclipse.help.internal.util.ProductPreferences;

/*
* Manages toc contributions (TocContribution) supplied by the various toc
* providers (AbstractTocProvider).
*/
public class TocManager {
 
  private static final String EXTENSION_POINT_ID_TOC = HelpPlugin.PLUGIN_ID + ".toc"; //$NON-NLS-1$
  private static final String ELEMENT_NAME_TOC_PROVIDER = "tocProvider"; //$NON-NLS-1$
  private static final String ATTRIBUTE_NAME_CLASS = "class"; //$NON-NLS-1$
 
  private AbstractTocProvider[] tocProviders;
  private Map tocContributionsByLocale = new HashMap();
  private Map tocsByLocale = new HashMap();
  private Map tocsById = new HashMap();
  private Map tocsByTopic;
 
  /*
   * Returns all toc entries (complete books) for the given locale.
   */
  public synchronized Toc[] getTocs(String locale) {
    Toc[] tocs = (Toc[])tocsByLocale.get(locale);
    if (tocs == null) {
      TocContribution[] raw = getRootTocContributions(locale);
      TocContribution[] filtered = filterTocContributions(raw);
      TocContribution[] ordered = orderTocContributions(filtered);
      List orderedTocs = new ArrayList(ordered.length);
      for (int i=0;i<ordered.length;++i) {
        try {
          Toc toc = (Toc)ordered[i].getToc();
          orderedTocs.add(toc);
          tocsById.put(ordered[i].getId(), toc);
        }
        catch (Throwable t) {
          // log and skip
          String msg = "Error getting " + Toc.class.getName() + " from " + ITocContribution.class.getName() + ": " + ordered[i]; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
          HelpPlugin.logError(msg, t);
        }
      }
      tocs = (Toc[])orderedTocs.toArray(new Toc[orderedTocs.size()]);
      tocsByLocale.put(locale, tocs);
    }
    return tocs;
  }
 
  /*
   * Returns the toc whose toc contribution has the given id, for the
   * given locale.
   */
  public synchronized Toc getToc(String id, String locale) {
    getTocs(locale);
    return (Toc)tocsById.get(id);
  }
 
  public synchronized Toc getOwningToc(String href) {
    if (tocsByTopic == null) {
      tocsByTopic = new HashMap();
      Toc[] tocs = HelpPlugin.getTocManager().getTocs(Platform.getNL());
      for (int i=0;i<tocs.length;++i) {
        ITocContribution contribution = tocs[i].getTocContribution();
        String[] extraDocuments = contribution.getExtraDocuments();
        for (int j=0;j<extraDocuments.length;++j) {
          tocsByTopic.put(extraDocuments[j], tocs[i]);
        }
      }
    }
    return (Toc)tocsByTopic.get(href);
  }
 
  public synchronized Topic getTopic(String href) {
    Toc[] tocs = HelpPlugin.getTocManager().getTocs(Platform.getNL());
    for (int i=0;i<tocs.length;++i) {
      Topic topic = (Topic)tocs[i].getTopic(href);
      if (topic != null) {
        return topic;
      }
    }
    int index = href.indexOf('#');
    if (index != -1) {
      return getTopic(href.substring(0, index));
    }
    return null;
  }
 
  public synchronized int[] getTopicPath(String href) {
    Topic topic = getTopic(href);
    if (topic != null) {
      List path = new ArrayList();
      UAElement element = topic;
      while (!(element instanceof Toc)) {
        UAElement parent = element.getParentElement();
        path.add(new Integer(indexOf(parent, (Topic)element)));
        element = parent;
      }
      Toc[] tocs = getTocs(Platform.getNL());
      for (int i=0;i<tocs.length;++i) {
        if (tocs[i] == element) {
          path.add(new Integer(i));
          int[] array = new int[path.size()];
          for (int j=0;j<array.length;++j) {
            array[j] = ((Integer)path.get(array.length - 1 - j)).intValue();
          }
          return array;
        }
      }
    }
    // no path; not in toc
    return null;
  }
 
  /*
   * Returns the zero-based index at which the child topic is located under
   * the parent topic/toc.
   */
  private int indexOf(UAElement parent, Topic child) {
    ITopic[] children;
    if (parent instanceof Topic) {
      children = ((Topic)parent).getSubtopics();
    }
    else if (parent instanceof Toc) {
      children = ((Toc)parent).getTopics();
    }
    else {
      return -1;
    }
    for (int i=0;i<children.length;++i) {
      if (children[i] == child) {
        return i;
      }
    }
    return -1;
  }
 
  /*
   * Returns all toc contributions for the given locale, from all toc
   * providers.
   */
  public synchronized TocContribution[] getTocContributions(String locale) {
    TocContribution[] cached = (TocContribution[])tocContributionsByLocale.get(locale);
    if (cached == null) {
      List contributions = new ArrayList();
      AbstractTocProvider[] providers = getTocProviders();
      for (int i=0;i<providers.length;++i) {
        ITocContribution[] contrib;
        try {
          contrib = providers[i].getTocContributions(locale);
        }
        catch (Throwable t) {
          // log, and skip the offending provider
          String msg = "Error getting help table of contents data from provider: " + providers[i].getClass().getName() + " (skipping provider)"; //$NON-NLS-1$ //$NON-NLS-2$
          HelpPlugin.logError(msg, t);
          continue;
        }
       
        for (int j=0;j<contrib.length;++j) {
          TocContribution contribution = new TocContribution();
          contribution.setCategoryId(contrib[j].getCategoryId());
          contribution.setContributorId(contrib[j].getContributorId());
          contribution.setExtraDocuments(contrib[j].getExtraDocuments());
          contribution.setId(contrib[j].getId());
          contribution.setLocale(contrib[j].getLocale());
          contribution.setPrimary(contrib[j].isPrimary());
          IToc toc = contrib[j].getToc();
          contribution.setToc(toc instanceof Toc ? (Toc)toc : (Toc)UAElementFactory.newElement(toc));
          contributions.add(contribution);
        }
      }
      cached = (TocContribution[])contributions.toArray(new TocContribution[contributions.size()]);
      tocContributionsByLocale.put(locale, cached);
    }
    return cached;
  }

  /*
   * Clears all cached contributions, forcing the manager to query the
   * providers again next time a request is made.
   */
  public void clearCache() {
    tocContributionsByLocale.clear();
    tocsByLocale.clear();
    tocsById.clear();
    tocsByTopic = null;
  }

  /*
   * Internal hook for unit testing.
   */
  public AbstractTocProvider[] getTocProviders() {
    if (tocProviders == null) {
      List providers = new ArrayList();
      IExtensionRegistry registry = Platform.getExtensionRegistry();
      IConfigurationElement[] elements = registry.getConfigurationElementsFor(EXTENSION_POINT_ID_TOC);
      for (int i=0;i<elements.length;++i) {
        IConfigurationElement elem = elements[i];
        if (elem.getName().equals(ELEMENT_NAME_TOC_PROVIDER)) {
          try {
            AbstractTocProvider provider = (AbstractTocProvider)elem.createExecutableExtension(ATTRIBUTE_NAME_CLASS);
            providers.add(provider);
          }
          catch (CoreException e) {
            // log and skip
            String msg = "Error instantiating help table of contents provider class \"" + elem.getAttribute(ATTRIBUTE_NAME_CLASS) + '"'; //$NON-NLS-1$
            HelpPlugin.logError(msg, e);
          }
        }
      }
      tocProviders = (AbstractTocProvider[])providers.toArray(new AbstractTocProvider[providers.size()]);
    }
    return tocProviders;
  }

  /*
   * Internal hook for unit testing.
   */
  public void setTocProviders(AbstractTocProvider[] tocProviders) {
    this.tocProviders = tocProviders;
  }

  /*
   * Filters the given contributions according to product preferences. If
   * either the contribution's id or its category's id is listed in the
   * ignoredTocs, filter the contribution.
   */
  private TocContribution[] filterTocContributions(TocContribution[] unfiltered) {
    Set tocsToFilter = getIgnoredTocContributions();
    List filtered = new ArrayList();
    Set ignoredHrefs = new HashSet();
    Set notIgnoredHrefs = new HashSet();
    for (int i=0;i<unfiltered.length;++i) {
      Toc toc = (Toc)unfiltered[i].getToc();
      Set hrefs = toc.getHref2TopicMap().keySet();
      if (!tocsToFilter.contains(unfiltered[i].getId()) &&
          !tocsToFilter.contains(unfiltered[i].getCategoryId())) {
        filtered.add(unfiltered[i]);
        notIgnoredHrefs.addAll(hrefs);
      }
      else {
        ignoredHrefs.addAll(hrefs);
      }
    }
    return (TocContribution[])filtered.toArray(new TocContribution[filtered.size()]);
  }

  private TocContribution[] getRootTocContributions(String locale) {
    TocContribution[] contributions = getTocContributions(locale);
    List unassembled = new ArrayList(Arrays.asList(contributions));
    TocAssembler assembler = new TocAssembler();
    List assembled = assembler.assemble(unassembled);
    return (TocContribution[])assembled.toArray(new TocContribution[assembled.size()]);
  }
 
  private Set getIgnoredTocContributions() {
    HelpData helpData = HelpData.getProductHelpData();
    if (helpData != null) {
      return helpData.getHiddenTocs();
    }
    else {
      HashSet ignored = new HashSet();
      Preferences pref = HelpPlugin.getDefault().getPluginPreferences();
      String preferredTocs = pref.getString(HelpPlugin.IGNORED_TOCS_KEY);
      if (preferredTocs.length() > 0) {
        StringTokenizer suggestdOrderedInfosets = new StringTokenizer(preferredTocs, " ;,"); //$NON-NLS-1$
        while (suggestdOrderedInfosets.hasMoreTokens()) {
          ignored.add(suggestdOrderedInfosets.nextToken());
        }
      }
      return ignored;
    }
  }

  /*
   * Orders the given toc contributions by category and product preference.
   */
  private TocContribution[] orderTocContributions(TocContribution[] unorderedTocs) {
    // first categorize the TOCs
    List itemsToOrder = new ArrayList();
    Map categorized = categorizeTocs(Arrays.asList(unorderedTocs), itemsToOrder);
     
    // order them
    List orderedItems = ProductPreferences.getTocOrder(itemsToOrder);
     
    // replace with actual TocContribution or category
    orderedItems = substituteValues(orderedItems, categorized);
     
    // expand the categories
    orderedItems = expandCategories(orderedItems);
    return (TocContribution[])orderedItems.toArray(new TocContribution[orderedItems.size()]);
  }
 
  /*
   * Categorizes the given toc contributions into categories, or individual
   * toc contributions if no category (treated as a category of one). Returns
   * mapping from category id/toc id to category/toc. Order of categories/
   * tocs is returned via tocOrder.
   */
  private Map categorizeTocs(List tocs, List tocOrder) {
    Map categorized = new HashMap();
    Iterator iter = tocs.iterator();
    while (iter.hasNext()) {
      ITocContribution toc = (ITocContribution)iter.next();
      String categoryId;
      try {
        categoryId = toc.getCategoryId();
      }
      catch (Throwable t) {
        // log and skip
        String msg = "Error retrieving categoryId from " + ITocContribution.class.getName() + ": " + toc.getClass().getName(); //$NON-NLS-1$ //$NON-NLS-2$
        HelpPlugin.logError(msg, t);
        continue;
      }
      if (categoryId != null) {
        // it has a category, add it to the appropriate TocCategory
        TocCategory category = (TocCategory)categorized.get(categoryId);
        if (category == null) {
          // create categories as needed
          category = new TocCategory(categoryId);
          categorized.put(categoryId, category);
          tocOrder.add(categoryId);
        }
        category.add(toc);
      }
      else {
        // doesn't have a category; insert the TOC directly
        String id;
        try {
          id = toc.getId();
        }
        catch (Throwable t) {
          // log and skip
          String msg = "Error retrieving id from " + ITocContribution.class.getName() + ": " + toc.getClass().getName(); //$NON-NLS-1$ //$NON-NLS-2$
          HelpPlugin.logError(msg, t);
          continue;
        }
        categorized.put(id, toc);
        tocOrder.add(id);
      }
    }
    return categorized;
  }
 
  /*
   * Expands all categories in the given list to actual toc contributions
   * organized by category.
   */
  private List expandCategories(List entries) {
    List expanded = new ArrayList();
    Iterator iter = entries.iterator();
    while (iter.hasNext()) {
      Object entry = iter.next();
      if (entry instanceof ITocContribution) {
        expanded.add(entry);
      }
      else if (entry instanceof TocCategory) {
        expanded.addAll((TocCategory)entry);
      }
    }
    return expanded;
  }

  /*
   * Returns whether or not the toc for the given locale has been completely
   * loaded yet or not.
   */
  public boolean isTocLoaded(String locale) {
    return tocsByLocale.get(locale) != null;
  }
 
  /*
   * Substitutes each item with it's corresponding mapping from the map.
   * Original List is not modified.
   */
  private static List substituteValues(List items, Map map) {
    if (items != null && map != null) {
      List result = new ArrayList(items.size());
      Iterator iter = items.iterator();
      while (iter.hasNext()) {
        Object key = iter.next();
        Object value = map.get(key);
        if (value != null) {
          result.add(value);
        }
      }
      return result;
    }
    return null;
  }
   
  /*
   * A category of tocs. A category has an id and a list of contained
   * tocs.
   */
  private static class TocCategory extends ArrayList {
   
    private static final long serialVersionUID = 1L;
    private String id;
   
    /**
     * Constructs a new empty TOC category with the given id.
     *
     * @param id the category's id
     */
    public TocCategory(String id) {
      this.id = id;
    }
   
    /**
     * Returns the category's id.
     *
     * @return the id of the category
     */
    public String getId() {
      return id;
    }
  }
}
TOP

Related Classes of org.eclipse.help.internal.toc.TocManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.