Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[eclipse-dev] Moving Existing Wizards and Categories to Other

Greetings all,

I've spent the last 4 days on this problem and I've learned a lot about the WizardRegistries, IExtensions, and IContributors, ConfigurationElementDescriptions, ConfigurationElementHandles, RegistryObjectManagers, etc., My team and I develop an Eclipse-based IDE. We've added our own Import and New Project Wizards and wish to move Wizards that aren't ours to the Other category, maintain the sub-tree structure (e.g. Other > C/C++ > C/C++ Project). The reason for moving them, is the wizard selector is quite crowded with different options; we want to make our wizards easier to find, while allowing the user to find these other wizards. My strategy is to iterate through the registry trees, cloning categories and moving wizards whose IDs didn't match my regex. Here are some of the things I've learned, problems I've encountered, and questions I still have:

* I've heard you can toggle visibility of a set of wizards from a single contributor will an activity. Is this true? Perhaps I should hide some of the project wizards we know our users will never use.

 * The trees from NewProjectWizardRegistry and ImportProjectWizardRegistry are very strange. They contained more than new project and import wizards, but seemed to have the most basic of wizards in its tree, such as new Header File, new Source File, etc. I eventually figured out that if you check the "project" attribute to equal "true," you can filter these out, but why include them in the first place? Their inclusion made me think it was the complete set of wizards, but upon closer inspection, the new project tree did not have import project wizards and vice versa (thank goodness!) But, why are these non-project wizards showing up? Shouldn't the extension points filter these out? 

* For the categories, I flatten the tree use recursion from the wizardRegistry.getRootCategory().getCategories(), to build List<IWizardCategory>. I iterate through the categories prepending to the ID a "movedWizards.". For each category's parent ID, I update it to "org.eclipse.ui.Other" if it was pointing to the root, or prepend the "movedWizards." ID. I leave the original category alone, but create a duplicate set with the "movedWizards" prepended to the namespace.
* Finally, for moving wizards, I am able to delete the wizard using the removeExtension(IExtension, Object[]) method, and I am able to re-add the wizard, however, it is a direct descendant to the Other category, despite setting correctly both the ID attribute of the category configurationElementDescription, and the category attribute of the wizard configurationElementDescription. In order to update the category on the wizard, I build a new ConfigurationElementDescription from the original IConfigurationElement, updating the category ID (you can see the code below  in the poorly named "moveCategory" method).

Is there anything obvious why the wizards aren't appearing under the categories cloned to the Other category? I've made sure they maintain the same contributor, in case that was also a factor. I feel like I'm close, but I'm missing a small detail. Anyone have any pointers?


P.S. Here are most methods I've written:

protected void run(Pattern filter) {
    // printTree(wizardRegistry.getRootCategory(), "");
    // Recursively Find all categories
    List<WizardCollectionElement> cats = flattenCategories(wizardRegistry.getRootCategory().getCategories());
    // Filter all wizards
    List<WorkbenchWizardElement> wizards = filterWizards(cats, filter);
    // Now that we have a copy of everything, let's start manipulating objects.

    // Clone all categories into this registry.
    // List<ConfigurationElementDescription> transformed = new
    // ArrayList<ConfigurationElementDescription>(cats.size() + wizards.size());
    for (WizardCollectionElement curr : cats) {
      if (curr.getId().equals(OTHER_ID)) {
      String newId = "movedWizards." + curr.getId();
      String parentId = curr.getParent().getId();
      if (parentId.equals("root")) {
        // top-level categories get cloned to the other category
        parentId = OTHER_ID;
      } else if (!parentId.equals(OTHER_ID)) {
        parentId = "movedWizards." + parentId;

      ConfigurationElementDescription cat = createNewCategory(newId, curr.getLabel(), parentId);

      printConfigurationElementDescription(cat, false);

      // transformed.add(cat);
      addExtension(cat, curr.getConfigurationElement().getContributor());

    // Move Wizards under the cloned categories
    for (WorkbenchWizardElement wizard : wizards) {

      if (!"true".equals(wizard.getConfigurationElement().getAttribute("project")) ||
        OTHER_ID.equals(wizard.getCategory().getId())) {
        // Skip non-projects, or projects already in the Other category

      String newParent = "movedWizards." + wizard.getConfigurationElement().getAttribute(TAG_CATEGORY);
      ConfigurationElementDescription w = moveWizard(wizard.getConfigurationElement(), TAG_CATEGORY, newParent);
      wizardRegistry.removeExtension(wizard.getConfigurationElement().getDeclaringExtension(), new Object[] { wizard });
      printConfigurationElementDescription(w, false);

      addExtension(w, wizard.getConfigurationElement().getContributor());
      // transformed.add(w);

    // addExtension(transformed);

private List<WorkbenchWizardElement> filterWizards(List<WizardCollectionElement> cats, Pattern filter) {

    List<WorkbenchWizardElement> res = new ArrayList<WorkbenchWizardElement>(cats.size());
    for (WizardCollectionElement cat : cats) {
      for (IWizardDescriptor curr : cat.getWizards()) {
        if (!(curr instanceof WorkbenchWizardElement)) {
        WorkbenchWizardElement wizard = (WorkbenchWizardElement) curr;
        if (!filter.matcher(wizard.getId()).matches()) {
        } else {
          IConfigurationElement elem = wizard.getConfigurationElement();
          System.out.print("SKIPPING ");
    return res;

  public List<WizardCollectionElement> flattenCategories(IWizardCategory[] list) {

    List<WizardCollectionElement> res = new ArrayList<WizardCollectionElement>(list.length);
    for (IWizardCategory curr : list) {
      if (!(curr instanceof WizardCollectionElement)) {
        logger.error("Unable to clone wizard category because it wasn't cast right: " + curr.getLabel());
      res.add((WizardCollectionElement) curr);
    return res;

  private ConfigurationElementDescription createNewCategory(String id, String name, String parentId) {
    int len = (parentId == null) ? 2 : 3;
    ConfigurationElementAttribute[] atts = new ConfigurationElementAttribute[len];
    atts[0] = new ConfigurationElementAttribute("id", id);
    atts[1] = new ConfigurationElementAttribute("name", name);
    if ( parentId != null) {
      atts[2] = new ConfigurationElementAttribute("parentCategory", parentId);
    return new ConfigurationElementDescription(TAG_CATEGORY, atts, null, null);

  private ConfigurationElementDescription moveWizard(IConfigurationElement orig, String needle, String newValue) {
    Boolean shouldUpdateProp = needle != null && needle.length() > 0;

    String[] props = orig.getAttributeNames();
    ConfigurationElementAttribute[] atts = new ConfigurationElementAttribute[props.length];

    for (int idx = 0; idx < atts.length; idx++) {
      String propValue = orig.getAttribute(props[idx]);

      if (shouldUpdateProp && needle.equals(props[idx])) {
        propValue = newValue;

      atts[idx] = new ConfigurationElementAttribute(props[idx], propValue);
    return new ConfigurationElementDescription(IWorkbenchRegistryConstants.TAG_WIZARD, atts, null, null);

  private void addExtension(ConfigurationElementDescription description, IContributor contributor) {
    Object token = extensionRegistry.getTemporaryUserToken();
    extensionRegistry.addExtension("", contributor, false, "", extensionPointId, description, token);

Back to the top