/*
 * Copyright 2000-2014 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.ui;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.FileEditorManagerAdapter;
import com.intellij.openapi.fileEditor.FileEditorManagerListener;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
import com.intellij.openapi.progress.util.ReadTask;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.reference.SoftReference;
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.update.MergingUpdateQueue;
import com.intellij.util.ui.update.Update;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author peter
 */
public class EditorNotificationsImpl extends EditorNotifications {
  private static final ExtensionPointName<Provider> EXTENSION_POINT_NAME = ExtensionPointName.create("com.intellij.editorNotificationProvider");
  private static final Key<WeakReference<ProgressIndicator>> CURRENT_UPDATES = Key.create("CURRENT_UPDATES");
  private final ThreadPoolExecutor myExecutor = ConcurrencyUtil.newSingleThreadExecutor("EditorNotifications executor");
  private final MergingUpdateQueue myUpdateMerger;

  public EditorNotificationsImpl(Project project) {
    super(project);
    myUpdateMerger = new MergingUpdateQueue("EditorNotifications update merger", 100, true, null, project);
    MessageBusConnection connection = project.getMessageBus().connect(project);
    connection.subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerAdapter() {
      @Override
      public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
        updateNotifications(file);
      }
    });
    connection.subscribe(DumbService.DUMB_MODE, new DumbService.DumbModeListener() {
      @Override
      public void enteredDumbMode() {
        updateAllNotifications();
      }

      @Override
      public void exitDumbMode() {
        updateAllNotifications();
      }
    });

  }

  @Override
  public void updateNotifications(@NotNull final VirtualFile file) {
    UIUtil.invokeLaterIfNeeded(new Runnable() {
      @Override
      public void run() {
        ProgressIndicator indicator = SoftReference.dereference(file.getUserData(CURRENT_UPDATES));
        if (indicator != null) {
          indicator.cancel();
        }

        indicator = new ProgressIndicatorBase();
        file.putUserData(CURRENT_UPDATES, new WeakReference<ProgressIndicator>(indicator));

        final ReadTask task = createTask(indicator, file);
        if (task == null) return;

        if (ApplicationManager.getApplication().isUnitTestMode()) {
          task.computeInReadAction(indicator);
        }
        else {
          final ProgressIndicator indicator1 = indicator;
          myExecutor.execute(new Runnable() {
            @Override
            public void run() {
              ProgressIndicatorUtils.runWithWriteActionPriority(indicator1, task);
            }
          });
        }
      }
    });
  }

  @Nullable
  private ReadTask createTask(final ProgressIndicator indicator, @NotNull final VirtualFile file) {
    final FileEditor[] editors = FileEditorManager.getInstance(myProject).getAllEditors(file);
    if (editors.length == 0) return null;

    return new ReadTask() {
      private boolean isOutdated() {
        if (myProject.isDisposed() || !file.isValid() || indicator != SoftReference.dereference(file.getUserData(CURRENT_UPDATES))) {
          return true;
        }

        for (FileEditor editor : editors) {
          if (!editor.isValid()) {
            return true;
          }
        }

        return false;
      }

      @Override
      public void computeInReadAction(@NotNull final ProgressIndicator indicator) {
        if (isOutdated()) return;

        final List<Runnable> updates = ContainerUtil.newArrayList();
        for (final FileEditor editor : editors) {
          for (final Provider<?> provider : Extensions.getExtensions(EXTENSION_POINT_NAME, myProject)) {
            final JComponent component = provider.createNotificationPanel(file, editor);
            updates.add(new Runnable() {
              @Override
              public void run() {
                updateNotification(editor, provider.getKey(), component);
              }
            });
          }
        }

        UIUtil.invokeLaterIfNeeded(new Runnable() {
          @Override
          public void run() {
            if (!isOutdated()) {
              file.putUserData(CURRENT_UPDATES, null);
              for (Runnable update : updates) {
                update.run();
              }
            }
          }
        });
      }

      @Override
      public void onCanceled(@NotNull ProgressIndicator indicator) {
        updateNotifications(file);
      }
    };
  }


  private void updateNotification(@NotNull FileEditor editor, @NotNull Key<? extends JComponent> key, @Nullable JComponent component) {
    JComponent old = editor.getUserData(key);
    if (old != null) {
      FileEditorManager.getInstance(myProject).removeTopComponent(editor, old);
    }
    if (component != null) {
      FileEditorManager.getInstance(myProject).addTopComponent(editor, component);
      @SuppressWarnings("unchecked") Key<JComponent> _key = (Key<JComponent>)key;
      editor.putUserData(_key, component);
    }
    else {
      editor.putUserData(key, null);
    }
  }

  @Override
  public void updateAllNotifications() {
    myUpdateMerger.queue(new Update("update") {
      @Override
      public void run() {
        for (VirtualFile file : FileEditorManager.getInstance(myProject).getOpenFiles()) {
          updateNotifications(file);
        }
      }
    });
  }
}

@@ -3661,32 +3661,99 @@
 l();%0A        %7D%0A%0A
+        if (myProject.isDisposed()) %7B%0A          return;%0A        %7D%0A%0A
         indicato

fix Already Disposed from EditorNotificationsImpl