package com.intellij.openapi.progress.util;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.impl.LaterInvocator;
import com.intellij.openapi.application.impl.ModalityStateEx;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.util.containers.DoubleArrayList;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;

public class ProgressIndicatorBase implements ProgressIndicator {
  private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.progress.util.ProgressIndicatorBase");

  private volatile String myText;
  private volatile double myFraction;
  private volatile String myText2;

  private volatile boolean myCanceled;
  private volatile boolean myRunning;

  private volatile boolean myIndeterminate;

  private ArrayList<String> myTextStack = new ArrayList<String>();
  private DoubleArrayList myFractionStack = new DoubleArrayList();
  private ArrayList<String> myText2Stack = new ArrayList<String>();
  private volatile int myNonCancelableCount = 0;

  private ProgressIndicator myModalityProgress = null;
  private ModalityState myModalityState = ModalityState.NON_MODAL;
  private boolean myModalityEntered = false;

  public void start(){
    LOG.assertTrue(!isRunning());
    synchronized(this){
      myText = "";
      myFraction = 0;
      myText2 = "";
      myCanceled = false;
      myRunning = true;
    }

    enterModality();
  }

  protected final synchronized void enterModality() {
    if (myModalityProgress == this && !myModalityEntered){
      myModalityEntered = true;
      if (!EventQueue.isDispatchThread()){
        SwingUtilities.invokeLater(
          new Runnable() {
            public void run() {
              LaterInvocator.enterModal(ProgressIndicatorBase.this);
            }
          }
        );
      }
      else{
        LaterInvocator.enterModal(this);
      }
    }
  }

  public void stop(){
    LOG.assertTrue(myRunning, "stop() should be called only if start() called before");
    myRunning = false;

    exitModality();
  }

  protected final synchronized void exitModality() {
    if (myModalityProgress == this && myModalityEntered){
      myModalityEntered = false;
      if (!EventQueue.isDispatchThread()){
        SwingUtilities.invokeLater(
          new Runnable() {
            public void run() {
              LaterInvocator.leaveModal(ProgressIndicatorBase.this);
            }
          }
        );
      }
      else{
        LaterInvocator.leaveModal(this);
      }
    }
  }

  public boolean isRunning() {
    return myRunning;
  }

  public void cancel(){
    myCanceled = true;
  }

  public boolean isCanceled(){
    return myCanceled;
  }

  public final void checkCanceled(){
    if (isCanceled() && myNonCancelableCount == 0) {
      throw new ProcessCanceledException();
    }
  }

  public void setText(String text){
    myText = text;
  }

  public String getText(){
    return myText;
  }

  public void setText2(String text){
    myText2 = text;
  }

  public String getText2(){
    return myText2;
  }

  public double getFraction() {
    return myFraction;
  }

  public void setFraction(double fraction) {
    myFraction = fraction;
  }

  public void pushState(){
    synchronized(this){
      myTextStack.add(myText);
      myFractionStack.add(myFraction);
      myText2Stack.add(myText2);
      setText("");
      setFraction(0);
      setText2("");
    }
  }

  public void popState(){
    synchronized(this){
      LOG.assertTrue(myTextStack.size() > 0);
      setText(myTextStack.remove(myTextStack.size() - 1));
      setFraction(myFractionStack.remove(myFractionStack.size() - 1));
      setText2(myText2Stack.remove(myText2Stack.size() - 1));
    }
  }

  public void startNonCancelableSection(){
    myNonCancelableCount++;
  }

  public void finishNonCancelableSection(){
    myNonCancelableCount--;
  }

  public final boolean isModal(){
    return myModalityProgress != null;
  }

  public final ModalityState getModalityState() {
    return myModalityState;
  }

  public void setModalityProgress(ProgressIndicator modalityProgress) {
    LOG.assertTrue(!isRunning());
    myModalityProgress = modalityProgress;
    ModalityState currentModality = ApplicationManager.getApplication().getCurrentModalityState();
    myModalityState = myModalityProgress != null ? ((ModalityStateEx)currentModality).appendProgress(myModalityProgress) : currentModality;
  }

  public boolean isIndeterminate() {
    return myIndeterminate;
  }

  public void setIndeterminate(boolean indeterminate) {
    myIndeterminate = indeterminate;
  }

}

@@ -1640,37 +1640,24 @@
 ected final 
-synchronized 
 void enterMo
@@ -1705,64 +1705,10 @@
 this
- && !myModalityEntered)%7B%0A      myModalityEntered = true;
+)%7B
 %0A   
@@ -1860,60 +1860,24 @@
     
-LaterInvocator.enterModal(ProgressIndicatorBase.this
+doEnterModality(
 );%0A 
@@ -1926,32 +1926,141 @@
 %7D%0A      else%7B%0A  
+      doEnterModality();%0A      %7D%0A    %7D%0A  %7D%0A%0A  private void doEnterModality() %7B%0A    if (!myModalityEntered) %7B%0A
       LaterInvoc
@@ -2080,33 +2080,57 @@
 al(this);%0A      
-%7D
+myModalityEntered = true;
 %0A    %7D%0A  %7D%0A%0A  pu
@@ -2306,21 +2306,8 @@
 nal 
-synchronized 
 void
@@ -2362,64 +2362,10 @@
 this
- && myModalityEntered)%7B%0A      myModalityEntered = false;
+)%7B
 %0A   
@@ -2517,60 +2517,23 @@
     
-LaterInvocator.leaveModal(ProgressIndicatorBase.this
+doExitModality(
 );%0A 
@@ -2586,24 +2586,130 @@
     else%7B%0A  
+      doExitModality();%0A      %7D%0A    %7D%0A  %7D%0A%0A  private void doExitModality() %7B%0A    if (myModalityEntered) %7B%0A
       LaterI
@@ -2733,33 +2733,58 @@
 al(this);%0A      
-%7D
+myModalityEntered = false;
 %0A    %7D%0A  %7D%0A%0A  pu

fix enterModality/exitModality