public void rootsChanged(String listName) {
   FavoritesListener[] listeners =
       myListeners.toArray(new FavoritesListener[myListeners.size()]);
   for (FavoritesListener listener : listeners) {
     listener.rootsChanged(listName);
   }
 }
  private <T> boolean findListToRemoveFrom(
      @NotNull String name,
      @NotNull final List<T> elements,
      final Convertor<T, AbstractUrl> convertor) {
    Collection<TreeItem<Pair<AbstractUrl, String>>> list = getFavoritesListRootUrls(name);
    if (elements.size() > 1) {
      final List<T> sublist = elements.subList(0, elements.size() - 1);
      for (T obj : sublist) {
        AbstractUrl objUrl = convertor.convert(obj);
        final TreeItem<Pair<AbstractUrl, String>> item = findNextItem(objUrl, list);
        if (item == null || item.getChildren() == null) return false;
        list = item.getChildren();
      }
    }

    TreeItem<Pair<AbstractUrl, String>> found = null;
    AbstractUrl url = convertor.convert(elements.get(elements.size() - 1));
    if (url == null) return false;
    for (TreeItem<Pair<AbstractUrl, String>> pair : list) {
      if (url.equals(pair.getData().getFirst())) {
        found = pair;
        break;
      }
    }

    if (found != null) {
      list.remove(found);
      fireListeners.rootsChanged(name);
      return true;
    }
    return false;
  }
  public boolean addRoots(final String name, final Collection<AbstractTreeNode> nodes) {
    final Collection<TreeItem<Pair<AbstractUrl, String>>> list = getFavoritesListRootUrls(name);

    final HashSet<AbstractUrl> set =
        new HashSet<AbstractUrl>(
            ObjectsConvertor.convert(
                list,
                new Convertor<TreeItem<Pair<AbstractUrl, String>>, AbstractUrl>() {
                  @Override
                  public AbstractUrl convert(TreeItem<Pair<AbstractUrl, String>> o) {
                    return o.getData().getFirst();
                  }
                }));
    for (AbstractTreeNode node : nodes) {
      final Pair<AbstractUrl, String> pair = createPairForNode(node);
      if (pair != null) {
        if (set.contains(pair.getFirst())) continue;
        final TreeItem<Pair<AbstractUrl, String>> treeItem =
            new TreeItem<Pair<AbstractUrl, String>>(pair);
        list.add(treeItem);
        set.add(pair.getFirst());
        appendChildNodes(node, treeItem);
      }
    }
    fireListeners.rootsChanged(name);
    return true;
  }
 public void removeRootByIndexes(String name, List<Integer> elementsIndexes) {
   List<TreeItem<Pair<AbstractUrl, String>>> list = getFavoritesListRootUrls(name);
   assert list != null;
   for (Integer index : elementsIndexes.subList(0, elementsIndexes.size() - 1)) {
     assert index >= 0 && index < list.size();
     final TreeItem<Pair<AbstractUrl, String>> item = list.get(index);
     list = item.getChildren();
   }
   assert list != null && !list.isEmpty();
   list.remove(elementsIndexes.get(elementsIndexes.size() - 1).intValue());
   fireListeners.rootsChanged(name);
 }
  public synchronized boolean addRoot(
      @NotNull String name,
      @NotNull List<AbstractTreeNode> parentElements,
      final AbstractTreeNode newElement,
      @Nullable AbstractTreeNode sibling) {
    final List<TreeItem<Pair<AbstractUrl, String>>> items = myName2FavoritesRoots.get(name);
    if (items == null) return false;
    AbstractUrl url = createUrlByElement(newElement.getValue(), myProject);
    if (url == null) return false;
    final TreeItem<Pair<AbstractUrl, String>> newItem =
        new TreeItem<Pair<AbstractUrl, String>>(Pair.create(url, newElement.getClass().getName()));

    if (parentElements.isEmpty()) {
      // directly to list
      if (sibling != null) {
        TreeItem<Pair<AbstractUrl, String>> after = null;
        AbstractUrl siblingUrl = createUrlByElement(sibling.getValue(), myProject);
        int idx = -1;
        for (int i = 0; i < items.size(); i++) {
          TreeItem<Pair<AbstractUrl, String>> item = items.get(i);
          if (item.getData().getFirst().equals(siblingUrl)) {
            idx = i;
            break;
          }
        }
        if (idx != -1) {
          items.add(idx, newItem);
        } else {
          items.add(newItem);
        }
      } else {
        items.add(newItem);
      }

      fireListeners.rootsChanged(name);
      return true;
    }

    Collection<TreeItem<Pair<AbstractUrl, String>>> list = items;
    TreeItem<Pair<AbstractUrl, String>> item = null;
    for (AbstractTreeNode obj : parentElements) {
      AbstractUrl objUrl = createUrlByElement(obj.getValue(), myProject);
      item = findNextItem(objUrl, list);
      if (item == null) return false;
      list = item.getChildren();
    }

    if (sibling != null) {
      TreeItem<Pair<AbstractUrl, String>> after = null;
      AbstractUrl siblingUrl = createUrlByElement(sibling.getValue(), myProject);
      for (TreeItem<Pair<AbstractUrl, String>> treeItem : list) {
        if (treeItem.getData().getFirst().equals(siblingUrl)) {
          after = treeItem;
          break;
        }
      }
      if (after == null) {
        item.addChild(newItem);
      } else {
        item.addChildAfter(newItem, after);
      }
    } else {
      item.addChild(newItem);
    }
    fireListeners.rootsChanged(name);
    return true;
  }
 public synchronized void fireListeners(@NotNull final String listName) {
   fireListeners.rootsChanged(listName);
 }