public static boolean processAddition(
     final MMenu menuModel,
     final ArrayList<MMenuElement> menuContributionsToRemove,
     MMenuContribution menuContribution,
     final HashSet<String> existingMenuIds,
     HashSet<String> existingSeparatorNames) {
   int idx = getIndex(menuModel, menuContribution.getPositionInParent());
   if (idx == -1) {
     return false;
   }
   for (MMenuElement item : menuContribution.getChildren()) {
     if (item instanceof MMenu && existingMenuIds.contains(item.getElementId())) {
       // skip this, it's already there
       continue;
     } else if (item instanceof MMenuSeparator
         && existingSeparatorNames.contains(item.getElementId())) {
       // skip this, it's already there
       continue;
     }
     MMenuElement copy = (MMenuElement) EcoreUtil.copy((EObject) item);
     if (DEBUG) {
       trace("addMenuContribution " + copy, menuModel.getWidget(), menuModel); // $NON-NLS-1$
     }
     menuContributionsToRemove.add(copy);
     menuModel.getChildren().add(idx++, copy);
     if (copy instanceof MMenu && copy.getElementId() != null) {
       existingMenuIds.add(copy.getElementId());
     } else if (copy instanceof MMenuSeparator && copy.getElementId() != null) {
       existingSeparatorNames.add(copy.getElementId());
     }
   }
   return true;
 }
 public static void gatherMenuContributions(
     final MMenu menuModel,
     final List<MMenuContribution> menuContributionList,
     final String id,
     final ArrayList<MMenuContribution> toContribute,
     final ExpressionContext eContext,
     boolean includePopups) {
   if (id == null || id.length() == 0) {
     return;
   }
   boolean menuBar = (((MUIElement) ((EObject) menuModel).eContainer()) instanceof MWindow);
   for (MMenuContribution menuContribution : menuContributionList) {
     String parentID = menuContribution.getParentId();
     if (parentID == null) {
       // it doesn't make sense for this to be null, temporary workaround for bug 320790
       continue;
     }
     boolean popup =
         parentID.equals(POPUP_PARENT_ID) && (menuModel instanceof MPopupMenu) && includePopups;
     boolean filtered = isFiltered(menuModel, menuContribution, includePopups);
     if (filtered || (!popup && !parentID.equals(id)) || !menuContribution.isToBeRendered()) {
       continue;
     }
     if (menuBar || isVisible(menuContribution, eContext)) {
       toContribute.add(menuContribution);
     }
   }
 }
 public static void printContributions(ArrayList<MMenuContribution> contributions) {
   for (MMenuContribution c : contributions) {
     trace("\n" + c, null); // $NON-NLS-1$
     for (MMenuElement element : c.getChildren()) {
       printElement(1, element);
     }
   }
 }
 static boolean isFiltered(
     MMenu menuModel, MMenuContribution menuContribution, boolean includePopups) {
   if (includePopups || menuModel.getTags().contains(ContributionsAnalyzer.MC_POPUP)) {
     return !menuContribution.getTags().contains(ContributionsAnalyzer.MC_POPUP)
         && menuContribution.getTags().contains(ContributionsAnalyzer.MC_MENU);
   }
   if (menuModel.getTags().contains(ContributionsAnalyzer.MC_MENU)) {
     return !menuContribution.getTags().contains(ContributionsAnalyzer.MC_MENU)
         && menuContribution.getTags().contains(ContributionsAnalyzer.MC_POPUP);
   }
   if (!includePopups) {
     // not including popups, so filter out popup menu contributions if the menu is a regular
     // menu
     return menuContribution.getTags().contains(ContributionsAnalyzer.MC_POPUP);
   }
   return false;
 }
 /** @param contribution */
 private void processMenuContribution(MMenuContribution contribution) {
   for (MMenuElement elmt : contribution.getChildren()) {
     if (elmt instanceof MMenu) {
       redirectHandledMenuItems((MMenu) elmt);
     } else if (elmt instanceof MMenuItem) {
       redirectHandledMenuItem((MMenuItem) elmt);
     }
   }
 }
 public void mergeIntoModel(
     ArrayList<MMenuContribution> menuContributions,
     ArrayList<MToolBarContribution> toolBarContributions,
     ArrayList<MTrimContribution> trimContributions) {
   if (location.getPath() == null || location.getPath().length() == 0) {
     WorkbenchPlugin.log(
         "MenuFactoryGenerator.mergeIntoModel: Invalid menu URI: " + location); // $NON-NLS-1$
     return;
   }
   if (inToolbar()) {
     if (MenuAdditionCacheEntry.isInWorkbenchTrim(location)) {
       // processTrimChildren(trimContributions, toolBarContributions,
       // configElement);
     } else {
       String query = location.getQuery();
       if (query == null || query.length() == 0) {
         query = "after=additions"; // $NON-NLS-1$
       }
       processToolbarChildren(toolBarContributions, configElement, location.getPath(), query);
     }
     return;
   }
   MMenuContribution menuContribution = MenuFactoryImpl.eINSTANCE.createMenuContribution();
   String idContrib = MenuHelper.getId(configElement);
   if (idContrib != null && idContrib.length() > 0) {
     menuContribution.setElementId(idContrib);
   }
   if ("org.eclipse.ui.popup.any".equals(location.getPath())) { // $NON-NLS-1$
     menuContribution.setParentId("popup"); // $NON-NLS-1$
   } else {
     menuContribution.setParentId(location.getPath());
   }
   String query = location.getQuery();
   if (query == null || query.length() == 0) {
     query = "after=additions"; // $NON-NLS-1$
   }
   menuContribution.setPositionInParent(query);
   menuContribution.getTags().add("scheme:" + location.getScheme()); // $NON-NLS-1$
   String filter = ContributionsAnalyzer.MC_MENU;
   if ("popup".equals(location.getScheme())) { // $NON-NLS-1$
     filter = ContributionsAnalyzer.MC_POPUP;
   }
   menuContribution.getTags().add(filter);
   menuContribution.setVisibleWhen(MenuHelper.getVisibleWhen(configElement));
   ContextFunction generator = new ContributionFactoryGenerator(configElement, 0);
   menuContribution.getTransientData().put(ContributionRecord.FACTORY, generator);
   menuContributions.add(menuContribution);
 }
 public static void XXXgatherMenuContributions(
     final MMenu menuModel,
     final List<MMenuContribution> menuContributionList,
     final String id,
     final ArrayList<MMenuContribution> toContribute,
     final ExpressionContext eContext,
     boolean includePopups) {
   if (id == null || id.length() == 0) {
     return;
   }
   ArrayList<String> popupIds = new ArrayList<String>();
   if (includePopups) {
     popupIds.add(id);
     for (String tag : menuModel.getTags()) {
       if (tag.startsWith("popup:")) { // $NON-NLS-1$
         String tmp = tag.substring("popup:".length()); // $NON-NLS-1$
         if (!popupIds.contains(tmp)) {
           popupIds.add(tmp);
         }
       }
     }
   }
   for (MMenuContribution menuContribution : menuContributionList) {
     String parentID = menuContribution.getParentId();
     if (parentID == null) {
       // it doesn't make sense for this to be null, temporary workaround for bug 320790
       continue;
     }
     boolean popupTarget = includePopups && popupIds.contains(parentID);
     boolean popupAny =
         includePopups && menuModel instanceof MPopupMenu && POPUP_PARENT_ID.equals(parentID);
     boolean filtered = isFiltered(menuModel, menuContribution, includePopups);
     if (filtered
         || (!popupAny && !popupTarget && !parentID.equals(id))
         || !menuContribution.isToBeRendered()) {
       continue;
     }
     toContribute.add(menuContribution);
   }
 }
 public MenuKey(MMenuContribution mc) {
   super(
       mc.getParentId(),
       mc.getPositionInParent(),
       mc.getTags(),
       (MCoreExpression) mc.getVisibleWhen(),
       mc.getTransientData().get(FACTORY));
   this.contribution = mc;
   mc.setWidget(this);
 }
 public static void mergeContributions(
     ArrayList<MMenuContribution> contributions, ArrayList<MMenuContribution> result) {
   HashMap<MenuKey, ArrayList<MMenuContribution>> buckets =
       new HashMap<MenuKey, ArrayList<MMenuContribution>>();
   trace("mergeContributions size: " + contributions.size(), null); // $NON-NLS-1$
   printContributions(contributions);
   // first pass, sort by parentId?position,scheme,visibleWhen
   for (MMenuContribution contribution : contributions) {
     MenuKey key = getKey(contribution);
     ArrayList<MMenuContribution> slot = buckets.get(key);
     if (slot == null) {
       slot = new ArrayList<MMenuContribution>();
       buckets.put(key, slot);
     }
     slot.add(contribution);
   }
   Iterator<MMenuContribution> i = contributions.iterator();
   while (i.hasNext() && !buckets.isEmpty()) {
     MMenuContribution contribution = i.next();
     MenuKey key = getKey(contribution);
     ArrayList<MMenuContribution> slot = buckets.remove(key);
     if (slot == null) {
       continue;
     }
     MMenuContribution toContribute = null;
     for (MMenuContribution item : slot) {
       if (toContribute == null) {
         toContribute = item;
         continue;
       }
       Object[] array = item.getChildren().toArray();
       for (int c = 0; c < array.length; c++) {
         MMenuElement me = (MMenuElement) array[c];
         if (!containsMatching(toContribute.getChildren(), me)) {
           toContribute.getChildren().add(me);
         }
       }
     }
     if (toContribute != null) {
       toContribute.setWidget(null);
       result.add(toContribute);
     }
   }
   trace("mergeContributions: final size: " + result.size(), null); // $NON-NLS-1$
 }
 private static MenuKey getKey(MMenuContribution contribution) {
   if (contribution.getWidget() instanceof MenuKey) {
     return (MenuKey) contribution.getWidget();
   }
   return new MenuKey(contribution);
 }
 public static boolean isVisible(MMenuContribution menuContribution, ExpressionContext eContext) {
   if (menuContribution.getVisibleWhen() == null) {
     return true;
   }
   return isVisible((MCoreExpression) menuContribution.getVisibleWhen(), eContext);
 }
  // this is similar in nature to:
  // org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer.addMenuContributions(MMenu,
  // ArrayList<MMenuContribution>, ArrayList<MMenuElement>)
  // the difference is it needs to add all the contributions and manage their
  // visiblility through a RAT
  private void addMenuBarContributions(
      final MMenu menuModel,
      ArrayList<MMenuContribution> toContribute,
      final IEclipseContext ctx,
      final ExpressionContext eContext) {
    HashSet<String> existingMenuIds = new HashSet<String>();
    HashSet<String> existingSeparatorNames = new HashSet<String>();
    for (MMenuElement child : menuModel.getChildren()) {
      String elementId = child.getElementId();
      if (child instanceof MMenu && elementId != null) {
        existingMenuIds.add(elementId);
      } else if (child instanceof MMenuSeparator && elementId != null) {
        existingSeparatorNames.add(elementId);
      }
    }

    boolean done = toContribute.size() == 0;
    while (!done) {
      ArrayList<MMenuContribution> curList = new ArrayList<MMenuContribution>(toContribute);
      int retryCount = toContribute.size();
      toContribute.clear();

      for (final MMenuContribution menuContribution : curList) {
        final ArrayList<MMenuElement> menuContributionsToRemove = new ArrayList<MMenuElement>();
        if (!ContributionsAnalyzer.processAddition(
            menuModel,
            menuContributionsToRemove,
            menuContribution,
            existingMenuIds,
            existingSeparatorNames)) {
          toContribute.add(menuContribution);
        } else {
          if (menuContribution.getVisibleWhen() != null) {
            ctx.runAndTrack(
                new RunAndTrack() {
                  @Override
                  public boolean changed(IEclipseContext context) {
                    if (!menuModel.isToBeRendered()
                        || !menuModel.isVisible()
                        || menuModel.getWidget() == null) {
                      return false;
                    }
                    boolean rc = ContributionsAnalyzer.isVisible(menuContribution, eContext);
                    for (MMenuElement element : menuContributionsToRemove) {
                      element.setToBeRendered(rc);
                    }
                    return true;
                  }
                });
          }
          ArrayList<ArrayList<MMenuElement>> lists = pendingCleanup.get(menuModel);
          if (lists == null) {
            lists = new ArrayList<ArrayList<MMenuElement>>();
            pendingCleanup.put(menuModel, lists);
          }
          lists.add(menuContributionsToRemove);
        }
      }
      // We're done if the retryList is now empty (everything done) or
      // if the list hasn't changed at all (no hope)
      done = (toContribute.size() == 0) || (toContribute.size() == retryCount);
    }
  }