public ExternalAnnotationsManagerImpl(
      @NotNull final Project project, final PsiManager psiManager) {
    super(psiManager);
    myBus = project.getMessageBus();
    final MessageBusConnection connection = myBus.connect(project);
    connection.subscribe(
        ProjectTopics.PROJECT_ROOTS,
        new ModuleRootAdapter() {
          @Override
          public void rootsChanged(ModuleRootEvent event) {
            dropCache();
          }
        });

    final MyVirtualFileListener fileListener = new MyVirtualFileListener();
    VirtualFileManager.getInstance().addVirtualFileListener(fileListener);
    Disposer.register(
        myPsiManager.getProject(),
        new Disposable() {
          @Override
          public void dispose() {
            VirtualFileManager.getInstance().removeVirtualFileListener(fileListener);
          }
        });
  }
  @Override
  public void dispose() {
    if (mySelectedEditor != null) {
      for (final Map.Entry<PropertiesFile, Editor> entry : myEditors.entrySet()) {
        if (mySelectedEditor.equals(entry.getValue())) {
          writeEditorPropertyValue(mySelectedEditor, entry.getKey(), null);
        }
      }
    }

    VirtualFileManager.getInstance().removeVirtualFileListener(myVfsListener);
    myDisposed = true;
    Disposer.dispose(myStructureViewComponent);
    releaseAllEditors();
  }
  public FileDocumentManagerImpl(
      @NotNull VirtualFileManager virtualFileManager, @NotNull ProjectManager projectManager) {
    virtualFileManager.addVirtualFileListener(this);
    projectManager.addProjectManagerListener(this);

    myBus = ApplicationManager.getApplication().getMessageBus();
    InvocationHandler handler =
        new InvocationHandler() {
          @Nullable
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            multiCast(method, args);
            return null;
          }
        };

    final ClassLoader loader = FileDocumentManagerListener.class.getClassLoader();
    myMultiCaster =
        (FileDocumentManagerListener)
            Proxy.newProxyInstance(
                loader, new Class[] {FileDocumentManagerListener.class}, handler);
  }
 @Override
 @NotNull
 protected List<VirtualFile> getExternalAnnotationsRoots(@NotNull VirtualFile libraryFile) {
   final List<OrderEntry> entries =
       ProjectRootManager.getInstance(myPsiManager.getProject())
           .getFileIndex()
           .getOrderEntriesForFile(libraryFile);
   List<VirtualFile> result = new ArrayList<VirtualFile>();
   for (OrderEntry entry : entries) {
     if (entry instanceof ModuleOrderEntry) {
       continue;
     }
     final String[] externalUrls = AnnotationOrderRootType.getUrls(entry);
     for (String url : externalUrls) {
       VirtualFile root = VirtualFileManager.getInstance().findFileByUrl(url);
       if (root != null) {
         result.add(root);
       }
     }
   }
   return result;
 }
  private void installPropertiesChangeListeners() {
    final VirtualFileManager virtualFileManager = VirtualFileManager.getInstance();
    if (myVfsListener != null) {
      assert false;
      virtualFileManager.removeVirtualFileListener(myVfsListener);
    }
    myVfsListener =
        new VirtualFileAdapter() {
          @Override
          public void fileCreated(@NotNull VirtualFileEvent event) {
            if (PropertiesImplUtil.isPropertiesFile(event.getFile(), myProject)) {
              recreateEditorsPanel();
            }
          }

          @Override
          public void fileDeleted(@NotNull VirtualFileEvent event) {
            for (PropertiesFile file : myEditors.keySet()) {
              if (Comparing.equal(file.getVirtualFile(), event.getFile())) {
                recreateEditorsPanel();
                return;
              }
            }
          }

          @Override
          public void propertyChanged(@NotNull VirtualFilePropertyEvent event) {
            if (PropertiesImplUtil.isPropertiesFile(event.getFile(), myProject)) {
              if (VirtualFile.PROP_NAME.equals(event.getPropertyName())) {
                recreateEditorsPanel();
              } else {
                updateEditorsFromProperties();
              }
            }
          }
        };

    virtualFileManager.addVirtualFileListener(myVfsListener, this);
    PsiTreeChangeAdapter psiTreeChangeAdapter =
        new PsiTreeChangeAdapter() {
          @Override
          public void childAdded(@NotNull PsiTreeChangeEvent event) {
            childrenChanged(event);
          }

          @Override
          public void childRemoved(@NotNull PsiTreeChangeEvent event) {
            childrenChanged(event);
          }

          @Override
          public void childReplaced(@NotNull PsiTreeChangeEvent event) {
            childrenChanged(event);
          }

          @Override
          public void childMoved(@NotNull PsiTreeChangeEvent event) {
            childrenChanged(event);
          }

          @Override
          public void childrenChanged(@NotNull PsiTreeChangeEvent event) {
            final PsiFile file = event.getFile();
            PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(file);
            if (propertiesFile == null) return;
            if (!propertiesFile.getResourceBundle().equals(myResourceBundle)) return;
            updateEditorsFromProperties();
          }
        };
    PsiManager.getInstance(myProject).addPsiTreeChangeListener(psiTreeChangeAdapter, this);
  }