@Override
 protected void addFolderGroupComponents() {
   super.addFolderGroupComponents();
   for (PyRootTypeProvider provider : myRootTypeProviders) {
     MultiMap<ContentEntry, VirtualFilePointer> roots = provider.getRoots();
     if (!roots.get(getContentEntry()).isEmpty()) {
       final JComponent sourcesComponent =
           createFolderGroupComponent(
               provider.getName() + " Folders",
               provider.createFolders(getContentEntry()),
               provider.getColor(),
               null);
       this.add(
           sourcesComponent,
           new GridBagConstraints(
               0,
               GridBagConstraints.RELATIVE,
               1,
               1,
               1.0,
               0.0,
               GridBagConstraints.NORTH,
               GridBagConstraints.HORIZONTAL,
               new Insets(0, 0, 10, 0),
               0,
               0));
     }
   }
 }
 @Override
 public void apply() throws ConfigurationException {
   super.apply();
   for (PyRootTypeProvider provider : myRootTypeProviders) {
     provider.apply(myModule);
   }
 }
 @Override
 public void deleteContentFolder(ContentEntry contentEntry, ContentFolder folder) {
   for (PyRootTypeProvider provider : myRootTypeProviders) {
     if (provider.isMine(folder)) {
       removeRoot(contentEntry, folder.getUrl(), provider);
       return;
     }
   }
   super.deleteContentFolder(contentEntry, folder);
 }
 @Override
 public boolean isModified() {
   if (super.isModified()) return true;
   for (PyRootTypeProvider provider : myRootTypeProviders) {
     if (provider.isModified(myModule)) {
       return true;
     }
   }
   return false;
 }
  @Override
  public void disposeUIResources() {
    super.disposeUIResources();
    if (myFilePointersDisposable != null) {
      Disposer.dispose(myFilePointersDisposable);
    }

    for (PyRootTypeProvider provider : myRootTypeProviders) {
      provider.disposeUIResources(myModule);
    }
  }
 @Override
 protected void createEditingActions() {
   super.createEditingActions();
   for (PyRootTypeProvider provider : myRootTypeProviders) {
     ContentEntryEditingAction action =
         provider.createRootEntryEditingAction(
             myTree, myFilePointersDisposable, PyContentEntriesEditor.this, getModel());
     myEditingActionsGroup.add(action);
     CustomShortcutSet shortcut = provider.getShortcut();
     if (shortcut != null) {
       action.registerCustomShortcutSet(shortcut, myTree);
     }
   }
 }
  @Override
  public void reset() {
    if (myFilePointersDisposable != null) {
      Disposer.dispose(myFilePointersDisposable);
    }

    myFilePointersDisposable = Disposer.newDisposable();
    for (PyRootTypeProvider provider : myRootTypeProviders) {
      provider.reset(myFilePointersDisposable, this, myModule);
    }

    if (myRootTreeEditor != null) {
      ContentEntryEditor editor = myRootTreeEditor.getContentEntryEditor();
      if (editor != null) editor.update();
      myRootTreeEditor.update();
    }
  }
 public VirtualFilePointer getRoot(PyRootTypeProvider provider, @NotNull final String url) {
   for (VirtualFilePointer filePointer : provider.getRoots().get(getContentEntry())) {
     if (Comparing.equal(filePointer.getUrl(), url)) {
       return filePointer;
     }
   }
   return null;
 }
 public void removeRoot(
     @Nullable ContentEntry contentEntry, String folder, PyRootTypeProvider provider) {
   if (contentEntry == null) {
     contentEntry = getContentEntry();
   }
   VirtualFilePointer root = getRoot(provider, folder);
   if (root != null) {
     provider.removeRoot(contentEntry, root, getModel());
     fireUpdate();
   }
 }
 public void addRoot(PyRootTypeProvider provider, @NotNull final VirtualFilePointer root) {
   provider.getRoots().putValue(getContentEntry(), root);
   fireUpdate();
 }